Android中如果需要通过adb指令调用系统服务中的方法,可以通过service call的形式。

0简介

举例说明,service call的常见用法

 1# 1.绑定port启动ViewServer
 2adb shell service call window 1 i32 $port
 3
 4# 2.停止ViewServer
 5adb shell service call window 2
 6
 7# 3.检查ViewServer是否正在运行
 8adb shell service call window 3
 9
10# 关闭HW overlays,code为1008,一个参数为int的1 
11adb shell service call SurfaceFlinger 1008 i32 1
12
13# 4.显示fps。来源见SurfaceFlinger.cpp中函数onTransact的switch片段,使用见surface_stats_collector.py
14adb shell service call SurfaceFlinger 1013 

service call的形式本质也是使用service调试命令。

 1picasso:/ $ service -h
 2Usage: service [-h|-?]
 3       service list
 4       service check SERVICE
 5       service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...
 6Options:
 7   i32: Write the 32-bit integer N into the send parcel.
 8   i64: Write the 64-bit integer N into the send parcel.
 9   f:   Write the 32-bit single-precision number N into the send parcel.
10   d:   Write the 64-bit double-precision number N into the send parcel.
11   s16: Write the UTF-16 string STR into the send parcel.

service本身作为一个命令的bin文件

可使用的参数为

  1. service list

    显示系统当前所有在service manager注册的service,类似dumpsys -l

  2. service check SERVICE

    查询SERVICE是否存在

  3. service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] …

    可以通过binder给service发送code,还可以向service发送intent等

本文结合蓝牙服务来分析,蓝牙的开关的源码(android13源码)

1# 打开蓝牙
2adb shell service call blutooth_manager 5
3# 关闭蓝牙
4adb shell service call blutooth_manager 7
5# 查看蓝牙状态,enable为true为打开,false为关闭
6adb shell dumpsys blutooth_manager | grep enable

1 service call

这里的service位置手机目录的/system/bin下面,这里是一个二进制的进程

对应的bp文件

 1//frameworks/native/cmds/service/Android.bp
 2cc_binary {
 3    //进程的名字是service
 4    name: "service",
 5	//生成进程的源文件service.cpp
 6    srcs: ["service.cpp"],
 7	//依赖的系统动态库
 8    shared_libs: [
 9        "libcutils",
10        "libutils",
11        "libbinder",
12    ],
13	//编译相关参数
14    cflags: [
15        "-DXP_UNIX",
16        "-Wall",
17        "-Werror",
18    ],
19}

可以知道最终service会调用的service.cpp的main函数中

2service call bluetooth_manager 5

本文这里以蓝牙的打开为例,即对应的蓝牙服务为blutooth_manager

 1//frameworks/native/cmds/service/service.cpp
 2int main(int argc, char* const argv[])
 3{
 4    bool wantsUsage = false;
 5    int result = 0;
 6    //这里的prog_name就是通过adb指令调用的service进程
 7    char* prog_name = basename(argv[0]);
 8    //启动ServiceManager大管家,后续在大管家中找对应服务
 9    sp<IServiceManager> sm = defaultServiceManager();
10    fflush(stdout);
11    ...
12    if (optind >= argc) {
13        wantsUsage = true;
14    //兵分三路,分别对应service的三个参数,service check、service list、service call
15    } else if (!wantsUsage) {
16        if (strcmp(argv[optind], "check") == 0) {
17            //service check走这里
18            ...
19        }
20        else if (strcmp(argv[optind], "list") == 0) {
21            //service list走这里
22            ...
23        } else if (strcmp(argv[optind], "call") == 0) {
24            //这里optind参数后移一位,对应的是具体的服务
25            optind++;
26            if (optind+1 < argc) {
27                int serviceArg = optind;
28                //【1】binder服务查询,通过sm大管家查询是否存在对应服务,这里为blutooth_manager 
29                sp<IBinder> service = sm->checkService(String16(argv[optind++]));
30                //这里的ifName为android.bluetooth.IBluetoothManager
31                String16 ifName = (service ? service->getInterfaceDescriptor() : String16());
32                //这里的code对应的是aidl方法中的对应的顺序,起始方法为1,按照次序往下
33                int32_t code = atoi(argv[optind++]);
34                if (service != nullptr && ifName.size() > 0) {
35                    Parcel data, reply;
36                    data.markForBinder(service);
37
38                    // 【2】通过序列化的方式,将查询出来的服务对应的名称写到内存中去
39                    data.writeInterfaceToken(ifName);
40
41                    // 处理剩余的一些参数,主要是传递的数据,这里没有其他数据,暂时不处理
42                    // 这里会涉及到数据传输
43                    // 32位的int型,参数为i32
44                    // 64位的int型,参数为i64
45                    // 单精度的浮点数类型,参数为f
46                    // 双精度的浮点数类型,参数为d
47                    // string16字符串类型,参数为s16
48                    while (optind < argc) {...}
49		            //【3】真实的调用,这里用到了binder原理,通过客户端的代理调用真实的远端服务
50                    // 这里会调用到BluetoothManagerService
51                    service->transact(code, data, &reply);
52                    aout << "Result: " << reply << endl;
53                } else {
54                    aerr << prog_name << ": Service " << argv[serviceArg]
55                        << " does not exist" << endl;
56                }
57            } else {
58                aerr << prog_name << ": No service specified for call" << endl;
59            }
60        } else {
61            aerr << prog_name << ": Unknown command " << argv[optind] << endl;
62        }
63    }
64    ...
65    return result;
66}

