bind Service细节

1,071 阅读6分钟

看完bindService,记得看Activity bindService后销毁及unbindService 记录

public boolean bindService(Intent service, ServiceConnection conn,
        int flags)

方法参数

  1. (ConnectionService实例conn、Intent囊括callerActivity、目标Service信息)
  2. conn保存到ServiceDispatcher实例sd中

bindService在ContextImpl类中。主要逻辑交由bindServiceCommon处理

//ContextImpl.java
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
        UserHandle user) {
    IServiceConnection sd;
    if (mPackageInfo != null) {
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                mMainThread.getHandler(), flags);
    } 
    try {
        IBinder token = getActivityToken();
        ...
        int res = ActivityManagerNative.getDefault().bindService(
            mMainThread.getApplicationThread(), getActivityToken(), service,
            service.resolveTypeIfNeeded(getContentResolver()),
            sd, flags, getOpPackageName(), user.getIdentifier());
        ...
        return res != 0;
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}

看下getServiceDispatcher,逻辑较为简单,主要是将Context, <ServiceConnection, ServiceDispatcher>键值对做保存。其中主要看下ServiceDispatcher对象的创建。

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
        Context context, Handler handler, int flags) {
    synchronized (mServices) {
        LoadedApk.ServiceDispatcher sd = null;
        //ArrayMap< Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> >
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
        if (map != null) {
            sd = map.get(c);
        }
        if (sd == null) {
        
            //构建ServiceDispatcher对象
            sd = new ServiceDispatcher(c, context, handler, flags);
            if (map == null) {
                map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                mServices.put(context, map);
            }
            map.put(c, sd);
        } else {
            sd.validate(context, handler);
        }
        return sd.getIServiceConnection();
    }
}
1 ServiceDispatcher
//ContextImpl中的OuterContext值为目标Service对象

ServiceDispatcher(ServiceConnection conn,
                Context context, Handler activityThread, int flags) {
            mIServiceConnection = new InnerConnection(this);
            mConnection = conn;
            mContext = context;
            mActivityThread = activityThread;
            mLocation = new ServiceConnectionLeaked(null);
            mLocation.fillInStackTrace();
            mFlags = flags;
}

ServiceDispatcher中Context(实际是一个Service对象)和Handler的组合来确定一个serviceDispatcher, 见ServiceDispatcher#invalidate

void validate(Context context, Handler activityThread) {
    if (mContext != context) {
        throw new RuntimeException(
            "ServiceConnection " + mConnection +
            " registered with differing Context (was " +
            mContext + " now " + context + ")");
    }
    if (mActivityThread != activityThread) {
        throw new RuntimeException(
            "ServiceConnection " + mConnection +
            " registered with differing handler (was " +
            mActivityThread + " now " + activityThread + ")");
    }
}

ServiceDispatcher对象保存了bindService传入的ServiceConnection对象, 后续还会用到。

bindService经AMS调用ActiveService#bindServiceLocked

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags,
        String callingPackage, int userId) throws TransactionTooLargeException {
  
    ...
    ActivityRecord activity = null;
    if (token != null) {// ActivityToken
        activity = ActivityRecord.isInStackLocked(token);
        if (activity == null) {
            Slog.w(TAG, "Binding with unknown activity: " + token);
            return 0;
        }
    }

    int clientLabel = 0;
    PendingIntent clientIntent = null;

    if (callerApp.info.uid == Process.SYSTEM_UID) {
        //调用目标Service的为系统应用
        ...
    }

    ...

    //检索目标Servie
    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
    
    ...
    ServiceRecord s = res.record;

    final long origId = Binder.clearCallingIdentity();

    ...


        //xi add: record the binding relation bewteen a client app and current service
        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
        ConnectionRecord c = new ConnectionRecord(b, activity,
                connection, flags, clientLabel, clientIntent);

        IBinder binder = connection.asBinder(); // IServiceConnect

        //-------------  记录连接-------------------
        //Service records connection
        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
        if (clist == null) {
            clist = new ArrayList<ConnectionRecord>();
            s.connections.put(binder, clist);
        }
        clist.add(c);

        //client app records connection
        b.connections.add(c);

        //client activity records connection
        if (activity != null) {
            if (activity.connections == null) {
                activity.connections = new HashSet<ConnectionRecord>();
            }
            activity.connections.add(c);
        }

        b.client.connections.add(c);

      
        clist = mServiceConnections.get(binder); // binder type is IServiceConnection
        if (clist == null) {
            clist = new ArrayList<ConnectionRecord>();
            mServiceConnections.put(binder, clist);
        }
        clist.add(c);
        
        //----------------- 记录连接 -----------------

        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            
            //视目标Service是否运行中,决定是否启动目标Service
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
                return 0;
            }
        }

        ...

        if (s.app != null && b.intent.received) {// if b.intent.received == true
            // Service is already running, so we can immediately
            // publish the connection.
            try {
            
                //如果目标Service已经处在运行中,直接通知Caller Activity bindService连接成功
                c.conn.connected(s.name, b.intent.binder);
            } catch (Exception e) {
                ...
            }

            ...
        }

        ...

    } finally {
        Binder.restoreCallingIdentity(origId);
    }

    return 1;
}
2.TODO resolveService

