アプリのパフォーマンス最適化の起動プロセス分析

1. Android システムの起動プロセスの分析

  1. BootLoader はカーネルと init プロセスを開始します。
  2. init プロセスは、Android Debug Damon、USB Damon などのデーモン プロセスを分割します。これらのデーモン プロセスは、ハードウェア関連のインターフェイスを処理します。
  3. The init process starts a Zygote process. Zygote プロセスは最初の VM を初期化し、フレームワークといくつかの共通リソースをプリロードします。
    zygote プロセスは、リクエストを監視するために Socket インターフェイスを開きます。リクエストが受信されると、Zygote は独自のプリロードされた VM に基づいて新しい VM をインキュベートし、新しいプロセスを作成します。
  4. Zygote の開始後、init プロセスはランタイム プロセスを開始します。Zygote は、スーパー管理プロセスである System Server を孵化させます。System Server は、Activity Manager Service やハードウェア関連サービスなど、すべてのシステム コア サービスを開始します。
  5. この時点で、最初のアプリ プロセス - ホーム プロセスを開始する準備ができています。

Android システムが開始され、いくつかのコア サービスも開始され、続いて Launcher アプリケーションが開始されます。

2. アプリ起動プロセスの分析

App プロセスはいつ作成されますか?

アプリケーションが別のアプリケーションのページを呼び出すとき、対象のプロセスが存在しない場合は、新しいプロセスが作成されて開始されます。

アプリケーションの起動プロセス

まずはフローチャートをご覧ください

  1. デスクトップ上のアイコンをクリックするか、クリックしてフォアグラウンド アプリケーションの別のアプリケーションにジャンプします
  2. 次に、StartActivity(Intent intent) メソッドを呼び出します。
    このメソッドは、最終的に、ここでは AMS と呼ばれる Binder IPC を介して ActivityManagerService を呼び出します。
  3. AMS は次のことを行います。
    1. 最後に、PackageManager の resolveIntent() メソッドを通じて、この Intent オブジェクトのポインティング情報が収集されます (途中で多くのクラスとメソッド呼び出しが行われます)。
    2. grantUriPermissionLocked() メソッドを使用して、ユーザーがターゲット アクティビティを呼び出すのに十分な権限を持っているかどうかを確認します。
    3. ProcessRecord が存在するかどうかを問い合わせます。
      存在しない場合、AMS はターゲット アクティビティをインスタンス化する新しいプロセスを作成します。

次に、App プロセスの作成プロセスについて説明します。

アプリ プロセスの作成

  1. startProcessLocked() メソッドを呼び出して新しいプロセスを作成し、上記のソケット チャネルを介して Zygote プロセスにパラメーターを渡します。Zygote プロセスは自身をインキュベートし、ZygoteInit.main() メソッドを呼び出して ActivityThread オブジェクトをインスタンス化し、最後に新しいプロセスの pid。
  2. ActivityThread は、Looper.prepare() メソッドと Looper.loop() メソッドを順番に呼び出して、メッセージ ループを開きます。

この時点でプロセスが作成されましたが、それをどのようにアプリケーション自体にリンクしますか?

アプリケーションバインディング

  1. ActivityThread で bindApplication() メソッドを呼び出して、BIND_APPLICATION メッセージをメッセージ キューに送信します。
  2. handleBindApplication() メソッドを介して前のバインディング メッセージを処理します。
  3. makeApplication() メソッドを呼び出して、Application クラスをメモリにロードします。

以下は、部分的なソース コード スニペットです。

ActivityThread.java

sendMessage(H.BIND_APPLICATION, データ);

@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 services, Bundle coreSettings,
                                  String buildSerial, AutofillOptions autofillOptions,
                                  ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges,
                                  SharedMemory serializedSystemFontMap) {
    if (services != null) {
        if (false) {
            // Test code to make sure the app could see the passed-in services.
            for (Object oname : services.keySet()) {
                if (services.get(oname) == null) {
                    continue; // AM just passed in a null service.
                }
                String name = (String) oname;

                // See b/79378449 about the following exemption.
                switch (name) {
                    case "package":
                    case Context.WINDOW_SERVICE:
                        continue;
                }

                if (ServiceManager.getService(name) == null) {
                    Log.wtf(TAG, "Service " + name + " should be accessible by this app");
                }
            }
        }

        // Setup the service cache in the ServiceManager
        ServiceManager.initServiceCache(services);
    }

    setCoreSettings(coreSettings);

    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;
    data.mSerializedSystemFontMap = serializedSystemFontMap;
    sendMessage(H.BIND_APPLICATION, data);
}

ハンドルメッセージ(メッセージ)

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(データ)

 @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);

            // Propagate autofill compat state
            app.setAutofillOptions(data.autofillOptions);

            // Propagate Content Capture options
            app.setContentCaptureOptions(data.contentCaptureOptions);
            sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName);

            mInitialApplication = app;
            final boolean updateHttpProxy;
            synchronized (this) {
                updateHttpProxy = mUpdateHttpProxyOnBind;
                // This synchronized block ensures that any subsequent call to updateHttpProxy()
                // will see a non-null mInitialApplication.
            }
            if (updateHttpProxy) {
                ActivityThread.updateHttpProxy(app);
            }

            // don't bring up providers in restricted mode; they may depend on the
            // app's custom Application class
            if (!data.restrictedBackupMode) {
                if (!ArrayUtils.isEmpty(data.providers)) {
                    installContentProviders(app, data.providers);
                }
            }
            ...
        }
        
        ...
    }

