美文网首页android 技术梳理
Android 进阶解密阅读笔记5

Android 进阶解密阅读笔记5

作者: jkwen | 来源:发表于2021-01-30 16:24 被阅读0次

    接上篇 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 操作。

    相关文章

      网友评论

        本文标题:Android 进阶解密阅读笔记5

        本文链接:https://www.haomeiwen.com/subject/iowqtltx.html