Android 应用程序的启动流程示例详解

目录
  • 应用进程的启动流程
    • 1、ActivityStackSupervisor.startSpecificActivity
    • 2、ATMS.startProcessAsync
    • 3、LocalService.startProcess
    • 4、startProcessLocked函数
    • 5、ProcessList.startProcessLocked
    • 6、ProcessList.startProcessLocked重载
    • 7、ProcessList.startProcess
    • 8、ZygoteState.startViaZygote
    • 9、ZygoteState.openZygoteSocketIfNeeded
    • 10、attemptZygoteSendArgsAndGetResult
    • 11、attemptZygoteSendArgsAndGetResult
    • 12、Zygote.main
    • 13、ZygoteServer.runSelectLoo
    • 14、ZygoteConnection.processOneCommand
    • 15、handleChildProc
    • 16、 ZygoteInit.zygoteInit
    • 17、RuntimeInit.applicationInit
    • 18、RuntimeInit.findStaticMain
    • 19、进程ActivityThread.main。
  • 知识点
  • 疑问点

应用进程的启动流程

本文基于Android 11,主要分析应用程序的启动流程,会直接定位到ActivityStackSupervisor.startSpecificActivity函数开始,因为该函数前面的内容主要在Activity的启动流程中,可以通过这部分的文章来阅读。

看源码流程,需要戒骄戒躁,心态好。配合源码使用,建议先收藏,夜深人静,心血来潮再看。

通过分析应用进程的启动流程,可以得到:

  • 在Framework层,现在不止有AMS负责请求Zygote进程创建新进程,还有ATMS、ActivityStarter、ActivityTaskManger、ActivityTaskS在协助分担一些参数和逻辑的检查。
  • 每个进程都是通过fork Zygote进程而来,且获得Java虚拟机。也就是说每一个应用进程都有自己的虚拟机。
  • 应用进程是通过Soket去请求Zygote进程fork自己的。
  • 每个进程都有自己的Binder线程池用于IPC。
  • 每个应用进程的主线程在ActivityThread,其main函数会创建消息循环机制。

1、ActivityStackSupervisor.startSpecificActivity

ATMS有一个ProcessMap<WindowProcessController>类型的mProcessNames ,用于存储封装了已启动进程信息ProcessRecord和窗口信息Windows的WindowProcessController实例。WindowProcessController用于协调ActivityManger管理ProcessReocrd和WindwManger管理WIndow和Activity的关系。

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    final WindowProcessController wpc =
            mService.getProcessController(r.processName, r.info.applicationInfo.uid);
    boolean knownToBeDead = false;
    if (wpc != null && wpc.hasThread()) {
        realStartActivityLocked(r, wpc, andResume, checkConfig);
        return;
        ...
        knownToBeDead = true;
    }
    r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
    final boolean isTop = andResume && r.isTopRunningActivity();
    mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}

这里的mService是ActivityTaskManagerService的实例,通过getProcessController函数获得当前wpc对象,判断当前启动应用进程是否启动wpc != null && wpc.hasThread(),如果条件成立,则开始真正启动一个未启动过的Activity,通过realStartActivityLocked;条件不成立,则调用mService的startProcessAsync启动当前Activity的所在的进程。即startSpecificActivity函数是启动进程和启动Activity的一个分界点。

2、ATMS.startProcessAsync

PooledLambda.obtainMessage函数是Lambda的调用方式,表示调用ActivityManagerInternal的startProcess函数,后续则是其参数。并返回一个Message对象,发给Handler类型的mH。

void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
        String hostingType) {
    final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
            mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
            isTop, hostingType, activity.intent.getComponent());
    mH.sendMessage(m);
}

抽象类ActivityManagerInternal的继承类定义在ActivityManagerService的内部类LocalService。

public final class LocalService extends ActivityManagerInternal

3、LocalService.startProcess

@Override
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
        boolean isTop, String hostingType, ComponentName hostingName) {
    startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
            new HostingRecord(hostingType, hostingName, isTop),
            ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
            false /* isolated */, true /* keepIfLarge */);
}

