uiautomator获取不到动态界面的缘由

来源:互联网 发布:应用双开软件下载 编辑:程序博客网 时间:2024/06/05 11:20

这几天查看了下源码发现,uiautomatorviewer在获取界面布局信息的时候用的是启动一个脚本,该脚本在/system/bin/uiautomator。这个命令也可以在命令行下启动。





默认情况下,获取的控件信息保存在/storage/emulated/legacy/window_dump.xml文件中,你也可以改变它保存的目录,例如保存在data/local/tmp下






这是正常情况下的,但我进入秒表界面,将秒表开启。然后执行上面的命令:




报了could not get idle state的错。


说明uiautomator在获取界面状态信息时,首先要等界面处于idle空闲状态才会做dump操作。这就是uiautomator死活拿不到动态界面信息的原因。


调出uiautomator这个脚本。

## Copyright (C) 2012 The Android Open Source Project## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##      http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.## Script to start "uiautomator" on the device## The script does a couple of things:# * Use an alternative dalvik cache when running as non-root. Jar file needs#   to be dexopt'd to run in Dalvik. For plain jar files, this is done at first#   use. shell user does not have write permission to default system Dalvik#   cache so we redirect to an alternative cache# * special processing for subcommand 'runtest':#    * '--nohup' allows process continue to run even if parent process that#      started it has already terminated. We parse for this parameter and set#      signal trap. This is useful for testing with USB disconnected#    * all jar files that the test classes resides in, or dependent on are#      provided on command line and exported to CLASSPATH environment variable#      before starting the Java code. This offloads the task of class loading#      and resolving of cross jar class dependency to Dalvik#    * all other subcommand or options are directly passed into Java code for#      further parsingexport run_base=/data/local/tmpexport base=/system# if not running as root, trick dalvik into using an alternative dex cacheif [ ${USER_ID} -ne 0 ]; then  tmp_cache=${run_base}/dalvik-cache  if [ ! -d ${tmp_cache} ]; then    mkdir -p ${tmp_cache}  fi  export ANDROID_DATA=${run_base}fi# take first parameter as the commandcmd=${1}if [ -z "${1}" ]; then  cmd="help"fi# strip the command parameterif [ -n "${1}" ]; then  shiftfiCLASSPATH=/system/framework/android.test.runner.jar:${base}/framework/uiautomator.jar# eventually args will be what get passed down to Java codeargs=# we also pass the list of jar files, so we can extract class names for tests# if they are not explicitly specifiedjars=# special case pre-processing for 'runtest' commandif [ "${cmd}" == "runtest" ]; then  # first parse the jar paths  while [ true ]; do    if [ -z "${1}" ] && [ -z "${jars}" ]; then      echo "Error: more parameters expected for runtest; please see usage for details"      cmd="help"      break    fi    if [ -z "${1}" ]; then      break    fi    jar=${1}    if [ "${1:0:1}" = "-" ]; then      # we are done with jars, starting with parameters now      break    fi    # if relative path, append the default path prefix    if [ "${1:0:1}" != "/" ]; then      jar=${run_base}/${1}    fi    # about to add the file to class path, check if it's valid    if [ ! -f ${jar} ]; then      echo "Error: ${jar} does not exist"      # force to print help message      cmd="help"      break    fi    jars=${jars}:${jar}    # done processing current arg, moving on    shift  done  # look for --nohup: if found, consume it and trap SIG_HUP, otherwise just  # append the arg to args  while [ -n "${1}" ]; do    if [ "${1}" = "--nohup" ]; then      trap "" HUP      shift    else      args="${args} ${1}"      shift    fi  doneelse  # if cmd is not 'runtest', just take the rest of the args  args=${@}fiargs="${cmd} ${args}"if [ -n "${jars}" ]; then   args="${args} -e jars ${jars}"fiCLASSPATH=${CLASSPATH}:${jars}export CLASSPATHexec app_process ${base}/bin com.android.commands.uiautomator.Launcher ${args}

看到最后一句话是去执行了com.android.commands.uiautomator.Launcher这个类。该类位于uiautomator.jar包里。该jar包在framework中。



导出该jar包,查看里面的laucher类。



不幸的是,打开以后,就一个dex文件,想办法暴力破解,更不幸的是破解后的smali文件我依然看不懂。




