Android bindService源码解析

看了好几篇bindService源码分析,感谢这篇写的最好,转载过来,以后方便学习.

原文地址:https://www.jianshu.com/p/1074af3eda78

bindService流程图:

 

在应用层点击bindService,会跳转到Context中的bindService,context的具体实现是ContextImpl,所以我们跟进去ContextImpl的bindService方法

 #ContextImpl
    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
                Process.myUserHandle());
    }

    ---

   private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            //1.重点 将 ServiceConnection对象转换成ServiceDispatcher.InnerConnection对象
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess(this);
            //2.重点 IPC操作,最终调用到ActivityManagerService的bindService方法
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

上述代码重点部分已经做了标注,我们首先看下 1处,1处调用到 mPackageInfo.getServiceDispatcher方法,将 ServiceConnection对象转换成ServiceDispatcher.InnerConnection对象,我们跟进去看下:

#LoadedApk
    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            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) {
                //1. 重点!
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
                if (map == null) {
                    map = new ArrayMap<>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            //2. 获得 ServiceDispatcher.InnerConnection实例
            return sd.getIServiceConnection();
        }
    }

上述方法中涉及到了 mServices,我们先来看下它的定义:

private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
        = new ArrayMap<>();

mServices就是一个ArrayMap,它存储了一个应用当前活动的 ServiceConnection和 ServiceDispatcher之间的映射关系。

可以看到在 1处创建了ServiceDispatcher对象,我们跟进去构造方法看下:

static final class ServiceDispatcher {

       private final ServiceDispatcher.InnerConnection mIServiceConnection;
       private final ServiceConnection mConnection;
       private final Context mContext;
       private final Handler mActivityThread;

       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的构造方法中,首先创建了InnerConnection对象,并赋值给它的成员变量mIServiceConnection,接着将ServiceConnection 对象conn赋值给成员变量mConnection ,将ActivityThread类中的Handler H mH赋值给mActivityThread 成员变量。

我们接着跟进去 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, boolean dead)
                throws RemoteException {
            LoadedApk.ServiceDispatcher sd = mDispatcher.get();
            if (sd != null) {
                sd.connected(name, service, dead);
            }
        }
    }

InnerConnection为ServiceDispatcher中的静态内部类,继承自 IServiceConnection.Stub,很显然,它是一个binder对象。类似于ApplicationThread,InnerConnection中的方法是运行在客户端进程中的Binder线程池中的,它主要参与Service绑定后ServiceConnection 中onServiceConnected方法的回调过程。可以看到在InnerConnection的构造方法中只是对外部传入的ServiceDispatcher对象通过WeakReference做了一次封装,使得InnerConnection对象持有ServiceDispatcher对象的引用,方便后续操作。

好了,我们回过头看下getServiceDispatcher方法的 2处,可以看到在 2处调用到ServiceDispatcher对象的getIServiceConnection()方法,我们跟进去看下:

    #ServiceDispatcher
    IServiceConnection getIServiceConnection() {
         return mIServiceConnection;
    }

方法中直接将mIServiceConnection return掉,mIServiceConnection不就是我们之前在ServiceDispatcher构造方法中创建的InnerConnection 对象嘛(Binder实例),是的没错!

我们回过头ContextImpl的bindServiceCommon方法,继续向下分析。2处为IPC操作,最终会调用到ActivityManagerService(AMS)的bindService方法,我们跟进去:

#ActivityManagerService
    public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String callingPackage,
            int userId) throws TransactionTooLargeException {
        enforceNotIsolatedCaller("bindService");

        // Refuse possible leaked file descriptors
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        if (callingPackage == null) {
            throw new IllegalArgumentException("callingPackage cannot be null");
        }

        synchronized(this) {
            //重点!
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, callingPackage, userId);
        }
    }

    ---

    #ActiveServices
    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {

        //通过applicationthread对象获得对应的ProcessRecord 
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        if (callerApp == null) {
            throw new SecurityException(
                    "Unable to find app for caller " + caller
                    + " (pid=" + Binder.getCallingPid()
                    + ") when binding service " + service);
        }

        ...  

       //创建 ServiceRecord对象并关联到新创建的ServiceLookupResult对象
       ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
        if (res == null) {
            return 0;
        }
        if (res.record == null) {
            return -1;
        }
        //通过res.record获取到创建的ServiceRecord对象并赋值给 ServiceRecord s变量
        ServiceRecord s = res.record;

        ...
         
           //调用ServiceRecord 的retrieveAppBindingLocked方法,
           //内部对bindings进行put操作,标志当前为bindService
           AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            //创建ConnectionRecord对象,将 IServiceConnection connection赋值给conn成员变量
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);

            IBinder binder = connection.asBinder();
            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                s.connections.put(binder, clist);
            }
            clist.add(c);
            b.connections.add(c);
            if (activity != null) {
                if (activity.connections == null) {
                    activity.connections = new HashSet<ConnectionRecord>();
                }
                activity.connections.add(c);
            }
            b.client.connections.add(c);
            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.hasAboveClient = true;
            }
            if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
                s.whitelistManager = true;
            }
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
            clist = mServiceConnections.get(binder);
            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();
                //1.重点!
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }

我们跟进去ActiveServices 中的 bringUpServiceLocked方法去看下:

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {

      ...

      if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    //1.重点
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }

      ...
  }

接着来到realStartServiceLocked方法:

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
        if (DEBUG_MU)
            Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
                    + ", ProcessRecord.uid = " + app.uid);
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked();

        //标记当前Service对象是否成功创建
        boolean created = false;
        try {
            if (LOG_SERVICE_START_STOP) {
                String nameTerm;
                int lastPeriod = r.shortName.lastIndexOf('.');
                nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
                EventLogTags.writeAmCreateService(
                        r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
            }
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            //1.重点 发起SystemServer进程到客户端进程的单向IPC操作,创建Service对象并调用其onCreate方法
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

                // Cleanup.
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                }

                // Retry.
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

        if (r.whitelistManager) {
            app.whitelistManager = true;
        }
 
        //2.若当前Service的启动方式为bindService,则执行Service的绑定操作
        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);

        //3.若当前Service的启动方式为startService,则新创建一个ServiceRecord.StartItem对象并添加到ServiceRecord对象 r的pendingStarts集合中
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }
       
        //4.若当前Service的启动方式为startService,则回调当前Service对象的 onStartCommand方法
        sendServiceArgsLocked(r, execInFg, true);

        if (r.delayed) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
            getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                        "Applying delayed stop (from start): " + r);
                stopServiceLocked(r);
            }
        }
    }

1处发起SystemServer进程到客户端进程的单向IPC操作,创建Service对象并调用其onCreate方法,上节课startService方式的时候我们已经分析过了,这里就不再赘述了。由于当前Service的启动方式为bindService,所以3处if条件不满足,导致ServiceRecord r的pendingStarts集合为empty,之后4处调用到sendServiceArgsLocked方法,在 sendServiceArgsLocked方法内部获取到pendingStarts.size()为0直接return掉了,至此当前Service对象的 onStartCommand方法并不会被回调。这也就解释了我们通过bindService的方式启动Service,onStartCommand方法并不会被回调的原因。好了,我们现在的重点放在 2处的 requestServiceBindingsLocked方法:

   private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
            throws TransactionTooLargeException {
        for (int i=r.bindings.size()-1; i>=0; i--) {
            IntentBindRecord ibr = r.bindings.valueAt(i);
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }

这里我同样要解释一下,当我们通过bindService的方式启动Service时,会对ServiceRecord r.bindings集合进行put操作,put操作的位置我们上述代码中有提及到,不记得的小伙伴可以回过头看下。这样子就导致r.bindings.size()不为0,会调用到for循环中的 requestServiceBindingLocked方法,而当我们通过startService的方式启动Service时,r.bindings.size()为0,for循环条件不满足直接退出。这也就解释了我们通过StartService的方式启动Service时,Service的onBind方法不会回调的原因。
好了,我们跟进去requestServiceBindingLocked方法:

 

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        if (r.app == null || r.app.thread == null) {
            // If service is not currently running, can't yet bind.
            return false;
        }
        if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
                + " rebind=" + rebind);
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);

                //重点!该操作为SystemServer进程到客户端进程的单向IPC操作,
                //最终会调用到ApplicationThread的scheduleBindService方法
                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.
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                throw e;
            } catch (RemoteException e) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                return false;
            }
        }
        return true;
    }

 在ApplicationThread的scheduleBindService方法中发送了一条BIND_SERVICE的Message,最终会调用ActivityThread类的handleBindService方法,我们跟进去看下:

private void handleBindService(BindServiceData data) {
        //1.获取到当前Service对象
        Service s = mServices.get(data.token);
        if (DEBUG_SERVICE)
            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        //2.回调当前Service对象的onBind方法
                        IBinder binder = s.onBind(data.intent);
                        //3.重点 IPC 操作,最终调用到AMS的publishService方法
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

可以看到 2处回调了当前Service对象的onBind方法,接着看下3处,我们跟进去AMS的publishService方法:

 #ActivityManagerService
    public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException("Invalid service token");
            }
            //重点!
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }

    ---

    #ActiveServices
    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
                  try {
                          //重点!IPC操作,最终会调用到InnerConnection 对象的connected方法,该方法运行在客户端的binder线程池中
                          c.conn.connected(r.name, service, false);
                      } catch (Exception e) {
                          Slog.w(TAG, "Failure sending service " + r.name +
                                " to connection " + c.conn.asBinder() +
                                " (in " + c.binding.client.processName + ")", e);
                      }
    }

我们看到在 ActiveServices的publishServiceLocked方法中发起了IPC操作,最终会调用到InnerConnection 对象的connected方法,该方法运行在客户端的binder线程池中,我们跟过去看下:

   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, boolean dead)
                throws RemoteException {           
            LoadedApk.ServiceDispatcher sd = mDispatcher.get();
            if (sd != null) {
                //重点 这里传过来的dead为false
                sd.connected(name, service, dead);
            }
        }
    }

可以看到在InnerConnection 对象的connected方法中调用到ServiceDispatcher 的connected方法,我们跟进去:

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

我们刚有讲过,在ServiceDispatcher的构造方法中,将ActivityThread类中的Handler H mH赋值给mActivityThread 成员变量,所以这里调用到mH的post方法切换到主线程,我们跟进去RunConnection对象的run方法:

      private final class RunConnection implements Runnable {
            RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
                mName = name;
                mService = service;
                mCommand = command;
                mDead = dead;
            }

            public void run() {
                //这里传入的mCommand 为0,会调用doConnected方法
                if (mCommand == 0) {
                    doConnected(mName, mService, mDead);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }

            final ComponentName mName;
            final IBinder mService;
            final int mCommand;
            final boolean mDead;
        }

我们接着跟进去doConnected方法看下:

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

            synchronized (this) {
                if (mForgotten) {
                    // We unbound before receiving the connection; ignore
                    // any connection received.
                    return;
                }
                old = mActiveConnections.get(name);
                if (old != null && old.binder == service) {
                    // Huh, already have this one.  Oh well!
                    return;
                }

                if (service != null) {
                    // A new service is being connected... set it all up.
                    info = new ConnectionInfo();
                    info.binder = service;
                    info.deathMonitor = new DeathMonitor(name, service);
                    try {
                        service.linkToDeath(info.deathMonitor, 0);
                        mActiveConnections.put(name, info);
                    } catch (RemoteException e) {
                        // This service was dead before we got it...  just
                        // don't do anything with it.
                        mActiveConnections.remove(name);
                        return;
                    }

                } else {
                    // The named service is being disconnected... clean up.
                    mActiveConnections.remove(name);
                }

                if (old != null) {
                    old.binder.unlinkToDeath(old.deathMonitor, 0);
                }
            }

            // If there was an old service, it is now disconnected.
            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
            if (dead) {
                mConnection.onBindingDied(name);
            }
            // If there is a new service, it is now connected.
            if (service != null) {
                //重点!!!
                mConnection.onServiceConnected(name, service);
            }
        }

可以看到在doConnected方法的最后调用到了ServiceConnection的onServiceConnected方法。

至此,Service的启动方式之bindService方式的源码分析就结束了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值