4、startProcessLocked函数

final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
            hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
            keepIfLarge, null /* ABI override */, null /* entryPoint */,
            null /* entryPointArgs */, null /* crashHandler */);
}

5、ProcessList.startProcessLocked

ProcessList类的startProcessLocked函数,有几个重载函数,第一个调用。

在 !isolated,判断了启动IntentFlag是否后台运行,是的话,直接拒绝。否则清理AMS中发生过Crash的进程(当前应用)。

分析一:创立当前应用进程的描述ProcessRecord。

判断当前系统是否启动完毕,未启动完毕,将进程信息缓存到AMS的mProcessesOnHold中。

分析二:调用了另外一个重载函数。

    final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
            int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
            boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs,
            Runnable crashHandler) {
        long startTime = SystemClock.uptimeMillis();
        ProcessRecord app;
		//isolated传递进来是false,
        if (!isolated) {
			//从mProcessNames缓存获取,由于是首次创建,null
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            checkSlow(startTime, "startProcess: after getProcessRecord");
			//判断要启动进程是否后台运行,直接return null
            if ((intentFlags &amp; Intent.FLAG_FROM_BACKGROUND) != 0) {
                if (mService.mAppErrors.isBadProcessLocked(info)) {
                    return null;
                }
            } else {
                //重置进程的crash状态,使其处于正常状态
                mService.mAppErrors.resetProcessCrashTimeLocked(info);
                if (mService.mAppErrors.isBadProcessLocked(info)) {
                    mService.mAppErrors.clearBadProcessLocked(info);
                    if (app != null) {
                        app.bad = false;
                    }
                }
            }
        } else {
            app = null;
        }
        ProcessRecord precedence = null;
        if (app != null &amp;&amp; app.pid &gt; 0) {
            if ((!knownToBeDead &amp;&amp; !app.killed) || app.thread == null) {
                app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
                return app;
            }
            ProcessList.killProcessGroup(app.uid, app.pid);
            precedence = app;
            app = null;
        }
        if (app == null) {
			// 分析一、创建新的应用进程描述ProcessRocrd
			//内部会将自己添加到mProcessNames中
			app = newProcessRecordLocked(info, processName, isolated, isolatedUid, hostingRecord);
			if (app == null) {
                return null;
            }
			//此时三者都是null
            app.crashHandler = crashHandler;
            app.isolatedEntryPoint = entryPoint;
            app.isolatedEntryPointArgs = entryPointArgs;
            if (precedence != null) {
                app.mPrecedence = precedence;
                precedence.mSuccessor = app;
            }
        } else {
            app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
        }
        // If the system is not ready yet, then hold off on starting this
        // process until it is.
        if (!mService.mProcessesReady
                &amp;&amp; !mService.isAllowedWhileBooting(info)
                &amp;&amp; !allowWhileBooting) {
            if (!mService.mProcessesOnHold.contains(app)) {
                mService.mProcessesOnHold.add(app);
            }
            if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
                    "System not ready, putting on hold: " + app);
            checkSlow(startTime, "startProcess: returning with proc on hold");
            return app;
        }
		分析二:
        final boolean success =
                startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);
        checkSlow(startTime, "startProcess: done starting proc!");
        return success ? app : null;
    }

6、ProcessList.startProcessLocked重载

再次调用另外一个重载函数。

final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
        int zygotePolicyFlags, String abiOverride) {
    return startProcessLocked(app, hostingRecord, zygotePolicyFlags,
            false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,
            false /* mountExtStorageFull */, abiOverride);
}

