美文网首页
Android源码阅读之Service启动(二)

Android源码阅读之Service启动(二)

作者: 十蛋stan | 来源:发表于2018-12-22 20:36 被阅读5次

这篇主要讲BindService的主要逻辑 Api-27

Service的一些特性:
1.多个客户端可以绑定同一个服务

bindservice的入口为ContextImpl.bindService(Intent service, ServiceConnection conn, int flags);
然后ContextImpl.bindServiceCommon().
bindService和startService使用区别在于启动着是有渠道持有Service的渠道的,这个渠道就是IServiceConnection

ContextImpl:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) {
    //
    IServiceConnection sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
    //2拒绝隐式Intent
    validateServiceIntent(service);
    try {
            ...
            //3.调用服务端bindService
            int res = ActivityManager.getService().bindService(..., sd, ...);
            ...
    }
}

在bindServiceCommon这个方法里先是根据conn去获得IServiceConnection,然后校验隐式Intent,最后调用服务端AMS去bindService()
服务端:

ActivityManagerService:
    public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String callingPackage,
            int userId) throws TransactionTooLargeException {
            ...
            synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, callingPackage, userId);
            }
            ...
    }
    

这里的mServices就是AMS中用于管理Service启动的ActiveServices

ActiveServices:

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {
        ...
        //1.获得要启动的Service信息
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
        ...
        ServiceRecord s = res.record;
        ...
        //2.得到AppBindRecord,AppBindRecord描述的作用是连接Service和他的绑定者(IntentBindRecord)
        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
        ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent);
        //3.启动Service
        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false, permissionsReviewRequired) != null) {
                return 0;
            }
        }
        ...
        if (s.app != null && b.intent.received) {
          //Service已经运行, 我们可以立即发布connection.
          try {
              c.conn.connected(s.name, b.intent.binder, false);
          } catch (Exception e) {
              ...
          }
          //4.如果是第一次连接并且被要求rebind
          if (b.intent.apps.size() == 1 && b.intent.doRebind) {
              requestServiceBindingLocked(s, b.intent, callerFg, true);
          }
        } else if (!b.intent.requested) {
          //5.
          requestServiceBindingLocked(s, b.intent, callerFg, false);
        }
    }

在这个方法里,首先通过retrieveServiceLocked(正常启动后返回null,只有异常返回非null)获得将要启动的Service信息,然后去找AppBindRecord,接着如果有Context.BIND_AUTO_CREATE,那么就调用bringUpServiceLocked(),启动完Service后(异步)就调用c.conn.connected()去绑定
我们回到ActiveServices.bindServiceLocked()方法里.如果已经绑定过Service就调用c.conn.connected(),否则就requestServiceBindingLocked().

ActiveServices:
  private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) {
    ...
    r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.repProcState);
    ...
    return true;
  }

这里开始回到客户端了,直接看ApplicationThread.scheduleBindService();

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

    case BIND_SERVICE:
       handleBindService((BindServiceData)msg.obj);
       break;

这里进入ActivityThread.handleBindService()方法

  private void handleBindService(BindServiceData data) {
        //1.首先获得之前bringUpServiceLocked通过启动的Service
        Service s = mServices.get(data.token);
        if (s != null) {
          try {
            if (!data.rebind) {
              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);
            }
          }
        }
        ...
    }

第一次bindService的话data.rebind是false,首先通过Service.onBind()返回一个IBinder,然后把这个IBinder交给服务端AMS的publishService方法()

ActivityManagerService:
    public void publishService(IBinder token, Intent intent, IBinder service) {
        ...
        synchronized(this) {
            ...
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }

交给ActiveServices的publishServiceLocked()方法

ActiveServices:
  void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    ...
    Intent.FilterComparison filter = new Intent.FilterComparison(intent);
    IntentBindRecord b = r.bindings.get(filter);
    if (b != null && !b.received) {
      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++) {
          ...
          try {
            ...//过滤不需要的ConnectionRecord
            c.conn.connected(r.name, service, false);
          }
        }
      }
    }
  }

这个方法里又看见c.conn.connected(r.name, service, false)了.
这里c是ConnectionRecord, c.conn是IServiceConnection,那么c.conn.connected()就是去调用IServiceConnection的connected(),这里的IServiceConnection实现类是InnerConnection,之前ContextImpl.bindServiceCommon的时候会通过mPackageInfo.getServiceDispatcher()去获得IServiceConnection

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) {
                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);
            }
            return sd.getIServiceConnection();
        }
    }

最终return sd.getIServiceConnection()返回的是mIServiceConnection

LoadedApk.ServiceDispatcher:
        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的构造函数里mIServiceConnection就是InnerConnection.
回到c.conn.connected()这个方法,可以看出其实就是去调InnerConnection的connected()方法

        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的connected方法又去调ServiceDispatcher的connected方法,最终调doConnected方法

ServiceDispatcher:
        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);
            }
        }

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

            synchronized (this) {
                ...
                //1.绑定过,返回
                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);
            }
        }

c.conn.connected(s.name, b.intent.binder, false);
doConnected的3个入参(ComponentName name, IBinder service, boolean dead)

  • ComponentName name : ServiceRecord.name也就是启动Service的Intent的ComponentName
  • IBinder service : b.intent.binder也就是AppBindRecord.IntentBindRecord.IBinder,IntentBindRecord的binder.这个值其实就是Service.onBind()返回的IBinder.
  • boolean dead:传的是false
    这里先判断该Service是否已经被绑定过,没有就增加一个死亡监听,然后调用ServiceConnection.onServiceConnected()

至此,Service的bind过程就分析完毕了.

相关文章

网友评论

      本文标题:Android源码阅读之Service启动(二)

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