service call源码分析(以蓝牙打开关闭为例)
900 Words|Read in about 4 Min|本文总阅读量次
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文件
可使用的参数为
service list
显示系统当前所有在service manager注册的service,类似dumpsys -l
service check SERVICE
查询SERVICE是否存在
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函数摘取部分内容,主要对上面标注的三处进行分析
-
查询blutooth_manager服务是否存在
由于已经有sm(servicemanager)这个大管家了,直接通过输入的参数blutooth_manager 找到对应的服务,这里并不是真正的服务,而是相对于服务端的一个代理,实际上是BluetoothManager.Proxy(代理可以通过binder方式跨进程调用最终服务)。
-
蓝牙服务对应的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. . . .'
-
蓝牙的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.