uiautomator2 源码阅读(四):主应用 – Service

本节涉及部分:([○] 本节覆盖,[√] 为前面已覆盖,[×] 为确认废弃)

app/src/
├── androidTest
│   └── java
│       └── com
│           └── github
│               └── uiautomator
│                   ├── ApplicationTest.java
│                   └── stub
│                       ├── AccessibilityEventListener.java
│                       ├── AccessibilityNodeInfoDumper.java
│                       ├── AutomatorHttpServer.java
│                       ├── AutomatorServiceImpl.java
│                       ├── AutomatorService.java
│                       ├── ConfiguratorInfo.java
│                       ├── DeviceInfo.java
│                       ├── Helper.java
│                       ├── Log.java
│                       ├── NotImplementedException.java
│                       ├── ObjInfo.java
│                       ├── Point.java
│                       ├── Rect.java
│                       ├── Selector.java
│                       ├── Stub.java
│                       ├── TouchController.java
│                       └── watcher
│                           ├── ClickUiObjectWatcher.java
│                           ├── PressKeysWatcher.java
│                           └── SelectorWatcher.java
└── main
    ├── aidl
    │   └── android
    │       └── view
    │           └── IRotationWatcher.aidl
    ├── AndroidManifest.xml [√]
    ├── java
    │   └── com
    │       └── github
    │           └── uiautomator
    │               ├── AdbBroadcastReceiver.java [√]
    │               ├── compat
    │               │   ├── InputManagerWrapper.java
    │               │   └── WindowManagerWrapper.java
    │               ├── Console.java
    │               ├── FastInputIME.java
    │               ├── FloatView.java [√]
    │               ├── IdentifyActivity.java [√]
    │               ├── MainActivity.java [√]
    │               ├── MinicapAgent.java
    │               ├── MinitouchAgent.java
    │               ├── MockLocationProvider.java
    │               ├── monitor
    │               │   ├── AbstractMonitor.java
    │               │   ├── BatteryMonitor.java [√]
    │               │   ├── HttpPostNotifier.java 
    │               │   ├── RotationMonitor.java [×]
    │               │   └── WifiMonitor.java [√]
    │               ├── RotationAgent.java
    │               ├── ScreenClient.java
    │               ├── ScreenHttpServer.java
    │               ├── Service.java [○]
    │               ├── ToastActivity.java [√]
    │               ├── ToastHelper.java [√]
    │               └── util
    │                   ├── InternalApi.java
    │                   ├── MemoryManager.java
    │                   ├── OkhttpManager.java
    │                   └── Permissons4App.java [√]
    └── res
        └── [...]

我们在前一节 Activity 部分已经做了初步的分析,这个 Service 是核心 uiautomator 的控制桥,前面看到是通过 jsonrpc 的接口调用来控制这个服务的启停的,按照设计思维推断,这个 jsonrpc 应该是主要的控制入口,在暴露给 adb 控制机上自动化进行启停的,应该也是这个接口来触发,因此在本节我们需要摸清 Service 内部的职测、工作原理,顺带顺藤摸瓜,找到 jsonrpc 的调用点,以便后续分析整个 jsonrpc 桥服务的运作机制。

主要生命周期钩子

我们看这个 Service 做了什么,主要看各个生命周期注册的行为。

image.png

官方科普:developer.android.com/guide/compo…

onCreate

首次服务创建时(后续不会),会调用这个生命周期钩子。

第一段:消息通知,并在前台运行服务

Intent notificationIntent = new Intent(this, MainActivity.class);
String channelId = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    channelId = createNotificationChannel("monitor service", "Monitor Service");
} else {
    // If earlier version channel ID is not used
    // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
}

builder = new NotificationCompat.Builder(this, channelId)
        .setSmallIcon(R.drawable.ic_notification)
        .setTicker(getString(R.string.monitor_service_ticker))
        .setContentTitle(getString(R.string.monitor_service_title))
        .setContentText(getString(R.string.monitor_service_text))
        .setContentIntent(PendingIntent.getActivity(this, NOTIFICATION_ID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT))
        .setWhen(System.currentTimeMillis());
