Android之Application进阶

一、Application的作用是什么?

  • 保存全局变量,但是,不建议在Application中保存全局变量。在App进入后台后,当前设备内存不足,会回收一些不在前台应用的内存,保存在Application中的全局变量会被释放,当前App在回到前台使用这些变量,变量会是null。
  • 初始化任务。
  • 提供Context上下文。

二、Application的生命周期

  1. 构造函数。
  2. attachBaseContext()函数。
  3. onCreate()函数。
  4. onTerminate()函数,但是,这个方法只有在模拟器中有效,在真机是不会被调用的。

三、Application的初始化过程

  1. 继承关系

public class Application extends ContextWrapper implements ComponentCallbacks2 {
    ……
}

  继承链:Application -> ContextWrapper -> Context

  2. 初始化过程

  AMS通过Zygote创建应用进程,应用进程启动完成后通过AMS,AMS再通知应用创建Application对象。

  下面代码是AMS通知应用创建Application对象的逻辑过程:

  源码:frameworks/base/core/java/android/app/ActivityThread.java

  ActivityThread类的main()函数是应用的入口函数:

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

    // Install selective syscall interception
    AndroidOs.install();

    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);

    Environment.initForCurrentUser();

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    // Call per-process mainline module initialization.
    initializeMainlineModules();

    Process.setArgV0("<pre-initialized>");

    Looper.prepareMainLooper();

    // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
    // It will be in the format "seq=114"
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

  main()函数中创建Application对象代码:

ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
……
Looper.loop();

  在thread.attach()函数中,实现了App与AMS通过,并将App的binder引用ApplicationThread对象mAppThread一起发送给AMS,AMS通过ApplicationThread对象(Binder代理对象)与App通过,通过App创建Application。

@UnsupportedAppUsage
private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        ……
    } else {
        ……
    }

    ……
}

  代码中,mgr是AMS的binder引用对象,也用于应用与AMS通信。通过mgr.attachApplication(mAppThread, ...)函数调用AMS服务的attachApplication(...)函数,看看在AMS是怎么执行的。

  PS:注意在attachApplication(mAppThread, ...)函数的参数mAppThread是应用的Binder对象,用于AMS与应用通信。mAppThread在AMS中有用到,看下面实现。

  源码:frameworks/services/core/java/com/android/server/ActivityManagerService.java

  attachApplication(...)函数:

@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    if (thread == null) {
        throw new SecurityException("Invalid application interface");
    }
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        Binder.restoreCallingIdentity(origId);
    }
}

  在attachAppliation(...)函数中使用synchronized加锁。因为,函数在AMS的binder线程池中执行,所以这里需要加锁。

  看attachApplication(...)函数中的attachApplicationLocked(...)函数实现:

@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
        int pid, int callingUid, long startSeq) {

    ……
    
    try {
        ……
        if (app.isolatedEntryPoint != null) {
            ……
        } else if (instr2 != null) {
            thread.bindApplication(processName, appInfo, providerList,
                    instr2.mClass,
                    profilerInfo, instr2.mArguments,
                    instr2.mWatcher,
                    instr2.mUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.isPersistent(),
                    new Configuration(app.getWindowProcessController().getConfiguration()),
                    app.compat, getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, autofillOptions, contentCaptureOptions,
                    app.mDisabledCompatChanges);
        } else {
            thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
                    null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.isPersistent(),
                    new Configuration(app.getWindowProcessController().getConfiguration()),
                    app.compat, getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, autofillOptions, contentCaptureOptions,
                    app.mDisabledCompatChanges);
        }
        ……
    } catch (Exception e) {
        ……
    }

    // See if the top visible activity is waiting to run in this process...
    if (normalMode) {
        try {
            didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }

    // Find any services that should be running in this process...
    if (!badApp) {
        try {
            didSomething |= mServices.attachApplicationLocked(app, processName);
            checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
            badApp = true;
        }
    }

    // Check if a next-broadcast receiver is in this process...
    if (!badApp && isPendingBroadcastProcessLocked(pid)) {
        try {
            didSomething |= sendPendingBroadcastsLocked(app);
            checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");
        } catch (Exception e) {
            // If the app died trying to launch the receiver we declare it 'bad'
            Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
            badApp = true;
        }
    }

    ……
}

  在函数中,thread.bindApplication(...)语句,thread是上文中说的应用的Binder对象。

  这里,需要注意一点,thread.bindApplication(...)函数是oneway调用。

  调用thread.bindApplication(...)函数后,执行下面代码:

// See if the top visible activity is waiting to run in this process...
mAtmInternal.attachApplication(app.getWindowProcessController());

// Find any services that should be running in this process...
mServices.attachApplicationLocked(app, processName);