重载函数,这个重载函数处理逻辑很长,主要给前面创建的ProcessRecord类型的app设置各种属性。例如外部存储挂载模式,应用进程运行模式,abi架构等等,其中包括最重要一点就是分析一,确定要启动进程的的类名:android.app.ActivityThread。分析二,继续调用重载函数。

    boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
            int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
            boolean mountExtStorageFull, String abiOverride) {
			...
            app.gids = gids;
            app.setRequiredAbi(requiredAbi);
            app.instructionSet = instructionSet;
            final String seInfo = app.info.seInfo
                    + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
            //分析一:确定要启动应用程序的类名
            final String entryPoint = "android.app.ActivityThread";
			//分析二:调用另外一个重载函数
            return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
                    runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
                    instructionSet, invokeWith, startTime);
        } catch (RuntimeException e) {
		  	...
        }
    }

重载函数:也是设置一些属性,然后调用startProcess函数。

 boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
            int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
            ...
            final Process.ProcessStartResult startResult = startProcess(hostingRecord,
                    entryPoint, app,
                    uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
                    requiredAbi, instructionSet, invokeWith, startTime);
            handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                    startSeq, false);
           ...
        }
    }

7、ProcessList.startProcess

ProcessList类的startProcess函数会根据hostingRecord属性mHostingZygote判断走不同的创建分支,前面创建使用默认值,所以走了else分支。通过 Process.start函数创建新的应用进程。

Process.start的一路调用:

Process.start=&gt;ZygoteProcess.start=&gt;ZygoteState.start=&gt;ZygoteState.startViaZygote

8、ZygoteState.startViaZygote

startViaZygote函数,主要是将传递进来的参数拼接成成字符串和收集起来。其中processClass是

private Process.ProcessStartResult startViaZygote(...)
                                                  throws ZygoteStartFailedEx {
        //根据传递进来的参数,拼接成字符串并收集到ArrayList&lt;String&gt;类型argsForZygote
        //将作为新应用程序的主函数的参数
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                          zygotePolicyFlags,
                                          argsForZygote);
}

9、ZygoteState.openZygoteSocketIfNeeded

zygoteSendArgsAndGetResult的第一个参数,调用了openZygoteSocketIfNeeded函数。尝试建立与Socket的连接(如果之前未建立的话)。我们知道Zygote进程在创建的过程,会调用runSelectLoop函数,创建Server端的Socket,一直等待来自AMS的Client端的Socket创建进程请求。

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    try {
    	//建立和Zygote的Socket连接
        attemptConnectionToPrimaryZygote();
		//匹配abi的架构。在Zygote的创建对应四种模式:32,32_64和64,64_32
		//32,64
        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }
		//主要架构模式不配,匹配第二种 32_64,64_32
        if (mZygoteSecondarySocketAddress != null) {
            // The primary zygote didn't match. Try the secondary.
            attemptConnectionToSecondaryZygote();
            if (secondaryZygoteState.matches(abi)) {
                return secondaryZygoteState;
            }
        }
    } catch (IOException ioe) {
        throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
    }
    throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}

attemptConnectionToPrimaryZygote函数主要通过底层的LocalSocket创建与Zygote进程的Socket连接,并获得输入流zygoteInputStream和输出流zygoteOutputWriter。

private void attemptConnectionToPrimaryZygote() throws IOException {
    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        primaryZygoteState =
                ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
        maybeSetApiBlacklistExemptions(primaryZygoteState, false);
        maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
    }
}

和Zygote进程的Server端Socket建立连接后,就是开始往Socket写数据了。

10、attemptZygoteSendArgsAndGetResult

回到第8步调用了zygoteSendArgsAndGetResult函数,又调用了attemptZygoteSendArgsAndGetResult函数。

zygoteSendArgsAndGetResult=&gt;attemptZygoteSendArgsAndGetResult

11、attemptZygoteSendArgsAndGetResult

到这里,通过Socket的方式向Zygote进程写进前面拼接好的参数,Zygote在Server端的Socket接收到数据之后,会执行创建动作。在返回的result.pid>=0表示创建成功,并运行在新的进程。

    private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
            ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
        try {
            final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
            final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
            zygoteWriter.write(msgStr);
            zygoteWriter.flush();
            Process.ProcessStartResult result = new Process.ProcessStartResult();
            result.pid = zygoteInputStream.readInt();
            result.usingWrapper = zygoteInputStream.readBoolean();
            if (result.pid &lt; 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
                    + ex.toString());
            throw new ZygoteStartFailedEx(ex);
        }
    }

