今天调式个8155 的demo板子,显示模块插拔线没有,无法看到显示的画面,但是领导要看画面,后来想到了使用android模拟器的环境进行搭建,最早调式手机的时候都是没有屏幕的,都是使用安卓模拟器调式的,下面介绍些vysor的同屏显示原理
===》vysor 同屏显示原理 直接上干活
adb shell能够调用screencap或者screenshot来截取屏幕,那就说明adb shell具备截屏的权限。Surface/SurfaceControl和screenshot/screencap它们内部的实现机制应该是相同的,因此也就是说adb shell是具备截屏权限的也就是可以调用到Surface/SurfaceControl。那么咱们怎么经过adb shell来调用到这两个类呢,答案就是app_process。app_process能够直接运行一个普通的java类,详细的资料你们能够在网上找到。也就是说咱们经过adb shell运行app_process,而后经过app_process来运行一个java类,在java类中就能够访问到Surface/SurfaceControl这两个类,是否是很巧妙?
adb shell 截屏
H264 压缩
encoder? 编码压缩
public static void main(String[] args) throws Exception {
if (args.length > 0) {
commandLinePassword = args[0];
Log.i(LOGTAG, "Received command line password: " + commandLinePassword);
}
Looper.prepare();
looper = Looper.myLooper();
AsyncServer server = new AsyncServer();
AsyncHttpServer httpServer = new AsyncHttpServer() {
protected boolean onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
Log.i(Main.LOGTAG, request.getHeaders().toString());
return super.onRequest(request, response);
}
};
String str = "getInstance";
Object[] objArr = new Object[0];
InputManager im = (InputManager) InputManager.class.getDeclaredMethod(r20, new Class[0]).invoke(null, objArr);
str = "obtain";
MotionEvent.class.getDeclaredMethod(r20, new Class[0]).setAccessible(true);
str = "injectInputEvent";
Method injectInputEventMethod = InputManager.class.getMethod(r20, new Class[]{InputEvent.class, Integer.TYPE});
KeyCharacterMap kcm = KeyCharacterMap.load(-1);
Class cls = Class.forName("android.os.ServiceManager");
Method getServiceMethod = cls.getDeclaredMethod("getService", new Class[]{String.class});
IClipboard clipboard = IClipboard.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"clipboard"}));
clipboard.addPrimaryClipChangedListener(new AnonymousClass3(clipboard), null);
IPowerManager pm = IPowerManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"power"}));
IWindowManager wm = IWindowManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"window"}));
IRotationWatcher watcher = new Stub() {
public void onRotationChanged(int rotation) throws RemoteException {
if (Main.webSocket != null) {
Point displaySize = SurfaceControlVirtualDisplayFactory.getCurrentDisplaySize();
JSONObject json = new JSONObject();
try {
json.put("type", "displaySize");
json.put("screenWidth", displaySize.x);
json.put("screenHeight", displaySize.y);
json.put("nav", Main.hasNavBar());
Main.webSocket.send(json.toString());
} catch (JSONException e) {
}
}
}
};
wm.watchRotation(watcher);
httpServer.get("/screenshot.jpg", new AnonymousClass5(wm));
httpServer.websocket("/input", "mirror-protocol", new AnonymousClass6(watcher, im, injectInputEventMethod, pm, wm, kcm));
httpServer.get("/h264", new AnonymousClass7(im, injectInputEventMethod, pm, wm));
Log.i(LOGTAG, "Server starting");
AsyncServerSocket rawSocket = server.listen(null, 53517, new AnonymousClass8(wm));
if (httpServer.listen(server, 53516) == null || rawSocket == null) {
System.out.println("No server socket?");
Log.e(LOGTAG, "No server socket?");
throw new AssertionError("No server socket?");
}
System.out.println("Started");
Log.i(LOGTAG, "Waiting for exit");
Looper.loop();
Log.i(LOGTAG, "Looper done");
server.stop();
if (current != null) {
current.stop();
current = null;
}
Log.i(LOGTAG, "Done!");
System.exit(0);
}
这个软件koushikdutta是由开发的,这个团队之前发布过一个很是流行的开源网络库:async。在这个项目中也用到了这个开源库。main函数主要是新建了一个httpserver而后开放了几个接口,经过screenshot.jpg获取截图,经过socket input接口来发送点击信息,经过h264这个接口来获取实时的屏幕视频流。每个接口都有对应的响应函数,这里咱们主要研究截图,因此就看screenshot这个接口。h264这个接口传输的是实时的视频流,因此就流畅性来讲应该会更好,它也是经过virtualdisplay来实现的有兴趣的读者能够自行研究。
接下来咱们来看screenshot对应的响应函数AnonymousClass5的实现代码。
* renamed from: com.koushikdutta.vysor.Main.5 */
static class AnonymousClass5 implements HttpServerRequestCallback {
final /* synthetic */ IWindowManager val$wm;
AnonymousClass5(IWindowManager iWindowManager) {
this.val$wm = iWindowManager;
}
public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
if (Main.checkPassword(request.getQuery().getString("password"))) {
Log.i(Main.LOGTAG, "screenshot authentication success");
try {
Bitmap bitmap = EncoderFeeder.screenshot(this.val$wm);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.JPEG, 100, bout);
bout.flush();
response.send("image/jpeg", bout.toByteArray());
return;
} catch (Exception e) {
response.code(500);
response.send(e.toString());
return;
}
}
Log.i(Main.LOGTAG, "screenshot authentication failed");
response.code(401);
response.send("Not Authorized.");
}
}
这个类传入了一个wm类,这个类是用来监听屏幕旋转的,这里不用管它。另外在vysor开始运行时,会随机生成一个验证码,只有验证经过才能进行链接,因此这里有一个验证的过程,这里也不过管。能够看到这个类定义的响应函数的代码很是简单,就是经过EncoderFeeder.screenshot()函数来过去截图的bitmap,而后返回给请求端。那么EncoderFeeder.screenshot这个函数是怎样实现截图的呢?
|