// Check if a next-broadcast receiver is in this process...
sendPendingBroadcastsLocked(app);

  在应用主线程(UI线程)中创建Activity、Service、Broadcast。

  bindApplication(...)函数实现:

  frameworks/base/core/java/android/app/ActivityThread.java文件中ApplicationThread类中的函数:

private class ApplicationThread extends IApplicationThread.Stub {
    ……

    @Override
    public final void bindApplication(String processName, ApplicationInfo appInfo,
            ProviderInfoList providerList, ComponentName instrumentationName,
            ProfilerInfo profilerInfo, Bundle instrumentationArgs,
            IInstrumentationWatcher instrumentationWatcher,
            IUiAutomationConnection instrumentationUiConnection, int debugMode,
            boolean enableBinderTracking, boolean trackAllocation,
            boolean isRestrictedBackupMode, boolean persistent, Configuration config,
            CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
            String buildSerial, AutofillOptions autofillOptions,
            ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
        ……
        AppBindData data = new AppBindData();
        data.processName = processName;
        data.appInfo = appInfo;
        data.providers = providerList.getList();
        data.instrumentationName = instrumentationName;
        data.instrumentationArgs = instrumentationArgs;
        data.instrumentationWatcher = instrumentationWatcher;
        data.instrumentationUiAutomationConnection = instrumentationUiConnection;
        data.debugMode = debugMode;
        data.enableBinderTracking = enableBinderTracking;
        data.trackAllocation = trackAllocation;
        data.restrictedBackupMode = isRestrictedBackupMode;
        data.persistent = persistent;
        data.config = config;
        data.compatInfo = compatInfo;
        data.initProfilerInfo = profilerInfo;
        data.buildSerial = buildSerial;
        data.autofillOptions = autofillOptions;
        data.contentCaptureOptions = contentCaptureOptions;
        data.disabledCompatChanges = disabledCompatChanges;
        sendMessage(H.BIND_APPLICATION, data);
    }

    ……
}

  在bindApplication(...)函数中通过sendMessage(...)函数将创建Application的消息发送到UI线程的Looper中。在ActivityThread类中实现的Handler callback,callback实现:

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
        case BIND_APPLICATION:
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
            AppBindData data = (AppBindData)msg.obj;
            handleBindApplication(data);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            break;
    }
}

  在消息执行中调用handleBindApplication(data)函数创建Application对象:

@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
    ……
    try {
        // If the app is being launched for full backup or restore, bring it up in
        // a restricted environment with the base application class.
        app = data.info.makeApplication(data.restrictedBackupMode, null);

        ……
    } finally {
        ……
    }

    ……
}

  调用data.info.makeApplication(...)函数,其实现:

  源码:frameworks/base/core/java/android/app/LoadedApk.java

@UnsupportedAppUsage
public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }

    try {
        ……
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        // The network security config needs to be aware of multiple
        // applications in the same process to handle discrepancies
        NetworkSecurityConfigProvider.handleNewApplication(appContext);
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        ……
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    return app;
}

  makeApplication(...)函数开头,mApplication != null是避免Application重复创建的防御代码。

  在makeApplication(...)函数中通过newApplication(..., appContext)创建Application对象:

  源码:frameworks/base/core/java/android/app/Instrumentation.java

/**
     * Perform instantiation of the process's {@link Application} object.  The
     * default implementation provides the normal system behavior.
     * 
     * @param cl The ClassLoader with which to instantiate the object.
     * @param className The name of the class implementing the Application
     *                  object.
     * @param context The context to initialize the application with
     * 
     * @return The newly instantiated Application object.
     */
    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        app.attach(context);
        return app;
    }

  在Application创建完成后,调用attach(context)函数,attach(context)函数再调用attachBaseContext(Context base)函数,将Context上下文对象赋值给Application类的父类ContextWrapper类中的成员变量mBase。Context详细请看Context进阶文章。

  上面就是在zygote进程fork应用进程后,AMS通过应用创建Application对象的过程。

四、Application生命周期函数不能执行耗时操作原因

  AMS通知应用创建Application对象是在UI线程执行的,如果在Applicaiton回调函数中执行耗时操作会堵塞UI线程,导致其它组件延迟创建,让App启动慢。

五、总结

  1. Application应用的数量?

  在应用中有多少进程就有多少Application对象,Application对象是随进程创建的,而不是应用。

  2. Application生命周期函数不能执行耗时操作。

  3. oneway方法是什么?

  oneway方法在调用后直接返回,不会等待函数执行完成。在AMS类中bindApplicationLocked(...)函数中thread.bindApplication(...)函数就是oneway函数,在调用后立即返回,不等待执行完成,这样即使应用执行耗时操作,也不会堵塞AMS服务执行。在Binder中有很多oneway方法。

原文地址:https://www.cnblogs.com/naray/p/15252036.html