12、Zygote.main

在Zygote的启动流程过程,调用了ZygoteInit的main函数,因为Zygote是通过fork自身来创建其他进程,所以需要根据传递进来的参数,进行判断是启动什么类型的进程,例如自身isPrimaryZygote=true,或者SystemServer进程。然后通过ZygoteServer.runSelectLoop函数,等待其他进程请求创建新的进程。

    public static void main(String argv[]) {
        ZygoteServer zygoteServer = null;
        Runnable caller;
        try {
        	...
            boolean startSystemServer = false;
            String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i &lt; argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true; //判断是否SystemServer进程
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                	//SCOKET_NAME_ARG="--socket-name=",根据参数得到SocketName
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
		    //PRIMARY_SOCKET_NAME=zygote
            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
         	gcAndFinalize();
            Zygote.initNativeState(isPrimaryZygote);
            ZygoteHooks.stopZygoteNoThreadCreation();
            zygoteServer = new ZygoteServer(isPrimaryZygote);
            if (startSystemServer) {
            	//启动SystemServer进程
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                if (r != null) {
                    r.run();
                    return;
                }
            }
		   //循环等待AMS来请求创建新的进程
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }
		//调用新的进程主函数
        if (caller != null) {
            caller.run();
        }
    }

13、ZygoteServer.runSelectLoo

这里只关注ZygoteServer.runSelectLoop函数,接受Socket客户端数据。

 /**
     * Runs the zygote process's select loop. Accepts new connections as
     * they happen, and reads commands from connections one spawn-request's
     * worth at a time.
     */
    Runnable runSelectLoop(String abiList) {
        while (true) {
         	...
            ZygoteConnection connection = peers.get(pollIndex);
            final Runnable command = connection.processOneCommand(this);
			...
            if (mIsForkChild) {
                return command;
            }
            ....
   		}
	}

14、ZygoteConnection.processOneCommand

runSelctLoop主要是从循环中检测是否有连接建立,建立之后执行ZygoteConnection的processOneCommand函数,并返回一个Runable类型的command对象。

Runnable processOneCommand(ZygoteServer zygoteServer) {
    ...
    args = Zygote.readArgumentList(mSocketReader);
    //根据参数内容,作其他类型的处理
    ...
    //创建进程,调用底层nativeForkAndSpecialize方法,通过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.mWhitelistedDataInfoList,
            parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
    ...
    if (pid == 0) {
        //设置mIsForkChild=true
        zygoteServer.setForkChild();
       //关闭Socket连接
        zygoteServer.closeServerSocket();
        IoUtils.closeQuietly(serverPipeFd);
        serverPipeFd = null;
       //执行子进程内容
        return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
    }
    ...
}

15、handleChildProc

handleChildProc函数。

private Runnable handleChildProc(ZygoteArguments parsedArgs,
        FileDescriptor pipeFd, boolean isZygote) {
        ...
        if (!isZygote) {
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mDisabledCompatChanges,
                    parsedArgs.mRemainingArgs, null /* classLoader */);
        } else {
            return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mRemainingArgs, null /* classLoader */);
        }
}

16、 ZygoteInit.zygoteInit

public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
        String[] argv, ClassLoader classLoader) {
    RuntimeInit.commonInit();
    ZygoteInit.nativeZygoteInit();//为新进程创建Binder线程池
    return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
            classLoader);
}

以前还以为每个进程共用一个Binder线程池,现在知道每个进程都有自己的Binder线程池进行IPC。

17、RuntimeInit.applicationInit

    protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        final Arguments args = new Arguments(argv);
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

这里的args.startClass就是Socket客户端传递下来的android.app.ActivityThread。

18、RuntimeInit.findStaticMain

RuntimeInit.findStaticMain函数主要通过反射创建ActivityThread类的实例,并反射主函数main,然后封装到MethodAndArgsCaller实例中返回。

