今天看啥  ›  专栏  ›  jkwen

Android 进阶解密阅读笔记5

jkwen  · 简书  ·  · 2021-01-30 16:24

接上篇 Android 进阶解密阅读笔记4 内容,以下代码是基于 API 28 版本进行的分析,分析思路还是参阅的「Android 进阶解密」,不过书上好像有个小错误,所以我就参照着书本做的分析。

//ActiveServices
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, final IServiceConnection connection, int flags,String callingPackage, final int userId) throws TransactionTooLargeException {
    //获取当前应用进程信息
    final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
    //获取相关的 Service 信息
    ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg, isBindExternal, allowInstant);
    ServiceRecord s = res.record;
    
    AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
    ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent);
    
    if ((flags&Context.BIND_AUTO_CREATE) != 0) {
        s.lastActivity = SystemClock.uptimeMillis();
        //按 startService 的流程启动 Service
        if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                permissionsReviewRequired) != null) {
            return 0;
        }
    }
    
    if (s.app != null && b.intent.received) {
        // Service is already running, so we can immediately
        // publish the connection.
        try {
            //这里 Service 与 应用进程建立了 binder 通信
            c.conn.connected(s.name, b.intent.binder, false);
        } catch (Exception e) {}
        // If this is the first app connected back to this binding,
        // and the service had previously asked to be told when
        // rebound, then do so.
        if (b.intent.apps.size() == 1 && b.intent.doRebind) {
            requestServiceBindingLocked(s, b.intent, callerFg, true);
        }
    } else if (!b.intent.requested) {
        requestServiceBindingLocked(s, b.intent, callerFg, false);
    }
}

假设当前应用绑定了这个 Service, callerApp 就代表着当前应用进程信息,接下去会通过 retrieveServiceLocked 方法生成一个 ServiceLookupResult 对象,这个方法的大致逻辑是通过调用者进程先从缓存里找到关联的 ServiceRecord,如果没有就新建,并存入缓存。从 ServiceLookupResult 对象中能取到 ServiceRecord s

再往下同样的逻辑可以取到 AppBindRecord 对象 b ,以及新建的 ConnectionRecord 对象 c

接着会自动创建 Service,也就是调 bringUpServiceLocked 方法走 startService 那套流程,正常启动时方法返回 null,不是 null 的话就是有问题,那么绑定过程就中止了。

再往下会,s.app 是 ProcessRecord 类型,在前面执行 realStartServiceLocked 方法时会赋值,意思是 Service 所运行的应用进程,那么这里就是指 callerApp 对象,如果前面能正常启动,那这里就不为 null。b.intent 是 IntentBindRecord 类型,b.intent.received 为 true 表示应用进程收到了绑定回调,可以获取到 Binder 对象了。

假设这是首次,应该还没收到,那么再去看下个判断,b.intent.requested 为 true 表示已发起绑定请求。此时还没有发起绑定,所以进入语句内执行 requestServiceBindingLocked 方法,

//ActiveServices
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    //前面正是因为 !i.requested 为 true 才执行到这的,所以前半部条件满足
    //i.apps 在前面获取 AppBindRecord 对象 b 时用过,可以回过头看下,就是 Service 关联的应用进程集合
    //可见条件满足
    if((!i.requested || rebing) && i.apps.size() > 0) {
        try {
            //熟悉的操作,这里通过相关联的应用进程的 ApplicationThread 继续处理
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.repProcState);
            if(!rebind) {
                //你看,这里就把请求标记至为 true 了
                i.requested = true;
            }
            i.hasBound = true;
            i.doRebind = false;
        }
    }
}
//ApplicationThread 会通过消息机制切到 ActivityThread 上执行
//ActivityThread
private void handleBindService(BindServiceData data) {
    //从缓存中取出相应 service,这是之前执行 realStartServiceLocked 时存进去的
    Service s = mServices.get(data.token);
    if(s != null) {
        try {
            if(!data.rebind) {
                //第一次会走这里,想想 onBind 方法不就是我们实现 Service 的时候要做的么
                IBinder binder = s.onBind(data.intent);
                ActivityManager.getService.publishService(data.token, data.intent, binder);
            } else {
                s.onRebind(data.intent);
                ActivityManager.getService.serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            }
        }
    }
}
//往 AMS 过一下,又回到了 ActiveServices 并调用了 publishServiceLocked 方法
//ActiveServices
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    if (r != null) {
        Intent.FilterComparison filter = new Intent.FilterComparison(intent);
        //这里 r.bindings 在之前获取 AppBindRecord 对象 b 的时候用过,所以这里可以取到
        IntentBindRecord b = r.bindings.get(filter);
        if(b != null && !b.received) {
            //此时请求绑定已经执行,需要等待回调,所以 b.received 为 false
            b.binder = service;
            b.requested = true;
            b.received = true;
            for (int conni=r.connections.size()-1; conni>=0; conni--) {
                ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                for (int i=0; i<clist.size(); i++) {
                    ConnectionRecord c = clist.get(i);
                    try {
                        //最后这里就是绑定连接了
                        //这里实际调用的是 LoadedApk.ServiceDispatcher.InnerConnection
                        //的 connected 方法,最后饶了几层会调用 LoadedApk.ServiceDispatcher
                        //的 doConnected 方法。
                        c.conn.connected(r.name, service, false);
                    }
                }
            }
        }
        serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
    }
}
//LoadedApk.ServiceDispatcher
public void doConnected(ComponentName name, IBinder service, boolean dead) {
    //方法的前半部会通过 mActiveConnections 做一些缓存检查
    //然后在这里调用 onServiceConnected 方法
    //方法入参的 service 就是之前 onBind 方法的返回值
    //这里的 mConnection 是 ServiceConnection 类型,这个被包含在 ConnectionRecord 里
    //也就是描述 Service 与相关联应用进程的一次连接通信
    //那么通过 IBinder 类型的 service 入参,我们就能实现 应用 与 Service 的通信了。
    if (service != null) {
        mConnection.onServiceConnected(name, service);
    } else {
        mConnection.onNullBinding(name);
    }
}

同样的思路,如果最开始时条件 (s.app != null && b.intent.received) 满足的话,那么就会直接去连接并做 rebind 操作。




原文地址:访问原文地址
快照地址: 访问文章快照