Android四大组件系列6 bindService流程

一 概述

bindService 和 startService 过程差不多,差别主要是在创建 Service 实例后一个是执行 bind 操作,一个是执行 start 操作。

本篇文章将从进程的角度出发来分析 bindService 流程,在 bindService 的流程中将要涉及到三个主要的进程,分别是 bindService 发起端进程,system_server 进程和目的端 Service 进程,我们将会以这三个进程角度出来阐述 bindService 是怎么在这三个进程之间辗转腾挪达到远程绑定服务或者说是 Binder 传递功能的。

分析的系统源码为 android 12 。

涉及代码如下:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java

frameworks/base/core/java/android/app/LoadedApk.java
frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/core/java/android/app/Service.java

在这里插入图片描述

二 发起端进程发送 bindService 请求

2.1 ContextImpl.bindService

frameworks/base/core/java/android/app/ContextImpl.java

@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
   
    // 和 startService 流程一样,检查是否是系统应用调用的,打印 log
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, null,
            mMainThread.getHandler(), null, getUser());
}

注意第5个参数,传入了主线程的 handler,对应着 client 端的主线程 handler,后面会用到它。

2.2 ContextImpl.bindServiceCommon

private boolean bindServiceCommon(Intent service, ServiceConnection conn,
        ......) {
   
    // 获取 ServiceDispatcher 对象,用来实现进程间通信的核心
    // 本质上是一个 ServiceDispatcher.InnerConnection 对象,这个类是
    // 实现了 IServiceConnection 接口的 Binder 实体,是服务端
    IServiceConnection sd;
    if (conn == null) {
   
            throw new IllegalArgumentException("connection is null");
        }
        if (handler != null && executor != null) {
   
            throw new IllegalArgumentException("Handler and Executor both supplied");
        }
    if (mPackageInfo != null) {
   
        if (executor != null) {
           
            sd = mPackageInfo.getServiceDispatcher(conn,
                getOuterContext(), executor, flags);
        } else {
   
        // conn 封装到了 ServiceDispatcher 中
            sd = mPackageInfo.getServiceDispatcher(conn,
                getOuterContext(), handler, flags);
        }
    }
    // 获取 Activity token
    IBinder token = getActivityToken();
    ......
    // 绑定 isolated 服务. 
    int res = ActivityManager.getService().bindIsolatedService(
        mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
    if (res < 0) {
   
          throw new SecurityException(
                 "Not allowed to bind to service " + service);
    }
    return res != 0;
}

将这个方法分为两部分来看,一部分是创建 sd 对象,第二部是调用 AMS 的 bindIsolatedService() 方法与系统进程交互。

先来看 sd 是如何被赋值的。这里 mPackageInfo 不为 null,并且 executor 传入的为 null,所以执行 else 分支调用 mPackageInfo 的 getServiceDispatcher() 方法得到一个 sd 对象,其中第一个参数 conn 为我们在客户端创建的 ServiceConnection,第三个参数 handler 为前文提到的客户端 app 主线程的 handler。mPackageInfo 是 LoadedApk 类型对象。

2.2.1 LoadedApk.getServiceDispatcher

LoadedApk.java

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
        Context context, Handler handler, int flags) {
   
    return getServiceDispatcherCommon(c, context, handler, null, flags);
}

继续调用 getServiceDispatcherCommon

LoadedApk.java

private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> 
        mServices = new ArrayMap<>(); 
        // 一个 ServiceConnection 对应一个 ServiceDispatcher,一一对应关系
        // 以 Context 为键值,存储在 ArrayMap 形式的 mServices 中

private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
        Context context, Handler handler, Executor executor, int flags) {
   
    synchronized (mServices) {
   
        LoadedApk.ServiceDispatcher sd = null;
        // 一个 ServiceConnection 对应一个 ServiceDispatcher,一一对应关系
        // 以 Context 为键值,存储在 ArrayMap 形式的 mServices 中
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map =
            mServices.get(context);
        if (map != null) {
   
            if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " +
                sd + " for conn " + c);
            sd = map.get(c);
        }
        if (sd == null) {
   
            if (executor != null) {
   
                sd = new ServiceDispatcher(c, context, executor, flags);
            } else {
   
           // 创建一个 ServiceDispatcher 实例,封装 context, connection 等
                sd = new ServiceDispatcher(c, context, handler, flags);
            }
            ......
            if (map == null) {
   
                map = new ArrayMap<>();
                mServices.put(context, map);
            }
            // 把 connection 和封装这个 connection 的 sd,放入 map 中
            map.put(c, sd);
        } else {
   
            sd.validate(context, handler, executor);
        }
        // 返回 sd 的内部类 ServiceDispatcher.InnerConnection 对象 
        // mIServiceConnection
        return sd.getIServiceConnection();
    }
}

executor 为空,执行注释2所在的 else 分支,创建一个 ServiceDispatcher 实例。

2.2.2 ServiceDispatcher

LoadedApk.java

static final class ServiceDispatcher {
   
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
    // 一个 Binder 实体,是 binder 通信的核心
    @UnsupportedAppUsage
    private final ServiceConnection mConnection;  // 一个连接被封装到此
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P,
        trackingBug = 115609023)
    private final Context mContext;
    private final Handler mActivityThread;
    private final Executor mActivityExecutor;
    private final ServiceConnectionLeaked mLocation;
    private final int mFlags;

    ......
    // 关键内部类 InnerConnection 实现了 IServiceConnection.Stub 接口
    // 是为 Binder 服务端
    private static class InnerConnection extends IServiceConnection.Stub {
   
        @UnsupportedAppUsage
        final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

        InnerConnection(LoadedApk.ServiceDispatcher sd) {
   
        // 构造方法中,包含了 ServiceDispatcher
            mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
        }
        // 跨进程调用的 connected 方法,这里的 service 即为从远程服务端所在进程传递过来的
        // Binder 对象,接下来我们重点关注这个对象是怎么传递过来的
        public void connected(ComponentName name, IBinder service, boolean dead)
                throws RemoteException {
   
            LoadedApk.ServiceDispatcher sd = mDispatcher.get();
            if (sd != null) {
   
            // 进而调用 ServiceDispatcher 的 connected 方法
             // 进而最终调用到 ServiceDispatcher 中的 ServiceConnection 的
             // onServiceConnected 方法
                sd.connected(name, service, dead);
            }
        }
    }

    ......

    // ServiceDispatcher 构造方法
    @UnsupportedAppUsage
    ServiceDispatcher(ServiceConnection conn,
            Context context, Handler activityThread, int fl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值