• Process.getStartElapsedRealTime时机

    时序总览图:

熬了3天3夜,做了6年Android开发

Process.getStartElapsedRealTime的赋值接口为handleBindApplication接口,赋值时机为App进程进入Java世界后,进程attach到ActivityManagerService,再通过binder call返回到App进程时。原理细节可继续阅读源码解析。

源码解析:

Android 8.1.0的源码中一段说明(Process.java):
487    /**
488     * Return the {@link SystemClock#elapsedRealtime()} at which this process was started.
489     */
490    public static final long getStartElapsedRealtime() {
491        return sStartElapsedRealtime;
492    }

从源码的说明中可知,Process.getStartElapsedRealTime代表程序创建开始的时间,
SystemClock#elapsedRealtime表示距离boot的真实时间,看下其赋值时机(ActivityThread.java):
5429    private void handleBindApplication(AppBindData data) {...
5436        // Note when this process has started.
5437        Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());

handleBindApplication是在ActivityThread主线程H的消息处理中被调用的,
H作为ActivityThread的内部类,是主线程处理消息的Handler。
234    final H mH = new H();

 这个消息是谁发的,什么时候发的呢?了解Android App的入口函数及创建过程的同学,可能不难解答这个问题。
App的创建,Java层调用的入口为ActivityThread main方法,看下:
6459    public static void main(String[] args) {...
6478        Looper.prepareMainLooper();
6479
6480        ActivityThread thread = new ActivityThread();
6481        thread.attach(false);...
6494        Looper.loop();

 从代码中看,main方法中主要是准备主线程消息Looper,执行ActivityThread attach方法,然后主线程开始消息循环。
看下ActivityThread attach:
6315    private void attach(boolean system) {
6318        if (!system) {
6328            final IActivityManager mgr = ActivityManager.getService();
6329            try {
6330                mgr.attachApplication(mAppThread);
6331            } catch (RemoteException ex) {
6332                throw ex.rethrowFromSystemServer();
6333            }

 从代码可知,此处有binder调用,调用AMS的attachApplication,此调用是在system_server进程,执行如下操作。
看下ActivityManagerService处理过程:
7215    public final void attachApplication(IApplicationThread thread) {
7216        synchronized (this) {
7219            attachApplicationLocked(thread, callingPid);
7221        }
7222    }
6911    private final boolean attachApplicationLocked(IApplicationThread thread,
6912            int pid) {…
7102                thread.bindApplication(processName, appInfo, providers,
7103                        app.instr.mClass,
7104                        profilerInfo, app.instr.mArguments,
7105                        app.instr.mWatcher,
7106                        app.instr.mUiAutomationConnection, testMode,
7107                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
7108                        isRestrictedBackupMode || !normalMode, app.persistent,
7109                        new Configuration(getGlobalConfiguration()), app.compat,
7110                        getCommonServicesLocked(app.isolated),
7111                        mCoreSettingsObserver.getCoreSettingsLocked(),
7112                        buildSerial);

 比较关键的调用:thread.bindApplication, thread是Binder对象,这个地方又有binder调用,看看执行者:
690    private class ApplicationThread extends IApplicationThread.Stub {
899        public final void bindApplication(String processName, ApplicationInfo appInfo,
900                List<ProviderInfo> providers, ComponentName instrumentationName,
901                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
902                IInstrumentationWatcher instrumentationWatcher,
903                IUiAutomationConnection instrumentationUiConnection, int debugMode,
904                boolean enableBinderTracking, boolean trackAllocation,
905                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
906                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
907                String buildSerial)
A 
pplicationThread执行sendMessage(H.BIND_APPLICATION, data);

将消息发送出去,此部分的执行为App进程的binder线程池里,是如何切换至主线程执行的呢?
2605    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
2609        Message msg = Message.obtain();...
2617        mH.sendMessage(msg);
2618    }  

 通过mH,将消息发送到主线程的Looper,主线程执行,
1462    private class H extends Handler {
1473        public static final int BIND_APPLICATION = 110;
1580        public void handleMessage(Message msg) {
1653                case BIND_APPLICATION:
1656                    handleBindApplication(data);
1658                    break;

handleBindApplication就是Process.getStartElapsedRealTime获取对进程创建的起点,后续逻辑就是Application的初始化的工作,由此可见Process.getStartElapsedRealTime时机是比Application<init style="box-sizing: border-box;">时机早,在Application构造方法中打断点情况如下:
熬了3天3夜,做了6年Android开发

/proc/self/stats starttime时机

/proc/self/stats starttime时机是kernel层记录的进程创建起点,为3个时机中最早的。详细看下:

proc/pid/stat用于获取某一个进程的统计信息,内容形式如下:

熬了3天3夜,做了6年Android开发

在proc/pid/stat统计信息中,starttime为第22个元素。starttime的值什么含义,以及是如何计算出来的呢?看下fs/proc/array.c的do_task_stat()

熬了3天3夜,做了6年Android开发

从内核代码中可知:start_time取值为task的real_start_time,先看下nesc_to_clock_t方法:

熬了3天3夜,做了6年Android开发

熬了3天3夜,做了6年Android开发

熬了3天3夜,做了6年Android开发

熬了3天3夜,做了6年Android开发

div_u64_rem方法为无符号除法操作:除数是无符号64bit,被除数是无符号32,remainder为余数。

从计算过程来看,是把real_start_time除以1000000000/100=10000000,real_start_time单位是什么呢?看下数据结构task_struct定义:


    struct timespec start_time;      
    struct timespec real_start_time;