data.info.makeApplication(data.restrictedBackupMode, null) と installContentProviders(app, data.providers) に注意してください。

data.info タイプは LoadedApk です

LoadedApk.java

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

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        final java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                             "initializeJavaContextClassLoader");
            initializeJavaContextClassLoader();
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }

        // Rewrite the R 'constants' for all library apks.
        SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers(
            false, false);
        for (int i = 0, n = packageIdentifiers.size(); i < n; i++) {
            final int id = packageIdentifiers.keyAt(i);
            if (id == 0x01 || id == 0x7f) {
                continue;
            }

            rewriteRValues(cl, packageIdentifiers.valueAt(i), id);
        }

        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) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + " package " + mPackageName + ": " + e.toString(), e);
        }
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    if (instrumentation != null) {
        try {
            instrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!instrumentation.onException(app, e)) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw new RuntimeException(
                    "Unable to create application " + app.getClass().getName()
                    + ": " + e.toString(), e);
            }
        }
    }

    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    return app;
}

そのうち、mApplicationInfo.className は App によってカスタマイズされたアプリケーションです。空の場合、デフォルトの appClass = "android.app.Application" が使用されます。initializeJavaContextClassLoader() は、クラス ローダーを初期化するためのロジック コールであり、続行できます。 sharedUserId を同じに設定すると、仮想マシンのロジックを共有できることがわかります。

app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext) このとき、Instrumentation での Application のインスタンス化であることがわかります。

コードの抜粋を見てください

ActivityThread.java

mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);

...
// Restore instance state
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState);

...
// Call postOnCreate()
mInstrumentation.callActivityOnPostCreate(activity, r.state, r.persistentState);

...
mInstrumentation.callActivityOnNewIntent(r.activity, intent);

...
 mInstrumentation.callActivityOnPause(r.activity);

...
mInstrumentation.callActivityOnDestroy(r.activity);

...
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);

...
mInstrumentation.callApplicationOnCreate(app);

その中には: callActivityOnCreate, callApplicationOnCreate, newActivity, callActivityOnNewIntent など. ActivityThread クラスの Instrumentation を介したアプリケーションとアクティビティのすべてのライフサイクル呼び出しでは、Instrumentation の対応するメソッドが最初に呼び出され、対応する関数が実現されます. より正確な関連関数があります。 Instrumentation class. メソッドで。

Instrumentation.java に進みます

 static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

ここで、Application クラスを作成します。

アプリケーション.java

final void attach(Context context) {
    attachBaseContext(context);
    mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

最後に、私たちが最もよく知っている attachBaseContext メソッドを見つけました。
もう一度 ContentProvider の onCreate のタイミングを探ってみましょう、まず前述の ActivityThread.java の publishContentProviders メソッドに戻りますと、先ほど実行した installContentProviders メソッドがあることがわかりますので、
このメソッドを確認してください

ActivityThread.java

 @UnsupportedAppUsage
    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<ContentProviderHolder> results = new ArrayList<>();

        for (ProviderInfo cpi : providers) {
            if (DEBUG_PROVIDER) {
                StringBuilder buf = new StringBuilder(128);
                buf.append("Pub ");
                buf.append(cpi.authority);
                buf.append(": ");
                buf.append(cpi.name);
                Log.i(TAG, buf.toString());
            }
            ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }

        try {
            ActivityManager.getService().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
private IActivityManager.ContentProviderHolder installProvider(Context context,IActivityManager.ContentProviderHolder holder, ProviderInfo info,boolean noisy, boolean noReleaseNeeded, boolean stable) {
    ...
    final java.lang.ClassLoader cl = c.getClassLoader();
                localProvider = (ContentProvider)cl.
                    loadClass(info.name).newInstance();
                provider = localProvider.getIContentProvider();
                if (provider == null) {
                    Slog.e(TAG, "Failed to instantiate class " +
                          info.name + " from sourceDir " +
                          info.applicationInfo.sourceDir);
                    return null;
                }
                if (DEBUG_PROVIDER) Slog.v(
                    TAG, "Instantiating local provider " + info.name);
                // XXX Need to create the correct context for this provider.
                localProvider.attachInfo(c, info);
    ...

}

ここで、ClassLoader から ContentProvider クラスのインスタンスをロードし、attachInfo メソッドを呼び出します。

ContentProvider.java を見てみましょう

private void attachInfo(Context context, ProviderInfo info, boolean testing) {
    ...
    ContentProvider.this.onCreate();
    ...
}

上記の起動プロセスの簡単な要約:

  1. ActivityThread.attath()
  2. AMS.attachApplication()
  3. ActivityThread.handleBindApplication()
  4. Application.attachBaseContext()
  5. ActivityThread.installContentProviders
  6. ContentProvider.onCreate()
  7. AMS.publishContentProviders()
  8. アプリケーション.onCreate()

したがって、アプリの起動を最適化するために、Application.attachBaseContext()、ContentProvider.onCreate()、および Application.onCreate() の 3 つの側面から介入できます。

 

おすすめ

転載: blog.csdn.net/u011106915/article/details/125389912