protected static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    ...
    Class&lt;?&gt; cl = Class.forName(className, true, classLoader);
    Method m = cl.getMethod("main", new Class[] { String[].class });
    ...
    return new MethodAndArgsCaller(m, argv);
}

MethodAndArgsCaller类继承自Runable,并在其run函数,调用主函数方法。

static class MethodAndArgsCaller implements Runnable {
    /** method to call */
    private final Method mMethod;
    /** argument array */
    private final String[] mArgs;
    public MethodAndArgsCaller(Method method, String[] args) {
        mMethod = method;
        mArgs = args;
    }
    public void run() {
        ...
        mMethod.invoke(null, new Object[] { mArgs });
        ...
    }
}

随着findStaticMain函数方法栈一路返回到runSelectLoop函数,因为mIsForkChild是true,所以MethodAndArgsCaller对象返回到ZygoteInit的main函数,并赋值给caller变量。main函数最后调用caller的run函数。即执行了ActivityThread的主函数main。

本来自己还有个疑惑,fork子进程之后,并caller的run函数,已经退出了Zygote进程的runSelectLoop循环等待。怎么继续去接收AMS新的请求。原来如此,fork子进程后,后续的代码都运行在了子进程,这里return其实是子进程了。

一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

19、进程ActivityThread.main。

public static void main(String[] args) {
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    Looper.loop();
}

ActivityThread的主函数,创建了ActivityThread进程,并启动了消息循环队列,代表着当前进程的主线程已启动。

知识点

  • fork函数。
  • 通过Socket创建新的进程。
  • Binder机制和应用程序创建的时机。
  • ActivityThread的进程的主线程。

疑问点

  • 通过Zygote进程fork而来的子进程都会获得Zygote创建的Java虚拟机,也就是每个应用进程都有自己的Java虚拟机。
  • 每个应用进程都有属于自己的Binder线程池和消息循环机制。
  • 之所以fork Zygote进程而不是init进程,是避免重复初始化环境资源的加载和虚拟机的创建。
  • 进程的创建之所选择Socket机制进行,因为Binder机制会导致死锁,怕父进程binder线程有锁,然后子进程的主线程一直在等其子线程(从父进程拷贝过来的子进程)的资源,但是其实父进程的子进程并没有被拷贝过来,造成死锁,所以fork不允许存在多线程

