您的位置:首页 > 移动开发 > Android开发

从dumpsys自定义服务来认识Android binder

2016-04-15 22:15 316 查看
问题的提出

dumpsys是一个非常有用的命令,可以用来查看打印一些系统服务数据



adb shell dumpsys display

adb shell dumpsys battery

详细内容可以搜索dumpsys查看

在查看代码的时候,发现

publishBinderService(“battery”, new BinderService());

private final class BinderService extends Binder {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {

pw.println("Permission Denial: can't dump Battery service from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
return;
}

dumpInternal(pw, args);
}
}


猜测dumpsys 服务名

可以调用的服务是在这里设置的

publishBinderService(“battery”, new BinderService());

于是,照葫芦画瓢,写了一句

publishBinderService(“atest”, new BinderService());

预料adb shell dumpsys atest 会进行打印调用

结果呢?

编译后,手机不能开机了。

好在可以在DDMS里抓到log

01-01 00:00:57.841: E/AndroidRuntime(817): * FATAL EXCEPTION IN SYSTEM PROCESS: main

01-01 00:00:57.841: E/AndroidRuntime(817): java.lang.RuntimeException: Failed to start service com.android.server.BatteryService: onStart threw an exception

01-01 00:00:57.841: E/AndroidRuntime(817): at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:119)

01-01 00:00:57.841: E/AndroidRuntime(817): at com.android.server.SystemServer.startCoreServices(SystemServer.java:621)

01-01 00:00:57.841: E/AndroidRuntime(817): at com.android.server.SystemServer.run(SystemServer.java:372)

01-01 00:00:57.841: E/AndroidRuntime(817): at com.android.server.SystemServer.main(SystemServer.java:258)

01-01 00:00:57.841: E/AndroidRuntime(817): at java.lang.reflect.Method.invoke(Native Method)

01-01 00:00:57.841: E/AndroidRuntime(817): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:849)

01-01 00:00:57.841: E/AndroidRuntime(817): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:739)

01-01 00:00:57.841: E/AndroidRuntime(817): Caused by: java.lang.SecurityException

一个字符串名称异常导致了系统不能开机,也就是说,一个字符就可以让系统不能开机,太可怕了

在publishBinderService(“atest”, new BinderService());

调用的时候进行try catch处理

结果还好,系统可以开机了

01-01 13:20:07.860: D/BatteryService(968): ================ atest ============

01-01 13:20:07.861: E/SELinux(325): avc: denied { add } for service=atest scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager

01-01 13:20:07.862: E/ServiceManager(325): add_service(‘atest’,28) uid=1000 - PERMISSION DENIED

01-01 13:20:07.862: D/BatteryService(968): ================ atest catch ============

01-01 13:20:07.862: W/System.err(968): java.lang.SecurityException

01-01 13:20:07.868: W/System.err(968): at android.os.BinderProxy.transactNative(Native Method)

还不错,打印出了具体信息,SELinux权限的问题

搜索

SELinux(325): avc: denied { add } for service

在stackoverflow上看到一种解决方案

To file:

android-dev\external\sepolicy\service.te

Add:

type mytest_service, system_api_service, system_server_service, service_manager_type;

To file:

android-dev\external\sepolicy\service_contexts

Add:

mytestservice u:object_r:mytest_service:s0

where mytestservice your name service

修改android/external/sepolicy 里的文件

修改后编译,还是抛异常

查找代码

find . -name *.c|xargs grep ’ PERMISSION DENIED’

./frameworks/native/cmds/servicemanager/service_manager.c: ALOGE(“add_service(‘%s’,%x) uid=%d - PERMISSION DENIED\n”,

./frameworks/native/cmds/servicemanager/service_manager.c: ALOGE(“list_service() uid=%d - PERMISSION DENIED\n”,

修改了te文件还是有异常,??

这个不清楚是不是编译的问题,现在决定跳过赋权,对服务调用进行测试

修改./frameworks/native/cmds/servicemanager/service_manager.c

int do_add_service(struct binder_state *bs,

const uint16_t *s, size_t len,

uint32_t handle, uid_t uid, int allow_isolated,

pid_t spid)

{

struct svcinfo *si;

//ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
//        allow_isolated ? "allow_isolated" : "!allow_isolated", uid);

if (!handle || (len == 0) || (len > 127))
return -1;

if (!svc_can_register(s, len, spid)) {
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
str8(s, len), handle, uid);


ALOGE(“=======test go =======”);

// return -1;

}

就可以调用自定义服务了

dumpsysatestdumpsysatestBinderService2dumpcalled==================== dumpsys atest
dumpsys atest
BinderService2 dump called ====================

ap调用测试

adb shell dumpsys atest

可以调用atest服务的dump方法

再写个ap进行测试

Binder aObject;

try {

aObject = (Binder)getSystemService(“atest”);

int id = aObject.getCallingPid();

System.out.println(“Pid = ” + id);

Log.d(“test614”, “Pid = ” + id);

} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}

Log

01-05 09:32:35.122: D/test614(801): Pid = 801

这样调用的都是binder里的接口方法,如果要自定义方法,aidl就出场了

详细使用可以查看这位达人的系列blog

http://www.cloudchou.com/android/post-447.html

写的非常好

总结

这里通过添加一个自定义服务,了解了addService的一些信息。

binder是用来进行进程间通信的,和ICE通信机制类似。

采用一些数据传送方法,把client和server关联交互起来
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: