【Android源码】Service的绑定过程

作者: 指间沙似流年 | 来源:发表于2017-07-04 09:14 被阅读143次

    前篇:Service的启动过程

    刚开始的过程和startService类似:

    @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) {
       IServiceConnection sd;
       if (conn == null) {
           throw new IllegalArgumentException("connection is null");
       }
       if (mPackageInfo != null) {
           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);
           int res = ActivityManagerNative.getDefault().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();
       }
    }
    

    bindServiceCommon主要完成了两件事情:

    1. 通过mPackageInfo.getServiceDispatcherServiceConnection转化成了ServiceDispatcher.InnerConnection对象,为什么需要转换呢?

      这是因为服务的绑定有可能是跨进程的,所以ServiceConnection必须借助Binder机制才能让服务器来回调自己的方法,而InnerConnection正好实现了IServiceConnection.Stub,转化成了Binder对象。

    2. 完成绑定操作。

      ActivityManagerService.bindService
      -> ActiveServices.bindServiceLocked
      -> ActiveServices.bringUpServiceLocked
      -> ActiveServices.realStartServiceLocked
      

      同样的和启动过程类似,都是通过ApplicationThread来创建Service的实例,并执行onCreate方法。

    之后会调用requestServiceBindingsLocked方法来绑定Service。

    ActiveServices.requestServiceBindingsLocked
    -> ActiveServices.requestServiceBindingLocked
    -> ApplicaitonThread.scheduleBindService
    

    同样的是通过Handler来发送BIND_SERVICE消息

     case BIND_SERVICE:
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
         handleBindService((BindServiceData)msg.obj);
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         break;
         
    private void handleBindService(BindServiceData data) {
       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) {
                       IBinder binder = s.onBind(data.intent);
                       ActivityManagerNative.getDefault().publishService(
                               data.token, data.intent, binder);
                   } else {
                       s.onRebind(data.intent);
                       ActivityManagerNative.getDefault().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);
               }
           }
       }
    }     
    

    这个时候通过s.onBind(data.intent)就将Service绑定起来了。

    那么客户端是如何知道已经成功连接到Service了呢?
    这个时候就要调用onServiceConnected方法,这个过程就由publishService来完成。

    ActivityManagerNative.getDefault().publishService(
                                    data.token, data.intent, binder);
                                    
    -> ActivityManagerService.publishService  
    -> ActiveServices.publishServiceLocked
    

    publishServiceLocked中核心就一句c.conn.connected(r.name, service)

    其中c.conn就是一开始将ServiceConnection转化成的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);
          }
      }
    }
    // LoadedApk.java
    public void connected(ComponentName name, IBinder service) {
      if (mActivityThread != null) {
          mActivityThread.post(new RunConnection(name, service, 0));
      } else {
          doConnected(name, service);
      }
    }
    

    由代码可以知道mActivityThread是一个Handler,其实就是ActivityThread中的H,是不可能为空的,所以必定会调用post方法。

    private final class RunConnection implements Runnable {
      RunConnection(ComponentName name, IBinder service, int command) {
          mName = name;
          mService = service;
          mCommand = command;
      }
    
      public void run() {
          if (mCommand == 0) {
              doConnected(mName, mService);
          } else if (mCommand == 1) {
              doDeath(mName, mService);
          }
      }
    
      final ComponentName mName;
      final IBinder mService;
      final int mCommand;
    }
    
    public void doConnected(ComponentName name, IBinder service) {
      ServiceDispatcher.ConnectionInfo old;
      ServiceDispatcher.ConnectionInfo info;
    
      // If there was an old service, it is not disconnected.
      if (old != null) {
          mConnection.onServiceDisconnected(name);
      }
      // If there is a new service, it is now connected.
      if (service != null) {
          mConnection.onServiceConnected(name, service);
      }
    }
    

    由于mCommand传的值为0,所以调用的是doConnected方法,这个时候很方便的调用到了onServiceConnected

    至此,Service的绑定过程就完全分析结束了。

    相关文章

      网友评论

        本文标题:【Android源码】Service的绑定过程

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