.class public Lcom/android/commands/uiautomator/Launcher;.super Ljava/lang/Object;.source "Launcher.java"# annotations.annotation system Ldalvik/annotation/MemberClasses;    value = {        Lcom/android/commands/uiautomator/Launcher$Command;    }.end annotation# static fields.field private static COMMANDS:[Lcom/android/commands/uiautomator/Launcher$Command;.field private static HELP_COMMAND:Lcom/android/commands/uiautomator/Launcher$Command;# direct methods.method static constructor <clinit>()V    .registers 3    .prologue    .line 99    new-instance v0, Lcom/android/commands/uiautomator/Launcher$1;    const-string v1, "help"    invoke-direct {v0, v1}, Lcom/android/commands/uiautomator/Launcher$1;-><init>(Ljava/lang/String;)V    sput-object v0, Lcom/android/commands/uiautomator/Launcher;->HELP_COMMAND:Lcom/android/commands/uiautomator/Launcher$Command;    .line 129    const/4 v0, 0x4    new-array v0, v0, [Lcom/android/commands/uiautomator/Launcher$Command;    const/4 v1, 0x0    sget-object v2, Lcom/android/commands/uiautomator/Launcher;->HELP_COMMAND:Lcom/android/commands/uiautomator/Launcher$Command;    aput-object v2, v0, v1    const/4 v1, 0x1    new-instance v2, Lcom/android/commands/uiautomator/RunTestCommand;    invoke-direct {v2}, Lcom/android/commands/uiautomator/RunTestCommand;-><init>()V    aput-object v2, v0, v1    const/4 v1, 0x2    new-instance v2, Lcom/android/commands/uiautomator/DumpCommand;    invoke-direct {v2}, Lcom/android/commands/uiautomator/DumpCommand;-><init>()V    aput-object v2, v0, v1    const/4 v1, 0x3    new-instance v2, Lcom/android/commands/uiautomator/EventsCommand;    invoke-direct {v2}, Lcom/android/commands/uiautomator/EventsCommand;-><init>()V    aput-object v2, v0, v1    sput-object v0, Lcom/android/commands/uiautomator/Launcher;->COMMANDS:[Lcom/android/commands/uiautomator/Launcher$Command;    return-void.end method.method public constructor <init>()V    .registers 1    .prologue    .line 31    invoke-direct {p0}, Ljava/lang/Object;-><init>()V    .line 36    return-void.end method.method static synthetic access$000()[Lcom/android/commands/uiautomator/Launcher$Command;    .registers 1    .prologue    .line 31    sget-object v0, Lcom/android/commands/uiautomator/Launcher;->COMMANDS:[Lcom/android/commands/uiautomator/Launcher$Command;    return-object v0.end method.method private static findCommand(Ljava/lang/String;)Lcom/android/commands/uiautomator/Launcher$Command;    .registers 6    .parameter "name"    .prologue    .line 91    sget-object v0, Lcom/android/commands/uiautomator/Launcher;->COMMANDS:[Lcom/android/commands/uiautomator/Launcher$Command;    .local v0, arr$:[Lcom/android/commands/uiautomator/Launcher$Command;    array-length v3, v0    .local v3, len$:I    const/4 v2, 0x0    .local v2, i$:I    :goto_4    if-ge v2, v3, :cond_16    aget-object v1, v0, v2    .line 92    .local v1, command:Lcom/android/commands/uiautomator/Launcher$Command;    invoke-virtual {v1}, Lcom/android/commands/uiautomator/Launcher$Command;->name()Ljava/lang/String;    move-result-object v4    invoke-virtual {v4, p0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z    move-result v4    if-eqz v4, :cond_13    .line 96    .end local v1           #command:Lcom/android/commands/uiautomator/Launcher$Command;    :goto_12    return-object v1    .line 91    .restart local v1       #command:Lcom/android/commands/uiautomator/Launcher$Command;    :cond_13    add-int/lit8 v2, v2, 0x1    goto :goto_4    .line 96    .end local v1           #command:Lcom/android/commands/uiautomator/Launcher$Command;    :cond_16    const/4 v1, 0x0    goto :goto_12.end method.method public static main([Ljava/lang/String;)V    .registers 6    .parameter "args"    .prologue    const/4 v4, 0x0    const/4 v3, 0x1    .line 74    const-string v2, "uiautomator"    invoke-static {v2}, Landroid/os/Process;->setArgV0(Ljava/lang/String;)V    .line 75    array-length v2, p0    if-lt v2, v3, :cond_22    .line 76    aget-object v2, p0, v4    invoke-static {v2}, Lcom/android/commands/uiautomator/Launcher;->findCommand(Ljava/lang/String;)Lcom/android/commands/uiautomator/Launcher$Command;    move-result-object v1    .line 77    .local v1, command:Lcom/android/commands/uiautomator/Launcher$Command;    if-eqz v1, :cond_22    .line 78    new-array v0, v4, [Ljava/lang/String;    .line 79    .local v0, args2:[Ljava/lang/String;    array-length v2, p0    if-le v2, v3, :cond_1e    .line 81    array-length v2, p0    invoke-static {p0, v3, v2}, Ljava/util/Arrays;->copyOfRange([Ljava/lang/Object;II)[Ljava/lang/Object;    move-result-object v0    .end local v0           #args2:[Ljava/lang/String;    check-cast v0, [Ljava/lang/String;    .line 83    .restart local v0       #args2:[Ljava/lang/String;    :cond_1e    invoke-virtual {v1, v0}, Lcom/android/commands/uiautomator/Launcher$Command;->run([Ljava/lang/String;)V    .line 88    .end local v0           #args2:[Ljava/lang/String;    .end local v1           #command:Lcom/android/commands/uiautomator/Launcher$Command;    :goto_21    return-void    .line 87    :cond_22    sget-object v2, Lcom/android/commands/uiautomator/Launcher;->HELP_COMMAND:Lcom/android/commands/uiautomator/Launcher$Command;    invoke-virtual {v2, p0}, Lcom/android/commands/uiautomator/Launcher$Command;->run([Ljava/lang/String;)V    goto :goto_21.end method

