Android中Service在新进程中的启动流程2

       

目录

1、Service在客户端的启动入口

2、Service启动在AMS的处理

3、Service在新进程中的启动

4、Service与AMS的关系再续


        上一篇文章中我们了解了Service在新进程中启动的大致流程,同时认识了与客户端进程交互的接口IApplicationThread以及与AMS交互的接口IActivityManager,客户端进程与AMS则借助于Binder驱动实现了二者之间的通信,这一篇文章我们将深入源码分析startService是如何一步步启动新服务的,源码同样基于Android2.3.7。

        首先放上上一篇的流程概览图,方便源码分析。

1、Service在客户端的启动入口

        该步骤对应流程图中的第一步,通过调用Context.startService启动服务,该动作最终会走到ContextImpl的startService函数中,代码如下:

//frameworks\base\core\java\android\app\Contextlmpl.java@Overridepublic ComponentName startService(Intent service) {try {ComponentName cn = ActivityManagerNative.getDefault().startService(mMainThread.getApplicationThread(), service,service.resolveTypeIfNeeded(getContentResolver()));if (cn != null && cn.getPackageName().equals("!")) {throw new SecurityException("Not allowed to start service " + service+ " without permission " + cn.getClassName());}return cn;} catch (RemoteException e) {return null;}}

        通过调用ActivityManagerNative.getDefault()来启动服务,ActivityManagerNative.getDefault()返回的是AMS的一个代理对象ActivityManagerProxy,上一篇我们说过ActivityManagerProxy实现了IActivityManager接口,这里通过该代理把请求转发到AMS去,代码如下:

//frameworks\base\core\java\android\app\ActivityManagerNative.java
class ActivityManagerProxy implements IActivityManager
{public ActivityManagerProxy(IBinder remote){mRemote = remote;}public IBinder asBinder(){return mRemote;}//...//启动服务public ComponentName startService(IApplicationThread caller, Intent service,String resolvedType) throws RemoteException{Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller != null ? caller.asBinder() : null);service.writeToParcel(data, 0);data.writeString(resolvedType);mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);reply.readException();ComponentName res = ComponentName.readFromParcel(reply);data.recycle();reply.recycle();return res;}//停止服务public int stopService(IApplicationThread caller, Intent service,String resolvedType) throws RemoteException{Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller != null ? caller.asBinder() : null);service.writeToParcel(data, 0);data.writeString(resolvedType);mRemote.transact(STOP_SERVICE_TRANSACTION, data, reply, 0);reply.readException();int res = reply.readInt();reply.recycle();data.recycle();return res;}public boolean stopServiceToken(ComponentName className, IBinder token,int startId) throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);ComponentName.writeToParcel(className, data);data.writeStrongBinder(token);data.writeInt(startId);mRemote.transact(STOP_SERVICE_TOKEN_TRANSACTION, data, reply, 0);reply.readException();boolean res = reply.readInt() != 0;data.recycle();reply.recycle();return res;}public void setServiceForeground(ComponentName className, IBinder token,int id, Notification notification, boolean removeNotification) throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);ComponentName.writeToParcel(className, data);data.writeStrongBinder(token);data.writeInt(id);if (notification != null) {data.writeInt(1);notification.writeToParcel(data, 0);} else {data.writeInt(0);}data.writeInt(removeNotification ? 1 : 0);mRemote.transact(SET_SERVICE_FOREGROUND_TRANSACTION, data, reply, 0);reply.readException();data.recycle();reply.recycle();}//绑定服务public int bindService(IApplicationThread caller, IBinder token,Intent service, String resolvedType, IServiceConnection connection,int flags) throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller != null ? caller.asBinder() : null);data.writeStrongBinder(token);service.writeToParcel(data, 0);data.writeString(resolvedType);data.writeStrongBinder(connection.asBinder());data.writeInt(flags);mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);reply.readException();int res = reply.readInt();data.recycle();reply.recycle();return res;}//解绑服务public boolean unbindService(IServiceConnection connection) throws RemoteException{Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(connection.asBinder());mRemote.transact(UNBIND_SERVICE_TRANSACTION, data, reply, 0);reply.readException();boolean res = reply.readInt() != 0;data.recycle();reply.recycle();return res;}public void publishService(IBinder token,Intent intent, IBinder service) throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(token);intent.writeToParcel(data, 0);data.writeStrongBinder(service);mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);reply.readException();data.recycle();reply.recycle();}    //...
}

         这里列举了与服务相关的操作,我们关注启动服务mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0),mRemote代表了远程AMS对象,它会把请求发送给Binder驱动,然后由Binder驱动负责把请求转发到AMS去,参数caller代表了源进程即发起请求的进程,service代表了我们要启动的服务。

        以上动作都发生在源进程,下面进入AMS服务侧的系统进程了。

        接收到startService动作的是ActivityManagerNative,根据标识START_SERVICE_TRANSACTION回调到以下代码:

//frameworks\base\core\java\android\app\ActivityManagerNative.java
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{/*** Cast a Binder object into an activity manager interface, generating* a proxy if needed.*/static public IActivityManager asInterface(IBinder obj){if (obj == null) {return null;}IActivityManager in =(IActivityManager)obj.queryLocalInterface(descriptor);if (in != null) {return in;}return new ActivityManagerProxy(obj);}/*** Retrieve the system's default/global activity manager.*/static public IActivityManager getDefault(){if (gDefault != null) {//if (Config.LOGV) Log.v(//    "ActivityManager", "returning cur default = " + gDefault);return gDefault;}IBinder b = ServiceManager.getService("activity");if (Config.LOGV) Log.v("ActivityManager", "default service binder = " + b);gDefault = asInterface(b);if (Config.LOGV) Log.v("ActivityManager", "default service = " + gDefault);return gDefault;}//...public ActivityManagerNative(){attachInterface(this, descriptor);}public boolean onTransact(int code, Parcel data, Parcel reply, int flags)throws RemoteException {switch (code) {//...//启动服务case START_SERVICE_TRANSACTION: {data.enforceInterface(IActivityManager.descriptor);IBinder b = data.readStrongBinder();IApplicationThread app = ApplicationThreadNative.asInterface(b);Intent service = Intent.CREATOR.createFromParcel(data);String resolvedType = data.readString();ComponentName cn = startService(app, service, resolvedType);reply.writeNoException();ComponentName.writeToParcel(cn, reply);return true;}case STOP_SERVICE_TRANSACTION: {data.enforceInterface(IActivityManager.descriptor);IBinder b = data.readStrongBinder();IApplicationThread app = ApplicationThreadNative.asInterface(b);Intent service = Intent.CREATOR.createFromParcel(data);String resolvedType = data.readString();int res = stopService(app, service, resolvedType);reply.writeNoException();reply.writeInt(res);return true;}case STOP_SERVICE_TOKEN_TRANSACTION: {data.enforceInterface(IActivityManager.descriptor);ComponentName className = ComponentName.readFromParcel(data);IBinder token = data.readStrongBinder();int startId = data.readInt();boolean res = stopServiceToken(className, token, startId);reply.writeNoException();reply.writeInt(res ? 1 : 0);return true;}case SET_SERVICE_FOREGROUND_TRANSACTION: {data.enforceInterface(IActivityManager.descriptor);ComponentName className = ComponentName.readFromParcel(data);IBinder token = data.readStrongBinder();int id = data.readInt();Notification notification = null;if (data.readInt() != 0) {notification = Notification.CREATOR.createFromParcel(data);}boolean removeNotification = data.readInt() != 0;setServiceForeground(className, token, id, notification, removeNotification);reply.writeNoException();return true;}case BIND_SERVICE_TRANSACTION: {data.enforceInterface(IActivityManager.descriptor);IBinder b = data.readStrongBinder();IApplicationThread app = ApplicationThreadNative.asInterface(b);IBinder token = data.readStrongBinder();Intent service = Intent.CREATOR.createFromParcel(data);String resolvedType = data.readString();b = data.readStrongBinder();int fl = data.readInt();IServiceConnection conn = IServiceConnection.Stub.asInterface(b);int res = bindService(app, token, service, resolvedType, conn, fl);reply.writeNoException();reply.writeInt(res);return true;}case UNBIND_SERVICE_TRANSACTION: {data.enforceInterface(IActivityManager.descriptor);IBinder b = data.readStrongBinder();IServiceConnection conn = IServiceConnection.Stub.asInterface(b);boolean res = unbindService(conn);reply.writeNoException();reply.writeInt(res ? 1 : 0);return true;}case PUBLISH_SERVICE_TRANSACTION: {data.enforceInterface(IActivityManager.descriptor);IBinder token = data.readStrongBinder();Intent intent = Intent.CREATOR.createFromParcel(data);IBinder service = data.readStrongBinder();publishService(token, intent, service);reply.writeNoException();return true;}case UNBIND_FINISHED_TRANSACTION: {data.enforceInterface(IActivityManager.descriptor);IBinder token = data.readStrongBinder();Intent intent = Intent.CREATOR.createFromParcel(data);boolean doRebind = data.readInt() != 0;unbindFinished(token, intent, doRebind);reply.writeNoException();return true;}//...}
}

        这里关注START_SERVICE_TRANSACTION分支的处理, 从binder中读出了IApplicationThread对象,这个对象代表了发起请求的源进程,取出service,该Intent代表了我们要启动的服务。接着调用startService(app, service, resolvedType),该函数的实现正是位于AMS中,接下来我们进入AMS分析它是如何启动服务的。

2、Service启动在AMS的处理

        现在我们进入到AMS的处理中,继续调用分析startService函数调用,代码如下:

    //frameworks\base\servicesljava\com\android\server\am\ActivityManagerService.javapublic ComponentName startService(IApplicationThread caller, Intent service,String resolvedType) {// Refuse possible leaked file descriptorsif (service != null && service.hasFileDescriptors() == true) {throw new IllegalArgumentException("File descriptors passed in Intent");}synchronized(this) {final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();ComponentName res = startServiceLocked(caller, service,resolvedType, callingPid, callingUid);Binder.restoreCallingIdentity(origId);return res;}}

        直接转发到函数startServiceLocked中,代码如下:

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid) {synchronized(this) {//...ServiceLookupResult res =retrieveServiceLocked(service, resolvedType, callingPid, callingUid);if (res == null) {return null;}if (res.record == null) {return new ComponentName("!", res.permission != null? res.permission : "private to package");}ServiceRecord r = res.record;int targetPermissionUid = checkGrantUriPermissionFromIntentLocked(callingUid, r.packageName, service);if (unscheduleServiceRestartLocked(r)) {if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);}r.startRequested = true;r.callStart = false;r.lastStartId++;if (r.lastStartId < 1) {r.lastStartId = 1;}r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId,service, targetPermissionUid));r.lastActivity = SystemClock.uptimeMillis();synchronized (r.stats.getBatteryStats()) {r.stats.startRunningLocked();}if (!bringUpServiceLocked(r, service.getFlags(), false)) {return new ComponentName("!", "Service process is bad");}return r.name;}}

         首先通过调用retrieveServiceLocked拿到对应的ServiceLookupResult对象,该对象包含了ServiceRecord对象,ServiceRecord则是解析参数service拿到的。

        接下来设置ServiceRecord的几个参数startRequested = true、callStart = false、lastStartId++。接着创建ServiceRecord.StartItem对象并放到ServiceRecord的pendingStarts成员变量中,代表了接下来有需要启动的Service。接着继续调用bringUpServiceLocked启动服务,代码如下:

    private final boolean bringUpServiceLocked(ServiceRecord r,int intentFlags, boolean whileRestarting) {//1if (r.app != null && r.app.thread != null) {sendServiceArgsLocked(r, false);return true;}//2if (!whileRestarting && r.restartDelay > 0) {// If waiting for a restart, then do nothing.return true;}// We are now bringing the service up, so no longer in the// restarting state.mRestartingServices.remove(r);//3final String appName = r.processName;ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);if (app != null && app.thread != null) {try {realStartServiceLocked(r, app);return true;} 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.}// Not running -- get it started, and enqueue this service record// to be executed when the app comes up.//4if (startProcessLocked(appName, r.appInfo, true, intentFlags,"service", r.name, false) == null) {bringDownServiceLocked(r, true);return false;}//5if (!mPendingServices.contains(r)) {mPendingServices.add(r);}return true;}

         函数参数中ServiceRecord就是我们要启动的Service对应的对象,whileRestarting为false,intentFlags则是与服务相关的一些参数。代码中我标记了5个地方,这里会一一说明:

  1. r.app != null && r.app.thread != null:这个代表了我们要启动的进程以及起来了,不需要再启动新进程了,所以接下来调用sendServiceArgsLocked执行服务的生命周期函数,函数返回。由于新进程还没有启动,所以不会进入该分支。
  2. !whileRestarting && r.restartDelay > 0:whileRestarting为false,但是restartDelay参数并没有设置。所以不会进入该分支。
  3. app != null && app.thread != null:代表新进程是否以及存在,明显不存在;所以也不会进入这里。
  4. startProcessLocked:由于新进程没有启动,所以调用startProcessLocked启动服务要运行在的进程。
  5. mPendingServices.add(r):把ServiceRecord对象加入到集合mPendingServices中,也就是说,当进程起来以后需要从集合mPendingServices中拿到需要运行的服务。

        第四点启动新进程会把需要运行服务的进程创建起来,接下来我们进入startProcessLocked,代码如下:

    final ProcessRecord startProcessLocked(String processName,ApplicationInfo info, boolean knownToBeDead, int intentFlags,String hostingType, ComponentName hostingName, boolean allowWhileBooting) {ProcessRecord app = getProcessRecordLocked(processName, info.uid);// We don't have to do anything more if:// (1) There is an existing application record; and// (2) The caller doesn't think it is dead, OR there is no thread//     object attached to it so we know it couldn't have crashed; and// (3) There is a pid assigned to it, so it is either starting or//     already running.//...if (app == null) {app = newProcessRecordLocked(null, info, processName);mProcessNames.put(processName, info.uid, app);} else {// If this is a new package in the process, add the package to the listapp.addPackage(info.packageName);}//...startProcessLocked(app, hostingType, hostingNameStr);return (app.pid != 0) ? app : null;}

        代码省略了一些相关的判断,如果需要创建新进程, 则会调用newProcessRecordLocked创建一个ProcessRecord对象用于记录新进程的一些信息。继续调用到startProcessLocked,代码如下:

    private final void startProcessLocked(ProcessRecord app,String hostingType, String hostingNameStr) {//...try {//1 设置一些启动参数int uid = app.info.uid;int[] gids = null;//...int debugFlags = 0;if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;}// Run the app in safe mode if its manifest requests so or the// system is booted in safe mode.if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||Zygote.systemInSafeMode == true) {debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;}if ("1".equals(SystemProperties.get("debug.checkjni"))) {debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;}if ("1".equals(SystemProperties.get("debug.assert"))) {debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;}//2 启动新进程,入口类为android.app.ActivityThreadint pid = Process.start("android.app.ActivityThread",mSimpleProcessManagement ? app.processName : null, uid, uid,gids, debugFlags, null);//...if (pid == 0 || pid == MY_PID) {// Processes are being emulated with threads.app.pid = MY_PID;app.removed = false;mStartingProcesses.add(app);} else if (pid > 0) {//3 发送了一个超时消息app.pid = pid;app.removed = false;synchronized (mPidsSelfLocked) {this.mPidsSelfLocked.put(pid, app);Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);msg.obj = app;mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);}} else {app.pid = 0;//...}} catch (RuntimeException e) {// XXX do better error recovery.app.pid = 0;Slog.e(TAG, "Failure starting process " + app.processName, e);}}

        该函数中有三个关键位置,接下来我们一一说明:

  1. 这里主要设置一些新进程的启动参数,比如uid、gids、debugFlags。
  2. 启动新进程,入口类为android.app.ActivityThread
  3. 新进程创建成功返回了,获得了进程id,也即是返回值pid ;同时还把ProcessRecord对象放入到集合mPidsSelfLocked中,然后发送了一个超时消息PROC_START_TIMEOUT_MSG。
  • mPidsSelfLocked:是AMS用来记录当前启动进程信息的集合。
  • PROC_START_TIMEOUT_MSG:则是新进程创建成功后发送的一个延时消息,AMS这里采取的策略是新进程必须在启动之后的一段时间内回调到AMS,此时会把消息该消息移除掉;如果新进程启动太久了,没有及时回调AMS则该消息会弹出ANR弹窗提醒用户。言下之意就是新进程启动太慢了,影响了用户体验,所以通过这种方式告知用户,用户可以选择继续等待或者杀死待启动的应用。

        新进程启动的入口类为android.app.ActivityThread,首先调用的是ActivityThread.main,接下来运行流程就到了客户端的MyService进程中了。

有关新进程如何启动,可以再写一遍文章分析,这里关注Service的启动流程,先简单跳过了。

3、Service在新进程中的启动

        新进程启动后的入口为android.app.ActivityThread.main,代码如下:

    //frameworks\base\core\java\android\app\ActivityThread.javapublic static final void main(String[] args) {SamplingProfilerIntegration.start();Process.setArgV0("<pre-initialized>");Looper.prepareMainLooper();if (sMainThreadHandler == null) {sMainThreadHandler = new Handler();}ActivityThread thread = new ActivityThread();thread.attach(false);if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}Looper.loop();if (Process.supportsProcesses()) {throw new RuntimeException("Main thread loop unexpectedly exited");}thread.detach();String name = (thread.mInitialApplication != null)? thread.mInitialApplication.getPackageName(): "<unknown>";Slog.i(TAG, "Main thread of " + name + " is now exiting");}

         通过Looper.prepareMainLooper()/Looper.loop();建立消息循环,这就是主线程消息循环建立的地方。同时创建了ActivityThread对象,该对象代表了客户端MyService进程,然后调用thread.attach(false),注意参数为false。

        创建ActivityThread对象的时候其实还创建了IApplicationThread对象。

//frameworks\base\core\java\android\app\ActivityThread.java
final ApplicationThread mAppThread = new ApplicationThread();

         该对象代表了客户端,AMS就是通过这个对象与客户端通信的。attach的实现如下:

    private final void attach(boolean system) {sThreadLocal.set(this);mSystemThread = system;if (!system) {//1 ViewRoot.addFirstDrawHandler(new Runnable() {public void run() {ensureJitEnabled();}});android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");RuntimeInit.setApplicationObject(mAppThread.asBinder());IActivityManager mgr = ActivityManagerNative.getDefault();try {mgr.attachApplication(mAppThread);} catch (RemoteException ex) {}} else {//2 // Don't set application object here -- if the system crashes,// we can't display an alert, we just want to die die die.android.ddm.DdmHandleAppName.setAppName("system_process");try {mInstrumentation = new Instrumentation();ContextImpl context = new ContextImpl();context.init(getSystemContext().mPackageInfo, null, this);Application app = Instrumentation.newApplication(Application.class, context);mAllApplications.add(app);mInitialApplication = app;app.onCreate();} catch (Exception e) {throw new RuntimeException("Unable to instantiate Application():" + e.toString(), e);}}ViewRoot.addConfigCallback(new ComponentCallbacks() {public void onConfigurationChanged(Configuration newConfig) {synchronized (mPackages) {// We need to apply this change to the resources// immediately, because upon returning the view// hierarchy will be informed about it.if (applyConfigurationToResourcesLocked(newConfig)) {// This actually changed the resources!  Tell// everyone about it.if (mPendingConfiguration == null ||mPendingConfiguration.isOtherSeqNewer(newConfig)) {mPendingConfiguration = newConfig;queueOrSendMessage(H.CONFIGURATION_CHANGED, newConfig);}}}}public void onLowMemory() {}});}

        这里说明以下两处:

  1. 参数system为false,所以会进入这个分支,然后调用attachApplication
  2. 这个分支表示system为true,代表了系统进程。

        由于system为false,所以流程走第一个分支,IActivityManager mgr = ActivityManagerNative.getDefault(),拿到AMS的代理,调用attachApplication;该函数调用会进入AMS侧,我们直接到AMS那边分析接下来的流程。

4、Service与AMS的关系再续

        进入AMS后,先调用attachApplication,代码如下:

    public final void attachApplication(IApplicationThread thread) {synchronized (this) {int callingPid = Binder.getCallingPid();final long origId = Binder.clearCallingIdentity();attachApplicationLocked(thread, callingPid);Binder.restoreCallingIdentity(origId);}}

        直接转发到函数 attachApplicationLocked,代码如下:

    private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {//1 找到ProcessRecord对象,还记得该对象是啥时候加到集合mPidsSelfLocked的吗ProcessRecord app;if (pid != MY_PID && pid >= 0) {synchronized (mPidsSelfLocked) {app = mPidsSelfLocked.get(pid);}} else if (mStartingProcesses.size() > 0) {app = mStartingProcesses.remove(0);app.setPid(pid);} else {app = null;}if (app == null) {//...return false;}//...String processName = app.processName;//...//2 设置ProcessRecord对象的一些参数app.thread = thread;app.curAdj = app.setAdj = -100;app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;app.forcingToForeground = null;app.foregroundServices = false;app.debugging = false;//3 移除延时消息mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);//...try {//...//4 执行dex优化ensurePackageDexOpt(app.instrumentationInfo != null? app.instrumentationInfo.packageName: app.info.packageName);if (app.instrumentationClass != null) {ensurePackageDexOpt(app.instrumentationClass.getPackageName());}//5 回调应用程序thread.bindApplication(processName, app.instrumentationInfo != null? app.instrumentationInfo : app.info, providers,app.instrumentationClass, app.instrumentationProfileFile,app.instrumentationArguments, app.instrumentationWatcher, testMode, isRestrictedBackupMode || !normalMode,mConfiguration, getCommonServicesLocked());updateLruProcessLocked(app, false, true);app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();} catch (Exception e) {//...return false;}//....boolean badApp = false;boolean didSomething = false;// 6 See if the top visible activity is waiting to run in this process...ActivityRecord hr = mMainStack.topRunningActivityLocked(null);if (hr != null && normalMode) {if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid&& processName.equals(hr.processName)) {try {if (mMainStack.realStartActivityLocked(hr, app, true, true)) {didSomething = true;}} catch (Exception e) {Slog.w(TAG, "Exception in new application when starting activity "+ hr.intent.getComponent().flattenToShortString(), e);badApp = true;}} else {mMainStack.ensureActivitiesVisibleLocked(hr, null, processName, 0);}}// 7 Find any services that should be running in this process...if (!badApp && mPendingServices.size() > 0) {ServiceRecord sr = null;try {for (int i=0; i<mPendingServices.size(); i++) {sr = mPendingServices.get(i);if (app.info.uid != sr.appInfo.uid|| !processName.equals(sr.processName)) {continue;}mPendingServices.remove(i);i--;realStartServiceLocked(sr, app);didSomething = true;}} catch (Exception e) {Slog.w(TAG, "Exception in new application when starting service "+ sr.shortName, e);badApp = true;}}// 8 Check if the next broadcast receiver is in this process...BroadcastRecord br = mPendingBroadcast;if (!badApp && br != null && br.curApp == app) {try {mPendingBroadcast = null;processCurBroadcastLocked(br, app);didSomething = true;} catch (Exception e) {Slog.w(TAG, "Exception in new application when starting receiver "+ br.curComponent.flattenToShortString(), e);badApp = true;logBroadcastReceiverDiscardLocked(br);finishReceiverLocked(br.receiver, br.resultCode, br.resultData,br.resultExtras, br.resultAbort, true);scheduleBroadcastsLocked();// We need to reset the state if we fails to start the receiver.br.state = BroadcastRecord.IDLE;}}//...return true;}

        代码中标记了一些关键的地方,下面一一说明:

  1. 找到ProcessRecord对象,主要是从mPidsSelfLocked集合中找到pid对应的ProcessRecord对象。
  2. 设置ProcessRecord对象的一些参数,其中最主要的是设置thread参数,该参数是IApplicationThread对象,代表了客户端;AMS就是通过这个对象与客户端通信的。
  3. 移除延时消息PROC_START_TIMEOUT_MSG,此时代表了新进程以及成功启动。
  4. 调用ensurePackageDexOpt执行dex优化,这里我们不关注。
  5. 调用bindApplication回调客户端,这里会调用到ActivityThread.handleBindApplication函数,然后执行Application的onCreate函数。从这里我们知道Application的onCreate运行于主线程中,所以我们在开发APP的时候最好只在里面做一些必要的初始化,否则会影响APP的启动速度。
  6. 此处是启动activity的,我们这里不关注。
  7. 启动service,这是我们需要关注的部分;还记得调用bringUpServiceLocked的时候mPendingServices集合加入了我们要启动的ServiceRecord对象吗?这里取出ServiceRecord对象,然后调用realStartServiceLocked继续启动服务。
  8. 广播处理,我们这里也不关注。

        realStartServiceLocked以ServiceRecord及ProcessRecord为参数,代码如下:

    private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app) throws RemoteException {//...r.app = app;r.restartTime = r.lastActivity = SystemClock.uptimeMillis();app.services.add(r);bumpServiceExecutingLocked(r, "create");updateLruProcessLocked(app, true, true);boolean created = false;try {//...//1 回调客户端app.thread.scheduleCreateService(r, r.serviceInfo);r.postNotification();created = true;} finally {if (!created) {app.services.remove(r);scheduleServiceRestartLocked(r, false);}}requestServiceBindingsLocked(r);//2设置一些参数if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {r.lastStartId++;if (r.lastStartId < 1) {r.lastStartId = 1;}r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId, null, -1));}//3 回调客户端onStartsendServiceArgsLocked(r, true);}

        scheduleCreateService将会回调到客户端,进入到ActivityThead.handleCreateService,而sendServiceArgsLocked将会回调客户端的onStartCommond方法。

        先来看看handleCreateService函数,代码如下:

    private final void handleCreateService(CreateServiceData data) {// If we are getting ready to gc after going to the background, well// we are back active so skip it.unscheduleGcIdler();LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo);Service service = null;try {//1java.lang.ClassLoader cl = packageInfo.getClassLoader();service = (Service) cl.loadClass(data.info.name).newInstance();} catch (Exception e) {//...}try {ContextImpl context = new ContextImpl();context.init(packageInfo, null, this);Application app = packageInfo.makeApplication(false, mInstrumentation);context.setOuterContext(service);service.attach(context, this, data.info.name, data.token, app,ActivityManagerNative.getDefault());//2service.onCreate();mServices.put(data.token, service);try {ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, 0, 0, 0);} catch (RemoteException e) {// nothing to do.}} catch (Exception e) {//...}}

         这里比较简单,首先loadClass加载了我们实现的服务类,然后调用服务的onCreate方法,嗯,终于看到了熟悉的onCreate了。

        好啦,感觉这篇有点长了,先不写了。

        这里只是回调到了服务的onCreate,我们知道在服务的onCreate里面执行耗时任务会导致ANR,下一篇我们将继续分析服务的生命周期调用是如何在AMS侧实现的、同时分析为何onCreate、onStartCommond执行耗时任务会导致ANR。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/68348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计网week1+2

计网 一.概念 1.什么是Internet 节点&#xff1a;主机及其运行的应用程序、路由器、交换机 边&#xff1a;通信链路&#xff0c;接入网链路主机连接到互联网的链路&#xff0c;光纤、网输电缆 协议&#xff1a;对等层的实体之间通信要遵守的标准&#xff0c;规定了语法、语义…

windows下部署安装 ELK,nginx,tomcat日志分析

1.安装包 如上就是elk- windows下部署需要用到的安装包 &#xff08;ps:注意版本需要对应&#xff0c;另外es7版本对应是 jdk8&#xff0c;若更高版本 请自行查询版本对应号&#xff09;。 下载地址&#xff1a; Past Releases of Elastic Stack Software | Elastic 此地址可…

docker安装MySQL8:docker离线安装MySQL、docker在线安装MySQL、MySQL镜像下载、MySQL配置、MySQL命令

一、镜像下载 1、在线下载 在一台能连外网的linux上执行docker镜像拉取命令 docker pull mysql:8.0.41 2、离线包下载 两种方式&#xff1a; 方式一&#xff1a; -&#xff09;在一台能连外网的linux上安装docker执行第一步的命令下载镜像 -&#xff09;导出 # 导出镜…

【AI论文】魔鬼在细节:关于在训练专用混合专家模型时实现负载均衡损失

摘要&#xff1a;本文重新审视了在训练混合专家&#xff08;Mixture-of-Experts, MoEs&#xff09;模型时负载均衡损失&#xff08;Load-Balancing Loss, LBL&#xff09;的实现。具体来说&#xff0c;MoEs的LBL定义为N_E乘以从1到N_E的所有专家i的频率f_i与门控得分平均值p_i的…

C语言编程笔记:文件处理的艺术

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文一、为什么要用文件二、文件的分…

OpenAI的真正对手?DeepSeek-R1如何用强化学习重构LLM能力边界——DeepSeek-R1论文精读

2025年1月20日&#xff0c;DeepSeek-R1 发布&#xff0c;并同步开源模型权重。截至目前&#xff0c;DeepSeek 发布的 iOS 应用甚至超越了 ChatGPT 的官方应用&#xff0c;直接登顶 AppStore。 DeepSeek-R1 一经发布&#xff0c;各种资讯已经铺天盖地&#xff0c;那就让我们一起…

Baklib如何重塑内容中台的智能化推荐系统实现个性化服务

内容概要 在数字内容日益丰富的今天&#xff0c;内容中台的智能化推荐系统显得尤为重要。它通过分析和处理海量的数据&#xff0c;为用户提供个性化的内容推荐&#xff0c;从而提升用户体验。在智能化推荐系统中&#xff0c;主要由以下几个部分构成&#xff1a; 部分主要功能…

从零推导线性回归:最小二乘法与梯度下降的数学原理

​ 欢迎来到我的主页&#xff1a;【Echo-Nie】 本篇文章收录于专栏【机器学习】 本文所有内容相关代码都可在以下仓库中找到&#xff1a; Github-MachineLearning 1 线性回归 1.1 什么是线性回归 线性回归是一种用来预测和分析数据之间关系的工具。它的核心思想是找到一条直…

【MySQL】 数据类型

欢迎拜访&#xff1a;雾里看山-CSDN博客 本篇主题&#xff1a;【MySQL】 数据类型 发布时间&#xff1a;2025.1.27 隶属专栏&#xff1a;MySQL 目录 数据类型分类数值类型tinyint类型数值越界测试结果说明 bit类型基本语法使用注意事项 小数类型float语法使用注意事项 decimal语…

数字人+展厅应用方案:开启全新沉浸式游览体验

随着人们生活质量的不断提升&#xff0c;对于美好体验的追求日益增长。在展厅展馆领域&#xff0c;传统的展示方式已难以满足大众日益多样化的需求。而通过将数字人与展厅进行深度结合&#xff0c;可以打造数字化、智能化新型展厅&#xff0c;不仅能提升展示效果&#xff0c;还…

RK3588平台开发系列讲解(ARM篇)ARM64底层中断处理

文章目录 一、异常级别二、异常分类2.1、同步异常2.2、异步异常三、中断向量表沉淀、分享、成长,让自己和他人都能有所收获!😄 一、异常级别 ARM64处理器确实定义了4个异常级别(Exception Levels, EL),分别是EL0到EL3。这些级别用于管理处理器的特权级别和权限,级别越高…

K8s运维管理平台 - xkube体验:功能较多

目录 简介Lic安装1、需要手动安装MySQL&#xff0c;**建库**2、启动命令3、[ERROR] GetNodeMetric Fail:the server is currently unable to handle the request (get nodes.metrics.k8s.io qfusion-1) 使用总结优点优化 补充1&#xff1a;layui、layuimini和beego的详细介绍1.…

无人机红外热成像:应急消防的“透视眼”

无人机红外热成像&#xff1a;应急消防的“透视眼” 亲爱的小伙伴们&#xff0c;每年一到夏天&#xff0c;应急消防的战士们就像上紧了发条的闹钟&#xff0c;时刻准备应对各种灾害。炎热天气让火灾隐患“蹭蹭”往上涨&#xff0c;南北各地还有防洪救灾、台风、泥石流等灾害轮…

14-6-3C++STL的list

&#xff08;一&#xff09;list的插入 1.list.insert(pos,elem);//在pos位置插入一个elem元素的拷贝&#xff0c;返回新数据的位置 #include <iostream> #include <list> using namespace std; int main() { list<int> lst; lst.push_back(10); l…

【Linux】 冯诺依曼体系与计算机系统架构全解

Linux相关知识点可以通过点击以下链接进行学习一起加油&#xff01;初识指令指令进阶权限管理yum包管理与vim编辑器GCC/G编译器make与Makefile自动化构建GDB调试器与Git版本控制工具Linux下进度条 冯诺依曼体系是现代计算机设计的基石&#xff0c;其统一存储和顺序执行理念推动…

【C++ 动态规划】1024. 视频拼接|1746

本文涉及知识点 C动态规划 LeetCode1024. 视频拼接 你将会获得一系列视频片段&#xff0c;这些片段来自于一项持续时长为 time 秒的体育赛事。这些片段可能有所重叠&#xff0c;也可能长度不一。 使用数组 clips 描述所有的视频片段&#xff0c;其中 clips[i] [starti, end…

EasyExcel写入和读取多个sheet

最近在工作中&#xff0c;作者频频接触到Excel处理&#xff0c;因此也对EasyExcel进行了一定的研究和学习&#xff0c;也曾困扰过如何处理多个sheet&#xff0c;因此此处分享给大家&#xff0c;希望能有所帮助 目录 1.依赖 2. Excel类 3.处理Excel读取和写入多个sheet 4. 执…

字节iOS面试经验分享:HTTP与网络编程

字节iOS面试经验分享&#xff1a;HTTP与网络编程 &#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 目录 字节iOS面试经验分享&#xff1a;HTT…

电力晶体管(GTR)全控性器件

电力晶体管&#xff08;Giant Transistor&#xff0c;GTR&#xff09;是一种全控性器件&#xff0c;以下是关于它的详细介绍&#xff1a;&#xff08;模电普通晶体管三极管进行对比学习&#xff09; 基本概念 GTR是一种耐高电压、大电流的双极结型晶体管&#xff08;BJT&am…

装饰SpringMVC的适配器实现响应自动包装

文章目录 1.common-tool-starter1.目录结构2.ResultWrapper.java 2.common-web-starter1.目录结构2.IgnoredResultWrapper.java 自定义注解&#xff0c;忽略对返回结果的自动包装3.ReturnValueHandlersDecorator.java 对适配器进行扩展的装饰器4.WebAutoConfiguration.java 将装…