以上就是Android 应用程序的启动流程示例详解的详细内容,更多关于Android 程序启动流程的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android基准配置文件Baseline Profile方案提升启动速度

    目录 引言 测量工具 生成基准配置文件 验证优化效果 引言 偶然在Youtube上看到一名国外安卓开发者分享了一个提升应用性能的视频,其中使用到了macro benchmark来进行性能测量,包括启动速度和列表帧率,方法是生成一个baseline-prof.txt文件放于app/src/main/下.查阅google的官方文档,其背后原理如下: 通过在应用或库中分发基准配置文件,Android 运行时 (ART) 可以通过预先 (AOT) 编译来优化包含的代码路径,从而针对每位新用户以及每个应用

  • Android10 App启动Activity源码分析

    目录 正文 ActivityThread的main方法 Application Context对象 LaunchActivityItem ClientLifecycleManager ClientTransaction TransactionExecutor executeLifecycleState方法 正文 上一篇: Android 10 App启动分析之进程创建篇(一) 上一篇文章,我们探讨了App启动过程中进程创建及初始化的流程,这篇文章我们接着上篇的内容,继续探讨App的Applica

  • Android Service启动绑定流程详解

    目录 前言 一.Service 的启动流程 二.Service的绑定 三.Service的Context 总结 前言 本文基于Android 11,参考<Android进阶解密>一书资料.了解Service的启动和绑定流程,以及Service的Context创建过程. 由于基于分析流程,忽略很多细节分支.各位在看源码的时候,要尽可能忽略细节,分析整体流程之后,还有精力的话再去看细节.例如有些属性是在后面赋值的,如果在前面追究,难哦. 另:阅读这种流程需要很大的耐心和毅力.建议在心情愉悦想要学习

  • Android framework ATMS启动流程

    目录 1 前言 (1)ATMS 创建流程 (2)ATMS 初始化 2 ATMS 启动流程 (1)main (2)run (3)startBootstrapServices (4)startService (5)ATMS.Lifecycle 3 ATMS 初始化 (1)ATMS 的构造方法 (2)start (3)initialize (4)onActivityManagerInternalAdded (5)ActivityStartController (6)DefaultFactory 1 前

  • 详解Android广播Broadcast的启动流程

    目录 正文 广播的注册 广播的解注册 广播的发送 总结 正文 本文整体阅读下来相对Activity和Service的启动流程较容易,比较贴近我们日常代码开发习惯.我们曾经有个整机项目,多个APP跨进程交互,本来想采用AIDL进行的,但最终考虑到项目工期和其他同事的能力,最终在采用广播方式进行IPC. 那时,自己也在想,这么多个APP相互发信息,数据量也大,对整机性能有影响么?会不会存在丢失和内存问题.一脸茫然,网上也不会有类似信息告诉总结这种情况,本文也不会总结这个答案,因为看完之后心中自然有数

  • Android开发InputManagerService创建与启动流程

    目录 前言 启动流程 创建输入系统 启动输入系统 输入系统就绪 结束 前言 之前写过几篇关于输入系统的文章,但是还没有写完,后来由于工作的变动,这个事情就一直耽搁了.而现在,在工作中,遇到输入系统相关的事情也越来越多,其中有一个非常有意思的需求,因此是时候继续分析 InputManagerService. InputManagerService 系统文章,基于 Android 12 进行分析. 本文将以 IMS 简称 InputManagerService. 启动流程 InputManagerS

  • Android10 App 启动分析进程创建源码解析

    目录 正文 RootActivityContainer ActivityStartController 调用startActivityUnchecked方法 ActivityStackSupervisor 启动进程 RuntimeInit.applicationInit这个方法 正文 从前文# Android 10 启动分析之SystemServer篇 (四)中可以得知,系统在完成所有的初始化工作后,会通过 mAtmInternal.startHomeOnAllDisplays(currentU

  • Android 应用程序的启动流程示例详解

    目录 应用进程的启动流程 1.ActivityStackSupervisor.startSpecificActivity 2.ATMS.startProcessAsync 3.LocalService.startProcess 4.startProcessLocked函数 5.ProcessList.startProcessLocked 6.ProcessList.startProcessLocked重载 7.ProcessList.startProcess 8.ZygoteState.star

  • Tomcat启动核心流程示例详解

    目录 一.Tomcat的启动核心流程 1.启动的入口 2.init方法 3.load方法 4.start方法 5.核心流程的总结 一.Tomcat的启动核心流程 前面给大家介绍了Tomcat中的生命周期的设计,掌握了这块对于我们分析Tomcat的核心流程是非常有帮助的,也就是我们需要创建相关的核心组件,比如Server,Service肯定都绕不开生命周期的方法. 1.启动的入口 你可以通过脚本来启动Tomcat服务(startup.bat),但如果你看过脚本的命令,你会发现最终调用的还是Boot

  • Android车载多媒体开发MediaSession框架示例详解

    目录 一.多媒体应用架构 1.1 音视频传统应用架构 1.2 MediaSession 框架 媒体会话 媒体控制器 二.MediaSession 2.1 概述 2.2 MediaBrowser 2.2.1 MediaBrowser.ConnectionCallback 2.2.2 MediaBrowser.ItemCallback 2.2.3 MediaBrowser.MediaItem 2.2.4 MediaBrowser.SubscriptionCallback 2.3 MediaContr

  • Android 动态加载 so实现示例详解

    目录 背景 so动态加载介绍 从一个例子出发 so库检索与删除 动态加载so 结束了吗? ELF文件 扩展 总结 背景 对于一个普通的android应用来说,so库的占比通常都是巨高不下的,因为我们无可避免的在开发中遇到各种各样需要用到native的需求,所以so库的动态化可以减少极大的包体积,自从2020腾讯的bugly团队发部关于动态化so的相关文章后,已经过去两年了,相关文章,经过两年的考验,实际上so动态加载也是非常成熟的一项技术了. 但是很遗憾,许多公司都还没有这方面的涉略又或者说不知

  • 网络安全渗透测试小程序抓包流程步骤详解

    目录 小程序测试流程 搜索目标小程序 小程序主体信息确认 小程序包获取 PC端 windows端获取小程序包流程 移动端 解包 调试 抓包 小程序测试流程 分为两个方面,解包可以挖掘信息泄露问题.隐藏的接口,抓包可以测试一些逻辑漏洞.API安全问题.两者结合起来就可以边调试边进行测试,更方便于安全测试. 搜索目标小程序 目标搜索不能仅仅局限于主体单位,支撑单位.供应商.全资子公司等都可能是入口点,所以小程序当然也不能放过它们. 小程序主体信息确认 查看小程序账号主体信息,否则打偏了花费了时间不说

  • springboot2.2 集成 activity6实现请假完整流程示例详解

    新手学习记录.写在springboot test 示例  示例代码地址看结尾.后面有带页面的示例. SpringBoot Test无页面简单示例 员工请假流程 员工发起申请,附带请假信息(请假几天) 单位领导审批,如果通过,交付经理审批,不通过,重新申请 经理审批,如果请假天数不超过三天,经理1审批 如果请假天数在3-5天,经理3审批 超过5天,经理2审批 经理审批通过,流程结束,经理审批不通过,员工重新申请 流程图 代码 activiti.cfg.xml为必须文件且数据库连接正确,否则Proc

  • Android Flutter实现3D动画效果示例详解

    目录 前言 AnimatedWidget 简介 3D 旋转动画的实现 总结 前言 上一篇我们介绍了 Animation 和 AnimationController 的使用,这是最基本的动画构建类.但是,如果我们想构建一个可复用的动画组件,通过外部参数来控制其动画效果的时候,上一篇的方法就不太合适了.在 Flutter 中提供了 AnimatedWidget 组件用于构建可复用的动画组件.本篇我们用 AnimatedWidget 来实现组件的3D 旋转效果,如下图所示. AnimatedWidge

  • springboot2.2 集成 activity6实现请假流程(示例详解)

    新手学习记录.写在springboot test 示例  示例代码地址看结尾.后面有带页面的示例. SpringBoot Test无页面简单示例 员工请假流程 员工发起申请,附带请假信息(请假几天) 单位领导审批,如果通过,交付经理审批,不通过,重新申请 经理审批,如果请假天数不超过三天,经理1审批 如果请假天数在3-5天,经理3审批 超过5天,经理2审批 经理审批通过,流程结束,经理审批不通过,员工重新申请 流程图 代码 activiti.cfg.xml为必须文件且数据库连接正确,否则Proc

  • python程序的打包分发示例详解

    目录 引言 python程序打包 __init__.py文件的作用 构建python包 生成分发包 本地安装 调用 引言 python编程时,一部分人习惯将实现同一个功能的代码放在同一个文件: 使用这些代码只需要import就可以了: 下面看一个例子. testModel.py class Test: name = 'tom' age = 0 __weight = 0 def __init__(self,n,a,w): self.name = n self.age = a self.__weig

  • Android开发Kotlin实现圆弧计步器示例详解

    目录 效果图 定义控件的样式 自定义StepView 绘制文本坐标 Android获取中线到基线距离 效果图 定义控件的样式 看完效果后,我们先定义控件的样式 <!-- 自定义View的名字 StepView --> <!-- name 属性名称 format 格式 string 文字 color 颜色 dimension 字体大小 integer 数字 reference 资源或者颜色 --> <declare-styleable name="StepView&q

随机推荐