貌似做了代码混淆。只能去网上搜搜看啦!


还是在之前的源码网站上找到了。


/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.android.commands.uiautomator;import android.app.UiAutomation;import android.graphics.Point;import android.hardware.display.DisplayManagerGlobal;import android.os.Environment;import android.view.Display;import android.view.accessibility.AccessibilityNodeInfo;import com.android.commands.uiautomator.Launcher.Command;import com.android.uiautomator.core.AccessibilityNodeInfoDumper;import com.android.uiautomator.core.UiAutomationShellWrapper;import java.io.File;import java.util.concurrent.TimeoutException;/** * Implementation of the dump subcommand * * This creates an XML dump of current UI hierarchy */public class DumpCommand extends Command {    private static final File DEFAULT_DUMP_FILE = new File(            Environment.getLegacyExternalStorageDirectory(), "window_dump.xml");    public DumpCommand() {        super("dump");    }    @Override    public String shortHelp() {        return "creates an XML dump of current UI hierarchy";    }    @Override    public String detailedOptions() {        return "    dump [--verbose][file]\n"            + "      [--compressed]: dumps compressed layout information.\n"            + "      [file]: the location where the dumped XML should be stored, default is\n      "            + DEFAULT_DUMP_FILE.getAbsolutePath() + "\n";    }    @Override    public void run(String[] args) {        File dumpFile = DEFAULT_DUMP_FILE;        boolean verboseMode = true;        for (String arg : args) {            if (arg.equals("--compressed"))                verboseMode = false;            else if (!arg.startsWith("-")) {                dumpFile = new File(arg);            }        }        UiAutomationShellWrapper automationWrapper = new UiAutomationShellWrapper();        automationWrapper.connect();        if (verboseMode) {            // default            automationWrapper.setCompressedLayoutHierarchy(false);        } else {            automationWrapper.setCompressedLayoutHierarchy(true);        }        // It appears that the bridge needs time to be ready. Making calls to the        // bridge immediately after connecting seems to cause exceptions. So let's also        // do a wait for idle in case the app is busy.        try {            UiAutomation uiAutomation = automationWrapper.getUiAutomation();            uiAutomation.waitForIdle(1000, 1000 * 10);            AccessibilityNodeInfo info = uiAutomation.getRootInActiveWindow();            if (info == null) {                System.err.println("ERROR: null root node returned by UiTestAutomationBridge.");                return;            }            Display display =                    DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);            int rotation = display.getRotation();            Point size = new Point();            display.getSize(size);            AccessibilityNodeInfoDumper.dumpWindowToFile(info, dumpFile, rotation, size.x, size.y);        } catch (TimeoutException re) {            System.err.println("ERROR: could not get idle state.");            return;        } finally {            automationWrapper.disconnect();        }        System.out.println(                String.format("UI hierchary dumped to: %s", dumpFile.getAbsolutePath()));    }}

源码发现确实是这样的。如何解决了。。。。。。fighting

0 1
原创粉丝点击