(具体交给PMS)

3. 记录连接

类AppBindRecord (An association between a service and one of its client applications. )

ServiceRecord AppBindRecord ActivityRecord 都要记录 connection. 其中,

  • ServieRecord中包含 ArrayMap<IBinder, ArrayList> 服务端记录连接
  • AppBindRecord中包含 ArraySet 客户端记录连接
  • ActivityRecord中包含 HashSet 客户端具体Activity记录连接
4 如必要,bringUpServiceLocked启动目标Service
4.1 目标Service已经启动且处在运行中

发送args到Service。直接返回,后面流程不需要走。

if (r.app != null && r.app.thread != null) {//serviceRecord.app thread不为null, 说明Service已经启动且处于运行中
   sendServiceArgsLocked(r, execInFg, false);
   return null;
}
4.2 Service所属进程app、线程thread已经启动,但Service没启动。

调用realStartServiceLocked

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
    
    r.app = app;//暂且记录下app
    
    final boolean newService = app.services.add(r); //新Service否
    bumpServiceExecutingLocked(r, execInFg, "create");
    mAm.updateLruProcessLocked(app, false, null);  //与进程调度相关
    mAm.updateOomAdjLocked();

    boolean created = false;
    try {
        ...
        //请求创建Service
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);

        created = true;
    } catch (DeadObjectException e) {
        ...
    } finally {
        if (!created) {
            //Service创建不成功
            // Retry.
            ...
        }
    }

    //请求绑定Service,调用Service onBind回调方法
    requestServiceBindingsLocked(r, execInFg);

    //向Service发送args
    sendServiceArgsLocked(r, execInFg, true);

    if (r.delayed) {// 处理延时启动相关
        getServiceMap(r.userId).mDelayedStartList.remove(r);
        r.delayed = false;
    }

   
}
4.2.1 scheduleCreateService

scheduleCreateService位于ActivityThread内部类ApplicationThread,为IApplicationThread服务端实现, IApplicationThread用于AMS和client APP通信。所以,scheduleCreateService逻辑也很简单,向ActivityThread#H发送CREATE_SERVICE消息

public final void scheduleCreateService(IBinder token,
        ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
    updateProcessState(processState, false);
    CreateServiceData s = new CreateServiceData();
    s.token = token;
    s.info = info;
    s.compatInfo = compatInfo;

    sendMessage(H.CREATE_SERVICE, s);
}

H接到消息后调用handleCreateService

case CREATE_SERVICE:
    handleCreateService((CreateServiceData)msg.obj);
    break;
private void handleCreateService(CreateServiceData data) {
   
    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = (Service) cl.loadClass(data.info.name).newInstance();
    } catch (Exception e) {
        ...
    }

    try {
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service); //ContextImpl中outerContext是目标Service实例

        ...
        //调用service的attach方法
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManagerNative.getDefault());
        
        //调用service的onCreate方法
        service.onCreate();
        mServices.put(data.token, service);
        try {
    
            //Target Service正常启动,启动后做相关工作
            ActivityManagerNative.getDefault().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            // nothing to do.
        }
    } catch (Exception e) {
        ...
    }
}

可以看到handleCreateService方法中获取到ClassLoader实例,利用反射创建了目标Service实例,依次调用它的attach、onCreate方法。同时调用AMS#serviceDoneExecuting方法,执行Service正常启动后的逻辑,其中会移除消息SERVICE_TIMEOUT_MSG,否则系统会提示ANR。

4.2.2 requestServiceBindingsLocked
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
        boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    if (r.app == null || r.app.thread == null) {
        // serviceRecord中app thread为null,表示目标Service并未启动,所以不需要bind,直接return false
        return false;
    }
    if ((!i.requested || rebind) && i.apps.size() > 0) {
        try {
            ...
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                    r.app.repProcState);
    
            //更新一些状态量
            if (!rebind) {
                i.requested = true;
            }
            i.hasBound = true;
            i.doRebind = false;
        } catch (TransactionTooLargeException e) {
            // Keep the executeNesting count accurate.
            ...
        } catch (RemoteException e) {
            ...
        }
    }
    return true;
}

同样,scheduleBindService属于ActivityThread#ApplicationThread中方法,还是发送消息,

public final void scheduleBindService(IBinder token, Intent intent,
        boolean rebind, int processState) {
    updateProcessState(processState, false);
    BindServiceData s = new BindServiceData();
    s.token = token;
    s.intent = intent;
    s.rebind = rebind;
    sendMessage(H.BIND_SERVICE, s);
}

H接到消息,调用handleBindService

case BIND_SERVICE:
    handleBindService((BindServiceData)msg.obj);
    break;
