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
    @Override
    public 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.java
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType) {
        // Refuse possible leaked file descriptors
        if (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) {
        //1
        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, false);
            return true;
        }

        //2
        if (!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);
        
        //3
        final 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.
        //4
        if (startProcessLocked(appName, r.appInfo, true, intentFlags,
                "service", r.name, false) == null) {
            bringDownServiceLocked(r, true);
            return false;
        }
        
        //5
        if (!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 list
            app.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.ActivityThread
            int 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.java
    public 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(new
                    LogPrinter(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 回调客户端onStart
        sendServiceArgsLocked(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 {
            //1
            java.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());
            //2
            service.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。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Three城市引擎地图插件Geo-3d

一、简介 基于Three开发&#xff0c;为Three 3D场景提供GIS能力和城市底座渲染能力。支持Web墨卡托、WGS84、GCJ02等坐标系&#xff0c;支持坐标转换&#xff0c;支持影像、地形、geojson建筑、道路&#xff0c;植被等渲染。支持自定义主题。 二、效果 三、代码 //插件初始化…

Ubuntu环境 nginx 源码 编译安装

ubuntu 终端 使用 wget 下载源码 sudo wget http://nginx.org/download/nginx-1.24.0.tar.gz解压刚下载的源码压缩包 nginx-1.24.0.tar.gz sudo tar -zxvf nginx-1.24.0.tar.gz 解压完成 产生 nginx-1.24.0 目录 进入该目录 cd ./nginx-1.24.0 目录下有一个可执行文件 con…

【深度学习】神经网络实战分类与回归任务

第一步 读取数据 ①导入torch import torch ②使用魔法命令&#xff0c;使它使得生成的图形直接嵌入到 Notebook 的单元格输出中&#xff0c;而不是弹出新的窗口来显示图形 %matplotlib inline③读取文件 from pathlib import Path import requestsDATA_PATHPath("dat…

60,【1】BUUCF web [RCTF2015]EasySQL1

先查看源码 1&#xff0c;changepwd&#xff08;修改密码&#xff09; <?php // 开启会话&#xff0c;以便使用会话变量 session_start();// 设置页面的内容类型为 HTML 并使用 UTF-8 编码 header("Content-Type: text/html; charsetUTF-8");// 引入配置文件&…

Chrome插件:图片缩放为头像(128*128)

前置条件&#xff1a; 安装有chrome谷歌浏览器的电脑 使用步骤&#xff1a; 1.打开chrome扩展插件 2.点击管理扩展程序 3.加载已解压的扩展程序 4.选择对应文件夹 5.成功后会出现一个扩展小程序 6.点击对应小程序 7.使用小程序 8.拖拽成功后会自动保存到下载 代码&#xf…

machine learning knn算法之使用KNN对鸢尾花数据集进行分类

通过导入必要的scikit-learn导入必要的库&#xff0c;加载给定的数据&#xff0c;划分测试集和训练集之后训练预测和评估即可 具体代码如下&#xff1a; import numpy as np from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split f…

电子应用设计方案102:智能家庭AI鱼缸系统设计

智能家庭 AI 鱼缸系统设计 一、引言 智能家庭 AI 鱼缸系统旨在为鱼类提供一个健康、舒适的生活环境&#xff0c;同时为用户提供便捷的管理和观赏体验。 二、系统概述 1. 系统目标 - 自动维持水质稳定&#xff0c;包括水温、酸碱度、硬度和溶氧量等关键指标。 - 智能投食&…

【C语言系列】深入理解指针(3)

深入理解指针&#xff08;3&#xff09; 一、字符指针变量二、数组指针变量2.1数组指针变量是什么&#xff1f;2.2数组指针变量怎么初始化&#xff1f; 三、二维数组传参的本质四、函数指针变量4.1函数指针变量的创建4.2函数指针变量的使用4.3两段有趣的代码4.4 typedef关键字 …

2024年度总结-CSDN

2024年CSDN年度总结 Author&#xff1a;OnceDay Date&#xff1a;2025年1月21日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 文章目录 2024年CSDN年度总结1. 整体回顾2…

Linux下php8安装phpredis扩展的方法

Linux下php8安装phpredis扩展的方法 下载redis扩展执行安装编辑php.ini文件重启php-fpmphpinfo 查看 下载redis扩展 前提是已经安装好redis服务了 php-redis下载地址 https://github.com/phpredis/phpredis 执行命令 git clone https://github.com/phpredis/phpredis.git执行…

我的2024年度历程回顾

一、自我介绍 这个是我的 个人主页 &#xff1a; zxctscl 从2023年到现在一些小成就 我主要分享的文章是C语言和C方面&#xff1a; 当然也有不少算法题&#xff1a; 二、年度回顾 在过去的一年里&#xff0c;也有不少收获&#xff1a; 在C编程语言的学习方面取得了显著…

AIGC专栏18——EasyAnimateV5.1版本详解 应用Qwen2 VL作为文本编码器,支持轨迹控制与相机镜头控制

AIGC专栏18——EasyAnimateV5.1版本详解 应用Qwen2 VL作为文本编码器&#xff0c;支持轨迹控制与相机镜头控制 学习前言相关地址汇总源码下载地址HF测试链接MS测试链接 测试效果Image to VideoText to Video轨迹控制镜头控制 EasyAnimate详解技术储备Qwen2 VLStable Diffusion …

YOLOv8改进,YOLOv8检测头融合DSConv(动态蛇形卷积),并添加小目标检测层(四头检测),适合目标检测、分割等

精确分割拓扑管状结构例如血管和道路,对各个领域至关重要,可确保下游任务的准确性和效率。然而,许多因素使任务变得复杂,包括细小脆弱的局部结构和复杂多变的全局形态。在这项工作中,注意到管状结构的特殊特征,并利用这一知识来引导 DSCNet 在三个阶段同时增强感知:特征…

U3D的.Net学习

Mono&#xff1a;这是 Unity 最初采用的方式&#xff0c;它将 C# 代码编译为中间语言 (IL)&#xff0c;然后在目标平台上使用虚拟机 (VM) 将其转换为本地机器码执行。 IL2CPP&#xff1a;这是一种较新的方法&#xff0c;它会将 C# 代码先编译为 C 代码&#xff0c;再由 C 编译器…

【MySQL】 库的操作

欢迎拜访&#xff1a;雾里看山-CSDN博客 本篇主题&#xff1a;【MySQL】 库的操作 发布时间&#xff1a;2025.1.23 隶属专栏&#xff1a;MySQL 目录 库的创建语法使用 编码规则认识编码集查看数据库默认的编码集和校验集查看数据库支持的编码集和校验集指定编码创建数据库验证不…

【随手笔记】FFT资料整理

&#xff08;一&#xff09;结果验证 函数波形示例1 #define Fs 44800 #define NPT 256 void InitBufInArray() {int i 0;float fx 0;for(i0; i<NPT; i){// fx 1500 * sin(2*PI * i * 350.0 / Fs) // 2700 * sin(2*PI * i * 8400.0 / Fs) // 4000 * sin(2*P…

Spark Streaming编程基础

文章目录 1. 流式词频统计1.1 Spark Streaming编程步骤1.2 流式词频统计项目1.2.1 创建项目1.2.2 添加项目依赖1.2.3 修改源目录1.2.4 添加scala-sdk库1.2.5 创建日志属性文件 1.3 创建词频统计对象1.4 利用nc发送数据1.5 启动应用&#xff0c;查看结果 2. 编程模型的基本概念3…

R语言学习笔记之开发环境配置

一、概要 整个安装过程及遇到的问题记录 操作步骤备注&#xff08;包含遇到的问题&#xff09;1下载安装R语言2下载安装RStudio3离线安装pacman提示需要安装Rtools4安装Rtoolspacman、tidyfst均离线安装完成5加载tidyfst报错 提示需要安装依赖&#xff0c;试错逐步下载并安装…

【29】Word:李楠-学术期刊❗

目录 题目​ NO1.2.3.4.5 NO6.7.8 NO9.10.11 NO12.13.14.15 NO16 题目 NO1.2.3.4.5 另存为手动/F12Fn光标来到开头位置处→插入→封面→选择花丝→根据样例图片&#xff0c;对应位置填入对应文字 (手动调整即可&#xff09;复制样式&#xff1a;开始→样式对话框→管理…

【Prometheus】Prometheus如何监控Haproxy

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…