Notification notification = builder.build();

里面的这一段,其实是在触发的时候,会弹出一个消息通知,而非首次启动服务的时候,不会重新触发,因此我们可以看到在手机上,如果出现了一条这样的消息通知,说明 Service 被初始化启动了一次。

image.png

然后这一句将在前台运行服务,我们可以看到在 onDestroy() 中会用 stopForeground(true) 清理这个前台运行。

startForeground(NOTIFICATION_ID, notification);

关于这个前台服务,可以看官方文档,事实上因为使用了前台服务,我们还需要在 AndroidManifest.xml 内添加一条权限:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

第二段:监听器

在当前的 service 上注册 BatteryMonitorWifiMonitor 这两个,Monitor 这块在下一节展开整体的 monitor 机制及源码分析。

HttpPostNotifier notifier = new HttpPostNotifier("http://127.0.0.1:7912");
Context context = getApplicationContext();
addMonitor(new BatteryMonitor(context, notifier));
addMonitor(new WifiMonitor(this, notifier));

基本上说,这个 notifier 是一个调用端,当 monitor 触发时间的时候调这个 notifier 设定好的目标服务去报送请求。

onStartCommand

这个钩子在 “另一个组件(例如 Activity)” 启动服务的时候触发,因此实际可以对应到 adb 启动服务的时候,传入一个 intent 来进入,看代码的话,仅仅是对服务本身的启停做一个控制接口的放出。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    Log.i(TAG, "On StartCommand");
    String action = intent.getAction();

    if (ACTION_START.equals(action)) {
        Log.i(TAG, "Receive start-service action, but ignore it");
    } else if (ACTION_STOP.equals(action)) {
        stopSelf();
    }

    return START_NOT_STICKY; // not start again, when killed by system
}

onBind: 不支持

科普一下什么是 Service 的 bind,经过了解,这部分其实是 Android Service 上的声明周期的一个基本节点,可以放出一个跟 Service 通讯的 IBinder 对象。

在本项目中,返回 null 说明不支持绑定。

onDestroy

简单的清理工作,清理 monitor,并且关闭前台,都是基本操作。

@Override
public void onDestroy() {
    super.onDestroy();
    Log.i(TAG, "Stopping service");
    removeAllMonitor();
    Log.i(TAG, "unregister all watchers");
    stopForeground(true);
}

注入点

我们看到 Service 类里面其实也没有特别重的控制逻辑,那么问题来了,到底为何我们 POST http://127.0.0.1:7912/uiautomator 的时候可以启动这个服务,在这个接口的内部应该有触发这个 Service 启停的处理,我们需要先找到这个点。

经过后续对整个项目的分析,:7912 上放出的 http 服务接口,是经过 atx-agent 的外层服务反向代理进去内层服务的 :9008 的。

:9008 的这个 HttpServer,是通过 androidTest 部分的逻辑,启动一个阻塞的 @Test 测试项来实现的,启动方式已经在第一章中说明,因此与 uiautomator 功能相关的核心逻辑其实是在 androidTest 目录下。

启动方式:

# 停止 AtxAgent
adb shell /data/local/tmp/atx-agent server --stop
# 启动 AtxAgent
adb shell /data/local/tmp/atx-agent server --nouia -d --addr 127.0.0.1 7912

atx-agent 内部会自动维持这个服务活动,执行的是:

adb shell am instrument -w -r -e debug false -e class com.github.uiautomator.stub.Stub com.github.uiautomator.test/android.support.test.runner.AndroidJUnitRunner

监听器模式:Monitor 机制

我们看到在 Service 类中声明了 monitors 列表属性,这个与之前看到的 Receiver 是一样的。

这里的 Receiver 主要就是加入了 WifiMonitor 和 BatteryMonitor,以监听电量变化和网络断连的事件。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYCwfhtb' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片