对Android应用启动时从ActivityThread.main到Application.onCreate的跟踪记录

一. 概述

Android中启动应用时,在Zygote进程fork自己创建一个新进程后,就会调用ActivityThread.main,而这便是进入app的起始入口。本片文章主要是记录Android 8.0.0_r1从ActivityThread.main方法到加载apk,再到调用Application的attach、attachBaseContext、onCreate。

二. ActivityThread.main

/frameworks/base/core/java/android/app/ActivityThread.java

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

        // 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();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
		//初始设置进程名为 "<pre-initialized>"
        Process.setArgV0("<pre-initialized>");
		//该行代码中调用Looper的prepare方法构造Looper对象,其中又会构建MessageQueue,并且设定mThread。Looper对象会赋给sMainLooper
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        //传参为false,表示不是系统进程附加,其中主要一步是"final IActivityManager mgr = ActivityManager.getService();  mgr.attachApplication(mAppThread);",这里会调用ams服务,最终会发送一个BIND_APPLICATION消息,对应的消息处理中会调用handleBindApplication(data),这里面就会加载apk以及调用Application的attach/attachBaseContext/onCreate方法。详见2小节。
        thread.attach(false);

        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");
    }

1. Looper.prepareMainLooper()

/frameworks/base/core/java/android/os/Looper.java

private Looper(boolean quitAllowed) {
   mQueue = new MessageQueue(quitAllowed);
   mThread = Thread.currentThread();
}


private static void prepare(boolean quitAllowed) {
   if (sThreadLocal.get() != null) {
	   throw new RuntimeException("Only one Looper may be created per thread");
   }
   sThreadLocal.set(new Looper(quitAllowed));
}

/**
 * Initialize the current thread as a looper, marking it as an
 * application's main looper. The main looper for your application
 * is created by the Android environment, so you should never need
 * to call this function yourself.  See also: {@link #prepare()}
 */
public static void prepareMainLooper() {
	prepare(false);
	synchronized (Looper.class) {
		if (sMainLooper != null) {
			throw new IllegalStateException("The main Looper has already been prepared.");
		}
		sMainLooper = myLooper();
	}
}

2. thread.attach(false)

/frameworks/base/core/java/android/app/ActivityThread.java

private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread);//通过binder机制,调用ams中的attachApplication方法
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            // Watch for getting close to heap limit. 监控是否垃圾回收
            BinderInternal.addGcWatcher(new Runnable() {
                @Override public void run() {}
            });
        } else {
            // 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",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplication(true, null); //这些是针对系统进程,普通进程加载在handleBindApplication中调用makeApplication
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }
		...
    }

2.1 ActivityManagerService.attachApplication

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

7020 @Override
7021    public final void attachApplication(IApplicationThread thread) {
7022        synchronized (this) {
7023            int callingPid = Binder.getCallingPid();
7024            final long origId = Binder.clearCallingIdentity();
7025            attachApplicationLocked(thread, callingPid);
7026            Binder.restoreCallingIdentity(origId);
7027        }
7028    }
6717    private final boolean attachApplicationLocked(IApplicationThread thread,
6718            int pid) {

6905            checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
6906            mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
6907            if (app.instr != null) {
6908                thread.bindApplication(processName, appInfo, providers,
6909                        app.instr.mClass,
6910                        profilerInfo, app.instr.mArguments,
6911                        app.instr.mWatcher,
6912                        app.instr.mUiAutomationConnection, testMode,
6913                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
6914                        isRestrictedBackupMode || !normalMode, app.persistent,
6915                        new Configuration(getGlobalConfiguration()), app.compat,
6916                        getCommonServicesLocked(app.isolated),
6917                        mCoreSettingsObserver.getCoreSettingsLocked(),
6918                        buildSerial);
6919            } else {
6920                thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
6921                        null, null, null, testMode,
6922                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
6923                        isRestrictedBackupMode || !normalMode, app.persistent,
6924                        new Configuration(getGlobalConfiguration()), app.compat,
6925                        getCommonServicesLocked(app.isolated),
6926                        mCoreSettingsObserver.getCoreSettingsLocked(),
6927                        buildSerial);
6928            }
				...
6944        }
			...
7018    }

/frameworks/base/core/java/android/app/ActivityThread.java

894        public final void bindApplication(String processName, ApplicationInfo appInfo,
895                ...
928            sendMessage(H.BIND_APPLICATION, data);
929        }
   public void handleMessage(Message msg) {
1585            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
1586            switch (msg.what) {
1658                case BIND_APPLICATION:
1659                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
1660                    AppBindData data = (AppBindData)msg.obj;
1661                    handleBindApplication(data);
1662                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1663                    break;
				...

3. Activity.handleBindApplication

/frameworks/base/core/java/android/app/ActivityThread.java

5453    private void handleBindApplication(AppBindData data) {
5454        ...
5717        if (ii != null) {
5718            final ApplicationInfo instrApp = new ApplicationInfo();
5719            ii.copyTo(instrApp);
5720            instrApp.initForUser(UserHandle.myUserId());
5721            final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
5722                    appContext.getClassLoader(), false, true, false);
5723            final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
5724
5725            try {
5726                final ClassLoader cl = instrContext.getClassLoader();//这里面会最终构造PathClassLoader加载apk
5727                mInstrumentation = (Instrumentation)
5728                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
5729            } catch (Exception e) {
5730                throw new RuntimeException(
5731                    "Unable to instantiate instrumentation "
5732                    + data.instrumentationName + ": " + e.toString(), e);
5733            }
5734
5735            final ComponentName component = new ComponentName(ii.packageName, ii.name);
5736            mInstrumentation.init(this, instrContext, appContext, component,
5737                    data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
5738		...
5762        try {
5763            // If the app is being launched for full backup or restore, bring it up in
5764            // a restricted environment with the base application class.
5765            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
5766            mInitialApplication = app;
5767
5768            // don't bring up providers in restricted mode; they may depend on the
5769            // app's custom Application class
5770            if (!data.restrictedBackupMode) {
5771                if (!ArrayUtils.isEmpty(data.providers)) {
5772                    installContentProviders(app, data.providers);
5773                    // For process that contains content providers, we want to
5774                    // ensure that the JIT is enabled "at some point".
5775                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
5776                }
5777            }
5778
5779            // Do this after providers, since instrumentation tests generally start their
5780            // test thread at this point, and we don't want that racing.
5781            try {
5782                mInstrumentation.onCreate(data.instrumentationArgs);
5783            }
5784            catch (Exception e) {
5785                throw new RuntimeException(
5786                    "Exception thrown in onCreate() of "
5787                    + data.instrumentationName + ": " + e.toString(), e);
5788            }
5789
5790            try {
5791                mInstrumentation.callApplicationOnCreate(app); //调用Application的onCreate方法
5792            } catch (Exception e) {
5793                if (!mInstrumentation.onException(app, e)) {
5794                    throw new RuntimeException(
5795                        "Unable to create application " + app.getClass().getName()
5796                        + ": " + e.toString(), e);
5797                }
5798            }
5799        } finally {
5800            StrictMode.setThreadPolicy(savedPolicy);
5801        }
5821    }

三. ContextImpl.getClassLoader() 包含apk的加载

/frameworks/base/core/java/android/app/ContextImpl.java

296    @Override
297    public ClassLoader getClassLoader() {
298        return mClassLoader != null ? mClassLoader : (mPackageInfo != null ? mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader());
299    }

/frameworks/base/core/java/android/app/LoadedApk.java

706    public ClassLoader getClassLoader() {
707        synchronized (this) {
708            if (mClassLoader == null) {
709                createOrUpdateClassLoaderLocked(null /*addedPaths*/);
710            }
711            return mClassLoader;
712        }
713    }
private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
580        if (mPackageName.equals("android")) {
581            // Note: This branch is taken for system server and we don't need to setup
582            // jit profiling support.
583            if (mClassLoader != null) {
584                // nothing to update
585                return;
586            }
587
588            if (mBaseClassLoader != null) {
589                mClassLoader = mBaseClassLoader;
590            } else {
591                mClassLoader = ClassLoader.getSystemClassLoader();
592            }
593
594            return;
595        }
623        final List<String> zipPaths = new ArrayList<>(10);
624        final List<String> libPaths = new ArrayList<>(10);
625
626        final boolean isBundledApp = mApplicationInfo.isSystemApp()
627                && !mApplicationInfo.isUpdatedSystemApp();
628
629        makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
630
631        String libraryPermittedPath = mDataDir;
632        if (isBundledApp) {
633            // This is necessary to grant bundled apps access to
634            // libraries located in subdirectories of /system/lib
635            libraryPermittedPath += File.pathSeparator +
636                                    System.getProperty("java.library.path");
637        }
638
639        final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
640
641        // If we're not asked to include code, we construct a classloader that has
642        // no code path included. We still need to set up the library search paths
643        // and permitted path because NativeActivity relies on it (it attempts to
644        // call System.loadLibrary() on a classloader from a LoadedApk with
645        // mIncludeCode == false).
646        if (!mIncludeCode) {
647            if (mClassLoader == null) {
648                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
649                mClassLoader = ApplicationLoaders.getDefault().getClassLoader(
650                    "" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp,
651                    librarySearchPath, libraryPermittedPath, mBaseClassLoader);
652                StrictMode.setThreadPolicy(oldPolicy);
653            }
654
655            return;
656        }

664        final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
665                TextUtils.join(File.pathSeparator, zipPaths);
666
667        if (DEBUG) Slog.v(ActivityThread.TAG, "Class path: " + zip +
668                    ", JNI path: " + librarySearchPath);
669
670        boolean needToSetupJitProfiles = false;
671        if (mClassLoader == null) {
672            // Temporarily disable logging of disk reads on the Looper thread
673            // as this is early and necessary.
674            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
675
676            mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
677                    mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
678                    libraryPermittedPath, mBaseClassLoader);
679
680            StrictMode.setThreadPolicy(oldPolicy);
681            // Setup the class loader paths for profiling.
682            needToSetupJitProfiles = true;
683        } ...
704    }

/frameworks/base/core/java/android/app/ApplicationLoaders.java

 public static ApplicationLoaders getDefault() {
	return gApplicationLoaders;
}
private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
41                                       String librarySearchPath, String libraryPermittedPath,
42                                       ClassLoader parent, String cacheKey) {
43        /*
44         * This is the parent we use if they pass "null" in.  In theory
45         * this should be the "system" class loader; in practice we
46         * don't use that and can happily (and more efficiently) use the
47         * bootstrap class loader.
48         */
49        ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent();
50
51        synchronized (mLoaders) {
52            if (parent == null) {
53                parent = baseParent;
54            }
55
56            /*
57             * If we're one step up from the base class loader, find
58             * something in our cache.  Otherwise, we create a whole
59             * new ClassLoader for the zip archive.
60             */
61            if (parent == baseParent) {
62                ClassLoader loader = mLoaders.get(cacheKey);
63                if (loader != null) {
64                    return loader;
65                }
66
67                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
68
69                PathClassLoader pathClassloader = PathClassLoaderFactory.createClassLoader(
70                                                      zip,
71                                                      librarySearchPath,
72                                                      libraryPermittedPath,
73                                                      parent,
74                                                      targetSdkVersion,
75                                                      isBundled);
76
77                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
78
79                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setupVulkanLayerPath");
80                setupVulkanLayerPath(pathClassloader, librarySearchPath);
81                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
82
83                mLoaders.put(cacheKey, pathClassloader);
84                return pathClassloader;
85            }
86
87            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
88            PathClassLoader pathClassloader = new PathClassLoader(zip, parent);
89            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
90            return pathClassloader;
91        }
92    }