private void handleBindService(BindServiceData data) {
    Service s = mServices.get(data.token);

    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            try {
                if (!data.rebind) {
                    //回调onBind方法
                    IBinder binder = s.onBind(data.intent);
                    ActivityManagerNative.getDefault().publishService(
                            data.token, data.intent, binder);
                } else {
                    //调用onRebind
                    s.onRebind(data.intent);
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
                ensureJitEnabled();
            } catch (RemoteException ex) {
            }
        } catch (Exception e) {
            ...
        }
    }
}

正常handleBindService方法中会去调用Service的onBind,返回目标Service中定义的自定义Binder对象binder,将binder传到AMS publishService方法中,再经过调用Activie#publishServiceLocked

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    final long origId = Binder.clearCallingIdentity();
    try {
        if (r != null) {
            if (b != null && !b.received) {
                ...
                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 {
                            //调用IConnectionService回调方法connected
                            c.conn.connected(r.name, service);
                        } catch (Exception e) {
                            ...
                        }
                    }
                }
            }

            serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
        }
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

这里变量c的类型为ConnectionRecord,c.conn类型为IServiceConnection,根据上下文知道,其服务端实现在LoadedApk#ServiceDispatcher#InnerConnection中

4.2.3 LoadedApk#ServiceDispatcher#InnerConnection
private static class InnerConnection extends IServiceConnection.Stub {
    final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

    InnerConnection(LoadedApk.ServiceDispatcher sd) {
        mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
    }

    public void connected(ComponentName name, IBinder service) throws RemoteException {
        LoadedApk.ServiceDispatcher sd = mDispatcher.get();
        if (sd != null) {
            sd.connected(name, service);
        }
    }
}

InnerConnection中connected方法调用了ServiceDispatcher中的同名方法

public void connected(ComponentName name, IBinder service) {
    if (mActivityThread != null) {
        mActivityThread.post(new RunConnection(name, service, 0));
    } else {
        doConnected(name, service);
    }
}

mActivityThread类型为Handler,为创建sd对象时传入。接着看下RunConnection

public void run() {
    if (mCommand == 0) {
        doConnected(mName, mService);
    } else if (mCommand == 1) {
        doDeath(mName, mService);
    }
}

mCommand传入为0,所以调用doConnected方法

4.2.4 doConnected
public void doConnected(ComponentName name, IBinder service) {
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;

    synchronized (this) {
        ...

        if (service != null) {
            // A new service is being connected... set it all up.
            mDied = false;
            info = new ConnectionInfo();
            info.binder = service;
            info.deathMonitor = new DeathMonitor(name, service);
            try {
                //目标Service接入死亡通知
                service.linkToDeath(info.deathMonitor, 0);
                
                //记录<ComponentName, IBinder>
                mActiveConnections.put(name, info);
            } catch (RemoteException e) {
                ...
            }

        } 
        ...
    }

    ...
    // If there is a new service, it is now connected.
    if (service != null) {
        mConnection.onServiceConnected(name, service);
    }
}

这里就到ServiceConnection#onServiceConnected方法。可以看到目标Service中的自定义Binder对象一路从publishServiceLocked中传递到onServiceConnected中,通过该IBinder对象 ,Caller Activity就能获取到目标Service对象,进而调用Service中的方法。

4.2.5 总结
a. Caller Activity调用bindService时,目标Service没有启动。需要创建目标Service;

b. 调用Service attachonCreate onBind方法

c. AMS调用publishService,调用IServiceConnect服务端,即LoadedApk#ServiceDispatcher#InnerConnection,调用ServiceConnection#onServiceConnected回调

d.如果Activity调用bindService时,目标Service已经启动,则不需调用Service attachonCreateonbind方法,直接调用ServiceConnection#onServiceConnected回调

5.Service所属进程app没有启动

通过AMS请求启动进程,Service存放到PendingService集合中,待启动

if (app == null) {// service所在进程没有启动,那么启动该进程
    if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
            "service", r.name, false, isolated, false)) == null) {
        String msg = "Unable to launch app "
                + r.appInfo.packageName + "/"
                + r.appInfo.uid + " for service "
                + r.intent.getIntent() + ": process is bad";
        //启动进程失败,关闭Service
        bringDownServiceLocked(r);
        return msg;
    }
    ...
}

if (!mPendingServices.contains(r)) {//存放Service,待启动
    mPendingServices.add(r);
}

在进程启动过程中,attachApplicationLocked会去检测mPendingServices.size()不为0, 表明有需要启动的服务。接着调用realStartServiceLocked启动目标Service。

boolean attachApplicationLocked(ProcessRecord proc, String processName)
        throws RemoteException {
    boolean didSomething = false;
    // Collect any services that are waiting for this process to come up.
    if (mPendingServices.size() > 0) {//  <----------
        ServiceRecord sr = null;
        try {
            for (int i=0; i<mPendingServices.size(); i++) {
                sr = mPendingServices.get(i);
                ...

                mPendingServices.remove(i);
                i--;
                proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
                        mAm.mProcessStats);
                                                     
                //启动目标Service                                   
                realStartServiceLocked(sr, proc, sr.createdFromFg);
                didSomething = true;
            }
        } catch (RemoteException e) {
            ...
        }
    }