startService启动流程---Service在非App进程且未启动

在 Service启动流程(startService)的最后,分析了在调用startService时可能存在的三种情况,本文分析第三种情况—Service不在App进程且未启动。

Service启动流程(startService)最后已经说明,在这种情况下,系统会执行startProcessLocked函数。startProcessLocked函数是不是很熟悉,在前面分析Activity从Launched中启动的时候,为了启动App,需要调用startProcessLocked函数创建新的进程。

private final void startProcessLocked(ProcessRecord app,
        String hostingType, String hostingNameStr) {
        ......
        int debugFlags = 0;
        if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
            debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
            // Also turn on CheckJNI for debuggable apps. It's quite
            // awkward to turn on otherwise.
            debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
        }
        // 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.jni.logging"))) {
            debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
        }
        if ("1".equals(SystemProperties.get("debug.assert"))) {
            debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
        }

        // Start the process.  It will either succeed and return a result containing
        // the PID of the new process, or else throw a RuntimeException.
        Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                app.processName, uid, uid, gids, debugFlags,
                app.info.targetSdkVersion, null);

       ......
}  

函数中略去了不影响Process启动的代码,Process.start方法的执行,回去调用ActivityThreadmain方法。

public static void main(String[] args) {
    ......
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    ......
}  

继续看下ActivityThreadattach函数

private void attach(boolean system) {
    sThreadLocal.set(this);
    mSystemThread = system;
    if (!system) {
        ......
        IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // Ignore
        }
    } else {
        ......
    }
    ......
}  