/frameworks/base/core/java/com/android/internal/os/PathClassLoaderFactory.java

public static PathClassLoader createClassLoader(String dexPath,
38                                                    String librarySearchPath,
39                                                    String libraryPermittedPath,
40                                                    ClassLoader parent,
41                                                    int targetSdkVersion,
42                                                    boolean isNamespaceShared) {
43        PathClassLoader pathClassloader = new PathClassLoader(dexPath, librarySearchPath, parent);//PathClassLoader类中会对apk文件进行加载,类似DexClassLoader,但前者能只能加载已经安装好的apk,后者可以加载任意目录下的dex文件,当然必须得有可读可写权限
		...
58        return pathClassloader;
59    }

四.Application的attach/attachBaseContext/onCreate调用

/frameworks/base/core/java/android/app/ActivityThread.java

try {
5763            // If the app is being launched for full backup or restore, bring it up in
5764            // a restricted environment with the base application class.
5765            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
5766            mInitialApplication = app; ...
5790            try {
5791                mInstrumentation.callApplicationOnCreate(app);
5792            } catch (Exception e) {
5793                if (!mInstrumentation.onException(app, e)) {
5794                    throw new RuntimeException(
5795                        "Unable to create application " + app.getClass().getName()
5796                        + ": " + e.toString(), e);
5797                }
5798            }
5799        } finally {
5800            StrictMode.setThreadPolicy(savedPolicy);
5801        }