这个main函数摘取部分内容,主要对上面标注的三处进行分析

  1. 查询blutooth_manager服务是否存在

    由于已经有sm(servicemanager)这个大管家了,直接通过输入的参数blutooth_manager 找到对应的服务,这里并不是真正的服务,而是相对于服务端的一个代理,实际上是BluetoothManager.Proxy(代理可以通过binder方式跨进程调用最终服务)。

  2. 蓝牙服务对应的ifName序列化

    通过查询到的BluetoothManager.Proxy,获取对应的ifName,即为"android.bluetooth.IBluetoothManager",通过Parcelable方式序列化这个字符串,类似下面的序列化

    1  0x000002c0: 00000000 006e0061 00720064 0069006f ' . .a.n.d.r.o.i.'
    2  0x000002d0: 002e0064 006c0062 00650075 006f0074 'd...b.l.u.e.t.o.'
    3  0x000002e0: 0074006f 002e0068 00420049 0075006c 'o.t.h...I.B.l.u.'
    4  0x000002f0: 00740065 006f006f 00680074 0061004d 'e.t.o.o.t.h.M.a.'
    5  0x00000300: 0061006e 00650067 00240000 00000000 'n.a.g.e.r. . . .'
    
  3. 蓝牙的binder通信

    通过code找到aidl中的序列号对应的方法,然后在对应BluetoothManagerService服务中也找到对应的方法(不同android版本对应不同的序列号,android11,6是打开,8是关闭)

 1//packages/modules/Bluetooth/system/binder/android/bluetooth/IBluetoothManager.aidl
 2interface IBluetoothManager
 3{
 4    IBluetooth registerAdapter(in IBluetoothManagerCallback callback);
 5
 6    void unregisterAdapter(in IBluetoothManagerCallback callback);
 7    @UnsupportedAppUsage
 8    void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
 9    @UnsupportedAppUsage
10    void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
11    //这个是打开
12    boolean enable(in AttributionSource attributionSource);    
13    boolean enableNoAutoConnect(in AttributionSource attributionSource);
14    //这个是关闭
15    boolean disable(in AttributionSource attributionSource, boolean persist);    
16    int getState();
17    @UnsupportedAppUsage   
18    IBluetoothGatt getBluetoothGatt();
19    ...
20}

对应的BluetoothManagerService服务

 1//packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java
 2public class BluetoothManagerService extends IBluetoothManager.Stub {
 3    private static final String TAG = "BluetoothManagerService";
 4    //具体为打开蓝牙逻辑,不展开
 5    public boolean enable(AttributionSource attributionSource) throws RemoteException {
 6        ...
 7    }
 8    //具体为关闭蓝牙逻辑,不展开
 9    public boolean disable(AttributionSource attributionSource, boolean persist) {
10        ...
11    }
12            
13}    

3最终结果

如果显示如下没有权限,需要给这个命令root权限,蓝牙服务本身也会对执行命令进行权限校验

 1vince:/ $ service call bluetooth_manager 5
 2Result: Parcel(
 3  0x00000000: ffffffff 0000006e 0065004e 00640065 '....n...N.e.e.d.'
 4  0x00000010: 00420020 0055004c 00540045 004f004f ' .B.L.U.E.T.O.O.'
 5  0x00000020: 00480054 00410020 004d0044 004e0049 'T.H. .A.D.M.I.N.'
 6  0x00000030: 00700020 00720065 0069006d 00730073 ' .p.e.r.m.i.s.s.'
 7  0x00000040: 006f0069 003a006e 004e0020 00690065 'i.o.n.:. .N.e.i.'
 8  0x00000050: 00680074 00720065 00750020 00650073 't.h.e.r. .u.s.e.'
 9  0x00000060: 00200072 00300032 00300030 006e0020 'r. .2.0.0.0. .n.'
10  0x00000070: 0072006f 00630020 00720075 00650072 'o.r. .c.u.r.r.e.'
11  0x00000080: 0074006e 00700020 006f0072 00650063 'n.t. .p.r.o.c.e.'
12  0x00000090: 00730073 00680020 00730061 00610020 's.s. .h.a.s. .a.'
13  0x000000a0: 0064006e 006f0072 00640069 0070002e 'n.d.r.o.i.d...p.'
14  0x000000b0: 00720065 0069006d 00730073 006f0069 'e.r.m.i.s.s.i.o.'
15  0x000000c0: 002e006e 004c0042 00450055 004f0054 'n...B.L.U.E.T.O.'
16  0x000000d0: 0054004f 005f0048 00440041 0049004d 'O.T.H._.A.D.M.I.'
17  0x000000e0: 002e004e 00000000                   'N.......        ')

如果有root权限,通常会返回一串序列化的二进制数字,这里的0x01,实际上返回的就是true,说明蓝牙打开成功。

1vince:/ # service call bluetooth_manager 5
2service call bluetooth_manager 5
3Result: Parcel(00000000 00000001   '........')

4总结

总的来说,这就是Android本身的一个cmds下面的命令,来用增加开发者对于Android系统开发调测功能,更加的便利。

参考

[1] SevenUUp, 【翻译】adb命令之service call, 2019.

[2] lyf5231, android—调试命令service, 2016.

[3] Mr_老冷, adb shell命令整理之service, 2016.