• android应用程序启动流程分析


    android应用程序启动流程

    当在launcher进程(home进程)中点击一个应用的图标时其会调用startActivity,然后会通过Binder与system_server系统进程跨进程通讯。system_server会调用Process.start开始启动一个新进程。Process.start会先调用Porcess.StartViaZygote函数


    Porcess.StartViaZygote函数会进一步调用Process.zygoteSendArgsAndGetResult函数打开一个socket连接。

    在zygote进程中会监控此socket连接,监听返回后会调用

    if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
                            || !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
                        // Continue using old code for now. TODO: Handle these cases in the other path.
                        //调用forkAndSpecialize去fork一个新进程
                        pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
                                parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
                                parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
                                fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                                parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
                                parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
                                parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
                                parsedArgs.mBindMountAppStorageDirs);
    
                        try {
                            if (pid == 0) {
                                // in child
                                //如果是子进程就调用handleParentProc()
                                zygoteServer.setForkChild();
    
                                zygoteServer.closeServerSocket();
                                IoUtils.closeQuietly(serverPipeFd);
                                serverPipeFd = null;
    
                                return handleChildProc(parsedArgs, childPipeFd,
                                        parsedArgs.mStartChildZygote);
                            } else {
                                // In the parent. A pid < 0 indicates a failure and will be handled in
                                // handleParentProc.
                                IoUtils.closeQuietly(childPipeFd);
                                childPipeFd = null;
                                handleParentProc(pid, serverPipeFd);
                                return null;
                            }
                        } finally {
                            IoUtils.closeQuietly(childPipeFd);
                            IoUtils.closeQuietly(serverPipeFd);
                        }
                    } 
    

    handlerChildProc最终会调用findStaticMain去加载android.app.ActivityThread类并通过反射调用其对应的静态main方法

    protected static Runnable findStaticMain(String className, String[] argv,
                ClassLoader classLoader) {
            Class<?> cl;
    
            try {
                //加载android.app.ActivityThread类
                cl = Class.forName(className, true, classLoader);
            } catch (ClassNotFoundException ex) {
                throw new RuntimeException(
                        "Missing class when invoking static main " + className,
                        ex);
            }
    
            Method m;
            try {
                //得到android.app.ActivityThread类的静态main方法Method对象
                m = cl.getMethod("main", new Class[] { String[].class });
            } catch (NoSuchMethodException ex) {
                throw new RuntimeException(
                        "Missing static main on " + className, ex);
            } catch (SecurityException ex) {
                throw new RuntimeException(
                        "Problem getting static main on " + className, ex);
            }
            //最后通过反射调用android.app.ActivityThread类的静态main方法
            return new MethodAndArgsCaller(m, argv);  
        }
    
    

    ActivityThread.main方法

    ActivityThread的静态main方法中会创建一个ActivityThread实例对象,然后进行初始化,最终进入loop主消息循环来接收系统的消息。

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

    当收到系统发送来的bindapplication的进程间调用时,调用函数handlebindapplication来处理该请求。
    其会先调用Application.attachBaseContext函数,然后调用Application.onCreate函数。所以一个app进程最先执行的就是这两个函数中代码。

    private void handleBindApplication(AppBindData data) {
        //step 1: 创建LoadedApk对象
        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
        ...
        //step 2: 创建ContextImpl对象;
        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
     
        //step 3: 创建Instrumentation
        mInstrumentation = new Instrumentation();
     
        //step 4: 创建Application对象;在makeApplication函数中调用了newApplication,在该函数中又调用了app.attach(context),在attach函数中调用了Application.attachBaseContext函数
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;
     
        //step 5: 安装providers
        List<ProviderInfo> providers = data.providers;
        installContentProviders(app, providers);
     
        //step 6: 执行Application.Create回调
        mInstrumentation.callApplicationOnCreate(app);
    

    注意makeApplication函数用来创建一个Application函数并调用其attachBaseContext函数。

    • 其会先判断第一个参数是否为null,如果不是就直接返回mApplication对象,
    • 如果是false就会判断mApplication是否已经加载,如果已经加载就直接返回,否则就new一个Application并加入到mAllApplications中。(所以在加壳apk中在Application时,创建原apk的Application前要先将mApplication删除并从mAllApplication中移除,然后调用makeApplication并传递null)
     
    public final class LoadedApk {
        public Application makeApplication(boolean forceDefaultAppClass,
                Instrumentation instrumentation) {
            if (mApplication != null) {
                return mApplication;
            }
     
            Application app = null;
            //判断mApplication是否已经加载
            String appClass = mApplicationInfo.className;
            if (forceDefaultAppClass || (appClass == null)) {
                appClass = "android.app.Application";
            }
     
            try {
                java.lang.ClassLoader cl = getClassLoader();
                ....
                app = mActivityThread.mInstrumentation.newApplication(
                        cl, appClass, appContext);
            } catch (Exception e) {
                ....
            }
            mActivityThread.mAllApplications.add(app);
            mApplication = app;
            ....
            return app;
        }
    }
     
    public class Instrumentation {
        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;
        }
    }
     
     
    

    参考:https://bbs.pediy.com/thread-252630.htm

  • 相关阅读:
    2017-2018-2 20179306 《网络攻防技术》第九周作业
    2017-2018-2 20179306 《网络攻防技术》第八周作业
    2017-2018-2 20179306《网络攻防技术》第七周作业
    2017-2018-2 20179306《网络攻防技术》第六周作业
    2017-2018-2 20179306《网络攻防技术》第五周作业
    jcFeather Maya 羽毛插件
    JCFeather 开源
    获取exr图片上像素点的颜色通道
    春天来了,看小夜游!
    jcFeather For Maya 2012免费版
  • 原文地址:https://www.cnblogs.com/revercc/p/16784167.html
Copyright © 2020-2023  润新知