frameworks/base/core/java/android/app/LoadedApk.java

public Application makeApplication(boolean forceDefaultAppClass,
942            Instrumentation instrumentation) {
943        if (mApplication != null) {
944            return mApplication;
945        }
946			...
955
956        try {
957            java.lang.ClassLoader cl = getClassLoader();
958           ...
964            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
965            app = mActivityThread.mInstrumentation.newApplication(
966                    cl, appClass, appContext);
967            ...
1006        return app;
1007    }

调用Application的attach方法

static public Application newApplication(Class<?> clazz, Context context)
1099            throws InstantiationException, IllegalAccessException,
1100            ClassNotFoundException {
1101        Application app = (Application)clazz.newInstance();//在反射构造Application实例后,马上调用Application的attach方法
1102        app.attach(context);
1103        return app;
1104    }

/frameworks/base/core/java/android/app/Application.java

  /* package */ final void attach(Context context) {
189        attachBaseContext(context);
190        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
191    }

/frameworks/base/core/java/android/content/ContextWrapper.java
调用Application的attachBaseContext方法,attachBaseContext 在Application的父类ContextWrapper中。

   protected void attachBaseContext(Context base) { 
69        if (mBase != null) {
70            throw new IllegalStateException("Base context already set");
71        }
72        mBase = base;
73    }

调用Application的onCreate方法

  public void callApplicationOnCreate(Application app) {
1118        app.onCreate();
1119    }

综上,app启动时,是先调用Application.attach —>Application.attachBaseContext —>Application.onCreate —> Activity.onCreate。

五.总结

本片文章主要是记录Android 8.0.0_r1从ActivityThread.main方法到加载apk,再到调用Application的attach、attachBaseContext、onCreate。如果有写得不对的地方,望多指正。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这是什么问题FATAL EXCEPTION: main Process: com.example.lightcontrol_app2, PID: 4533 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.lightcontrol_app2/com.example.lightcontrol_app2.ui.control.activity.EditingSingleLampActivity}: java.lang.RuntimeException: setOnItemClickListener cannot be used with a spinner. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2668) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2729) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1480) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6176) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783) Caused by: java.lang.RuntimeException: setOnItemClickListener cannot be used with a spinner. at android.widget.Spinner.setOnItemClickListener(Spinner.java:571) at com.example.lightcontrol_app2.ui.control.activity.EditingSingleLampActivity.init(EditingSingleLampActivity.java:111) at com.example.lightcontrol_app2.ui.control.activity.EditingSingleLampActivity.onCreate(EditingSingleLampActivity.java:65) at android.app.Activity.performCreate(Activity.java:6692) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2621) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2729) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1480) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6176) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
06-11
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值