由于Service进程不是系统进程,故attach会执行以上逻辑,attachApplication函数是跨进程调用,可以在ActivityManagerService中找到这个方法

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {

    ......
    try {
        ......
        thread.bindApplication(processName, appInfo, providers,
                app.instrumentationClass, profileFile, profileFd, profileAutoStop,
                app.instrumentationArguments, app.instrumentationWatcher, testMode,
                enableOpenGlTrace, isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
                mCoreSettingsObserver.getCoreSettingsLocked());
        ......
    } catch (Exception e) {
        // todo: Yikes!  What should we do?  For now we will try to
        // start another process, but that could easily get us in
        // an infinite loop of restarting processes...
        Slog.w(TAG, "Exception thrown during bind!", e);

        app.resetPackageList();
        app.unlinkDeathRecipient();
        startProcessLocked(app, "bind fail", processName);
        return false;
    }

    ......
    //新建完进程后启动Service
    if (!badApp && mPendingServices.size() > 0) {
        ServiceRecord sr = null;
        try {
            for (int i=0; i

这部分的代码有启动Service的逻辑,会在执行完新建进程后分析。直接定位到最关键的代码bindApplication,又是一个Binder跨进程调用,最终在ActivityThread中调用。

public final void bindApplication(String processName,
            ApplicationInfo appInfo, List providers,
            ComponentName instrumentationName, String profileFile,
            ParcelFileDescriptor profileFd, boolean autoStopProfiler,
            Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
            int debugMode, boolean enableOpenGlTrace, boolean isRestrictedBackupMode,
            boolean persistent, Configuration config, CompatibilityInfo compatInfo,
            Map services, Bundle coreSettings) {

        if (services != null) {
            // Setup the service cache in the ServiceManager
            ServiceManager.initServiceCache(services);
        }

        setCoreSettings(coreSettings);

        AppBindData data = new AppBindData();
        data.processName = processName;
        data.appInfo = appInfo;
        data.providers = providers;
        data.instrumentationName = instrumentationName;
        data.instrumentationArgs = instrumentationArgs;
        data.instrumentationWatcher = instrumentationWatcher;
        data.debugMode = debugMode;
        data.enableOpenGlTrace = enableOpenGlTrace;
        data.restrictedBackupMode = isRestrictedBackupMode;
        data.persistent = persistent;
        data.config = config;
        data.compatInfo = compatInfo;
        data.initProfileFile = profileFile;
        data.initProfileFd = profileFd;
        data.initAutoStopProfiler = false;
        queueOrSendMessage(H.BIND_APPLICATION, data);
    }  

又是Handler对消息的处理,可以直接定位到最终的执行函数handleBindApplication

private void handleBindApplication(AppBindData data) {
    mBoundApplication = data;
    ......
    if (data.instrumentationName != null) {
        InstrumentationInfo ii = null;
        try {
            ii = appContext.getPackageManager().
                getInstrumentationInfo(data.instrumentationName, 0);
        } catch (PackageManager.NameNotFoundException e) {
        }
        if (ii == null) {
            throw new RuntimeException(
                "Unable to find instrumentation info for: "
                + data.instrumentationName);
        }

        mInstrumentationAppDir = ii.sourceDir;
        mInstrumentationAppLibraryDir = ii.nativeLibraryDir;
        mInstrumentationAppPackage = ii.packageName;
        mInstrumentedAppDir = data.info.getAppDir();
        mInstrumentedAppLibraryDir = data.info.getLibDir();

        ApplicationInfo instrApp = new ApplicationInfo();
        instrApp.packageName = ii.packageName;
        instrApp.sourceDir = ii.sourceDir;
        instrApp.publicSourceDir = ii.publicSourceDir;
        instrApp.dataDir = ii.dataDir;
        instrApp.nativeLibraryDir = ii.nativeLibraryDir;
        LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                appContext.getClassLoader(), false, true);
        ContextImpl instrContext = new ContextImpl();
        instrContext.init(pi, null, this);

        try {
            java.lang.ClassLoader cl = instrContext.getClassLoader();
            mInstrumentation = (Instrumentation)
                cl.loadClass(data.instrumentationName.getClassName()).newInstance();
        } catch (Exception e) {
            throw new RuntimeException(
                "Unable to instantiate instrumentation "
                + data.instrumentationName + ": " + e.toString(), e);
        }

        mInstrumentation.init(this, instrContext, appContext,
                new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher);

        if (mProfiler.profileFile != null && !ii.handleProfiling
                && mProfiler.profileFd == null) {
            mProfiler.handlingProfiling = true;
            File file = new File(mProfiler.profileFile);
            file.getParentFile().mkdirs();
            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
        }

    } else {
        mInstrumentation = new Instrumentation();
    }

    if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
        dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
    }

    // Allow disk access during application and provider setup. This could
    // block processing ordered broadcasts, but later processing would
    // probably end up doing the same disk access.
    final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
    try {
        // If the app is being launched for full backup or restore, bring it up in
        // a restricted environment with the base application class.
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;

       ......
        try {
            mInstrumentation.onCreate(data.instrumentationArgs);
        }
        catch (Exception e) {
            throw new RuntimeException(
                "Exception thrown in onCreate() of "
                + data.instrumentationName + ": " + e.toString(), e);
        }

        try {
            //执行Application的onCreate方法
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to create application " + app.getClass().getName()
                    + ": " + e.toString(), e);
            }
        }
    } finally {
        StrictMode.setThreadPolicy(savedPolicy);
    }
}  

这段代码略去了不影响流程的代码,剩余的代码完成了新建Instrumentation对象mInstrumentation,然后调用了mInstrumentation.callApplicationOnCreate(app)方法,也就是执行了Application的onCreate方法。

这部分的逻辑也提醒我们,如果我们在应用中声明的Service不在应用的进程中,在启动Service的时候,应用的Application会执行。

好的,上面的代码执行完成之后,Service所在的进程已经创建完毕,接下来就要真正走执行Service自己的方法流程了。在本文attachApplicationLocked方法的最后,会有一个启动Service的逻辑:

if (!badApp && mPendingServices.size() > 0) {
        ServiceRecord sr = null;
        try {
            for (int i=0; i

badAppp = false,在Service启动流程(startService)的最后,会将即将启动的ServiceRecord添加到ActivityManagerService的mPendingServices队列中,因此mPendingServices.size()>0,故会执行接下来的逻辑。接下来的逻辑中,会循环遍历mPendingServices,由于此时是在单独进程中启动Service,故会对新建的进程app进行判断,,并且会对app的uid和processName进行判断,条件满足说明不需要对Service执行启动操作,执行continue,否则执行realStartServiceLocked去启动Service,realStartServiceLocked函数的逻辑可以参考startService启动流程—Service在App进程但未启动的内容,这里就不在进行分析了

你可能感兴趣的:(android,framework,android,framework)