本文章的目的是通过分析monkeyrunner是如何实现截屏来作为一个例子尝试投石问路为下一篇文章做准备,往下一篇文章本人有意分析下monkeyrunner究竟是如何和目标测试机器通信的,所以最好的办法本人认为是先跟踪一个调用示例从高层到底层进行分析,本人以前分析操作系统源代码的时候就是先从用户层的write这个api入手,然后一路打通到vfs文件系统层,到设备驱动层的,其效果比单纯的理论描述更容易理解和接受。
在整个代码分析过程中会设计到以下的库,希望想动手分析的同学们准备好源码:
首先我们先看takeSnapshot的入口函数是在MonkeyDevice这个class里面的(因为所有的代码都是反编译的,所以代码排版方便可能有点别扭).
MonkeyDevice.class takeSnapshot():
/* */ @MonkeyRunnerExported(doc="Gets the device's screen buffer, yielding a screen capture of the entire display.", returns="A MonkeyImage object (a bitmap wrapper)") /* */ public MonkeyImage takeSnapshot() /* */ { /* 92 */ IChimpImage image = this.impl.takeSnapshot(); /* 93 */ return new MonkeyImage(image); /* */ }
public MonkeyDevice(IChimpDevice impl) /* */ { /* 75 */ this.impl = impl; /* */ }
public abstract interface IChimpDevice { public abstract ChimpManager getManager(); public abstract void dispose(); public abstract HierarchyViewer getHierarchyViewer(); public abstract IChimpImage takeSnapshot(); public abstract void reboot(@Nullable String paramString); public abstract Collection<String> getPropertyList(); public abstract String getProperty(String paramString); public abstract String getSystemProperty(String paramString); public abstract void touch(int paramInt1, int paramInt2, TouchPressType paramTouchPressType); public abstract void press(String paramString, TouchPressType paramTouchPressType); public abstract void press(PhysicalButton paramPhysicalButton, TouchPressType paramTouchPressType); public abstract void drag(int paramInt1, int paramInt2, int paramInt3, int paramInt4, int paramInt5, long paramLong); public abstract void type(String paramString); public abstract String shell(String paramString); public abstract String shell(String paramString, int paramInt); public abstract boolean installPackage(String paramString); public abstract boolean removePackage(String paramString); public abstract void startActivity(@Nullable String paramString1, @Nullable String paramString2, @Nullable String paramString3, @Nullable String paramString4, Collection<String> paramCollection, Map<String, Object> paramMap, @Nullable String paramString5, int paramInt); public abstract void broadcastIntent(@Nullable String paramString1, @Nullable String paramString2, @Nullable String paramString3, @Nullable String paramString4, Collection<String> paramCollection, Map<String, Object> paramMap, @Nullable String paramString5, int paramInt); public abstract Map<String, Object> instrument(String paramString, Map<String, Object> paramMap); public abstract void wake(); public abstract Collection<String> getViewIdList(); public abstract IChimpView getView(ISelector paramISelector); public abstract IChimpView getRootView(); public abstract Collection<IChimpView> getViews(IMultiSelector paramIMultiSelector); }
/* */ @MonkeyRunnerExported(doc="Waits for the workstation to connect to the device.", args={"timeout", "deviceId"}, argDocs={"The timeout in seconds to wait. The default is to wait indefinitely.", "A regular expression that specifies the device name. See the documentation for 'adb' in the Developer Guide to learn more about device names."}, returns="A ChimpDevice object representing the connected device.") /* */ public static MonkeyDevice waitForConnection(PyObject[] args, String[] kws) /* */ { /* 64 */ ArgParser ap = JythonUtils.createArgParser(args, kws); /* 65 */ Preconditions.checkNotNull(ap); /* */ long timeoutMs; /* */ try /* */ { /* 69 */ double timeoutInSecs = JythonUtils.getFloat(ap, 0); /* 70 */ timeoutMs = (timeoutInSecs * 1000.0D); /* */ } catch (PyException e) { /* 72 */ timeoutMs = Long.MAX_VALUE; /* */ } /* */ /* 75 */ IChimpDevice device = chimpchat.waitForConnection(timeoutMs, ap.getString(1, ".*")); /* */ /* 77 */ MonkeyDevice chimpDevice = new MonkeyDevice(device); /* 78 */ return chimpDevice; /* */ }
/* */ public IChimpDevice waitForConnection(long timeoutMs, String deviceId) /* */ { /* 91 */ return this.mBackend.waitForConnection(timeoutMs, deviceId); /* */ }
/* */ private ChimpChat(IChimpBackend backend) /* */ { /* 39 */ this.mBackend = backend; /* */ }
/* */ public static ChimpChat getInstance(Map<String, String> options) /* */ { /* 48 */ sAdbLocation = (String)options.get("adbLocation"); /* 49 */ sNoInitAdb = Boolean.valueOf((String)options.get("noInitAdb")).booleanValue(); /* */ /* 51 */ IChimpBackend backend = createBackendByName((String)options.get("backend")); /* 52 */ if (backend == null) { /* 53 */ return null; /* */ } /* 55 */ ChimpChat chimpchat = new ChimpChat(backend); /* 56 */ return chimpchat; /* */ } /* */ /* */ /* */ /* */ public static ChimpChat getInstance() /* */ { /* 63 */ Map<String, String> options = new TreeMap(); /* 64 */ options.put("backend", "adb"); /* 65 */ return getInstance(options); /* */ }
/* */ private static IChimpBackend createBackendByName(String backendName) /* */ { /* 77 */ if ("adb".equals(backendName)) { /* 78 */ return new AdbBackend(sAdbLocation, sNoInitAdb); /* */ } /* 80 */ return null; /* */ }
/* */ public IChimpDevice waitForConnection(long timeoutMs, String deviceIdRegex) /* */ { /* */ do { /* 119 */ IDevice device = findAttachedDevice(deviceIdRegex); /* */ /* 121 */ if ((device != null) && (device.getState() == IDevice.DeviceState.ONLINE)) { /* 122 */ IChimpDevice chimpDevice = new AdbChimpDevice(device); /* 123 */ this.devices.add(chimpDevice); /* 124 */ return chimpDevice; /* */ } /* */ try /* */ { /* 128 */ Thread.sleep(200L); /* */ } catch (InterruptedException e) { /* 130 */ LOG.log(Level.SEVERE, "Error sleeping", e); /* */ } /* 132 */ timeoutMs -= 200L; /* 133 */ } while (timeoutMs > 0L); /* */ /* */ /* 136 */ return null; /* */ }
IChimpImage image = this.impl.takeSnapshot();
/* */ public IChimpImage takeSnapshot() /* */ { /* */ try { /* 209 */ return new AdbChimpImage(this.device.getScreenshot()); /* */ } catch (TimeoutException e) { /* 211 */ LOG.log(Level.SEVERE, "Unable to take snapshot", e); /* 212 */ return null; /* */ } catch (AdbCommandRejectedException e) { /* 214 */ LOG.log(Level.SEVERE, "Unable to take snapshot", e); /* 215 */ return null; /* */ } catch (IOException e) { /* 217 */ LOG.log(Level.SEVERE, "Unable to take snapshot", e); } /* 218 */ return null; /* */ }
/* */ public AdbChimpDevice(IDevice device) /* */ { /* 70 */ this.device = device; /* 71 */ this.manager = createManager("127.0.0.1", 12345); /* */ /* 73 */ Preconditions.checkNotNull(this.manager); /* */ }
/* */ public IChimpDevice waitForConnection(long timeoutMs, String deviceIdRegex) /* */ { /* */ do { /* 119 */ IDevice device = findAttachedDevice(deviceIdRegex); /* */ /* 121 */ if ((device != null) && (device.getState() == IDevice.DeviceState.ONLINE)) { /* 122 */ IChimpDevice chimpDevice = new AdbChimpDevice(device); /* 123 */ this.devices.add(chimpDevice); /* 124 */ return chimpDevice; /* */ } /* */ try /* */ { /* 128 */ Thread.sleep(200L); /* */ } catch (InterruptedException e) { /* 130 */ LOG.log(Level.SEVERE, "Error sleeping", e); /* */ } /* 132 */ timeoutMs -= 200L; /* 133 */ } while (timeoutMs > 0L); /* */ /* */ /* 136 */ return null; /* */ }
/* */ public abstract interface IDevice extends IShellEnabledDevice /* */ { /* */ public static final String PROP_BUILD_VERSION = "ro.build.version.release"; /* */ public static final String PROP_BUILD_API_LEVEL = "ro.build.version.sdk"; /* */ public static final String PROP_BUILD_CODENAME = "ro.build.version.codename"; /* */ public static final String PROP_DEVICE_MODEL = "ro.product.model"; /* */ public static final String PROP_DEVICE_MANUFACTURER = "ro.product.manufacturer"; /* */ public static final String PROP_DEVICE_CPU_ABI = "ro.product.cpu.abi"; /* */ public static final String PROP_DEVICE_CPU_ABI2 = "ro.product.cpu.abi2"; /* */ public static final String PROP_BUILD_CHARACTERISTICS = "ro.build.characteristics"; /* */ public static final String PROP_DEBUGGABLE = "ro.debuggable"; /* */ public static final String FIRST_EMULATOR_SN = "emulator-5554"; /* */ public static final int CHANGE_STATE = 1; /* */ public static final int CHANGE_CLIENT_LIST = 2; /* */ public static final int CHANGE_BUILD_INFO = 4; /* */ @Deprecated /* */ public static final String PROP_BUILD_VERSION_NUMBER = "ro.build.version.sdk"; /* */ public static final String MNT_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"; /* */ public static final String MNT_ROOT = "ANDROID_ROOT"; /* */ public static final String MNT_DATA = "ANDROID_DATA"; /* */ /* */ @NonNull /* */ public abstract String getSerialNumber(); /* */ /* */ @Nullable /* */ public abstract String getAvdName(); /* */ /* */ public abstract DeviceState getState(); /* */ /* */ public abstract java.util.Map<String, String> getProperties(); /* */ /* */ public abstract int getPropertyCount(); /* */ /* */ public abstract String getProperty(String paramString); /* */ /* */ public abstract boolean arePropertiesSet(); /* */ /* */ public abstract String getPropertySync(String paramString) throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException; /* */ /* */ public abstract String getPropertyCacheOrSync(String paramString) throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException; /* */ /* */ public abstract boolean supportsFeature(@NonNull Feature paramFeature); /* */ /* */ public static enum Feature /* */ { /* 53 */ SCREEN_RECORD, /* 54 */ PROCSTATS; /* */ /* */ private Feature() {} /* */ } /* */ /* 59 */ public static enum HardwareFeature { WATCH("watch"); /* */ /* */ private final String mCharacteristic; /* */ /* */ private HardwareFeature(String characteristic) { /* 64 */ this.mCharacteristic = characteristic; /* */ }
/* */ private IDevice findAttachedDevice(String deviceIdRegex) /* */ { /* 101 */ Pattern pattern = Pattern.compile(deviceIdRegex); /* 102 */ for (IDevice device : this.bridge.getDevices()) { /* 103 */ String serialNumber = device.getSerialNumber(); /* 104 */ if (pattern.matcher(serialNumber).matches()) { /* 105 */ return device; /* */ } /* */ } /* 108 */ return null; /* */ }
/* */ public IDevice[] getDevices() /* */ { /* 484 */ synchronized (sLock) { /* 485 */ if (this.mDeviceMonitor != null) { /* 486 */ return this.mDeviceMonitor.getDevices(); /* */ } /* */ }
/* */ private DeviceMonitor mDeviceMonitor;
/* */ Device[] getDevices() /* */ { /* 131 */ synchronized (this.mDevices) { /* 132 */ return (Device[])this.mDevices.toArray(new Device[this.mDevices.size()]); /* */ } /* */ }
/* 60 */ private final ArrayList<Device> mDevices = new ArrayList();
/* */ public RawImage getScreenshot() /* */ throws TimeoutException, AdbCommandRejectedException, IOException /* */ { /* 558 */ return AdbHelper.getFrameBuffer(AndroidDebugBridge.getSocketAddress(), this); /* */ }
/* */ static RawImage getFrameBuffer(InetSocketAddress adbSockAddr, Device device) /* */ throws TimeoutException, AdbCommandRejectedException, IOException /* */ { /* 272 */ RawImage imageParams = new RawImage(); /* 273 */ byte[] request = formAdbRequest("framebuffer:"); /* 274 */ byte[] nudge = { 0 }; /* */ /* */ /* */ /* */ /* 279 */ SocketChannel adbChan = null; /* */ try { /* 281 */ adbChan = SocketChannel.open(adbSockAddr); /* 282 */ adbChan.configureBlocking(false); /* */ /* */ /* */ /* 286 */ setDevice(adbChan, device); /* */ /* 288 */ write(adbChan, request); /* */ /* 290 */ AdbResponse resp = readAdbResponse(adbChan, false); /* 291 */ if (!resp.okay) { /* 292 */ throw new AdbCommandRejectedException(resp.message); /* */ } /* */ /* */ /* 296 */ byte[] reply = new byte[4]; /* 297 */ read(adbChan, reply); /* */ /* 299 */ ByteBuffer buf = ByteBuffer.wrap(reply); /* 300 */ buf.order(ByteOrder.LITTLE_ENDIAN); /* */ /* 302 */ int version = buf.getInt(); /* */ /* */ /* 305 */ int headerSize = RawImage.getHeaderSize(version); /* */ /* */ /* 308 */ reply = new byte[headerSize * 4]; /* 309 */ read(adbChan, reply); /* */ /* 311 */ buf = ByteBuffer.wrap(reply); /* 312 */ buf.order(ByteOrder.LITTLE_ENDIAN); /* */ /* */ /* 315 */ if (!imageParams.readHeader(version, buf)) { /* 316 */ Log.e("Screenshot", "Unsupported protocol: " + version); /* 317 */ return null; /* */ } /* */ /* 320 */ Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size=" + imageParams.size + ", width=" + imageParams.width + ", height=" + imageParams.height); /* */ /* */ /* */ /* 324 */ write(adbChan, nudge); /* */ /* 326 */ reply = new byte[imageParams.size]; /* 327 */ read(adbChan, reply); /* */ /* 329 */ imageParams.data = reply; /* */ } finally { /* 331 */ if (adbChan != null) { /* 332 */ adbChan.close(); /* */ } /* */ } /* */ /* 336 */ return imageParams; /* */ }
作者 | 自主博客 | 微信 | CSDN |
天地会珠海分舵 | http://techgogogo.com | 服务号:TechGoGoGo 扫描码: | 向AI问一下细节 免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。 猜你喜欢最新资讯相关推荐开发者交流群:相关标签AI
助 手 |
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>