美文网首页
app的启动流程

app的启动流程

作者: 崽子猪 | 来源:发表于2019-05-20 19:51 被阅读0次

一.首先启动一个App(在laucher点击一个应用图标) 一个App的启动入口就是这个ActivityThread 实际就是启动一个主线程搞事情

  ActivityThread方法有一个main方法,就是程序的入口 在里面搞了些什么事情呢

public static void main(String[] args) {

        ....

      //这一堆是初始化了系统目录等一些东西,从Environment类就可以看出来主要干什么

        Environment.initForCurrentUser();

        EventLogger.setReporter(new EventLoggingReporter());

        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());

        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        ...

        //初始化化主线程的Looper

        Looper.prepareMainLooper();

        //绑定线程

        ActivityThread thread = new ActivityThread();

        thread.attach(false);

        //主线程处理消息的Handler

        if (sMainThreadHandler == null) {

            sMainThreadHandler = thread.getHandler();

        }

        ...

        //开启Looper进行无线循环处理

        Looper.loop();

        ...

    }

  二.如何启动呢?

    在主线程初始化一个Looper,然后创建一系列的消息指令放到消息队列,开启Looper循环进行处理,复杂的地方全在thread.attach这个步骤里.

    我们知道平时使用Handler的时候是不需要创建Looper(UI线程使用),其实就是为了在这个地方进行了初始化,点击prepareMainLooper这个方法,我们发现这里首先调用了prepare方法,直接调用myLooper方法为主线程Looper进行了赋值

public static void prepareMainLooper() {

      prepare(false);

      synchronized (Looper.class) {

            if (sMainLooper != null) {

              throw new IllegalStateException("The main Looper has already been prepared.");

          }

            sMainLooper = myLooper();

            }

    }

  三.mylooper()和prepare()方法都做了什么?

  1.prepare():在这个方法里发现了一个ThreadLocal,ThreadLocal是一个线程安全的包装机制

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

      }

Looper中保存着一个ThreadLocal,首先通过ThreadLocal.get去获取Looper,如果获取到了那么就说明不对头,抛出异常(一个线程只能有一个Looper,如果没有那么就为ThreadLocal设置一个Looper进去)

// sThreadLocal.get() will return null unless you've called prepare().

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

Looper的构造函数,挣了一个消息队列,然后保存当前这个调用他的线程

private Looper(boolean quitAllowed) {

          mQueue = new MessageQueue(quitAllowed);

          mThread = Thread.currentThread();

    }

  2.mylooper():其实就是去获取一下当前线程的looper

public static @Nullable Looper myLooper() {

            return sThreadLocal.get();

    }

      再看get方法,这个threadLocal存放着一个map来保存looper,调用get的时候回根据线程来获取相应的looper,所以主线程的Looper以及平时可能会在子线程中调用的Looper都被存放到这个map中了.

public T get() {

          Thread t = Thread.currentThread();

        ThreadLocalMap map = getMap(t);

          if (map != null) {

            ThreadLocalMap.Entry e = map.getEntry(this);

            if (e != null) {

                  @SuppressWarnings("unchecked")

                  T result = (T)e.value;

                  return result;

                }

            }

            return setInitialValue();

    }

-----------------------上面的代码大体可以看出来做了一个绑定applaction的操作-----------------------

    public static IActivityManager getService() {

          return IActivityManagerSingleton.get();

    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =

            new Singleton<IActivityManager>() {

                @Override

                protected IActivityManager create() {

                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);

                    final IActivityManager am = IActivityManager.Stub.asInterface(b);

                    return am;

                }

          };

  ServiceManager.getService方法会经过ServiceManagerNative类的一个内部类代理去获取AMS,最终获取到这个类ActivityManagerService

下一步会调用mgr.attachApplication(mAppThread)这个东西,去AMS中找一下这个方法看看有没有

    @Override

    public final void attachApplication(IApplicationThread thread) {

        synchronized (this) {

            int callingPid = Binder.getCallingPid();

            final long origId = Binder.clearCallingIdentity();

            attachApplicationLocked(thread, callingPid);

            Binder.restoreCallingIdentity(origId);

        }

    }

    找到上面代码中的一个方法,获取了一下进程,清楚了一下进程的调用标记

private final boolean attachApplicationLocked(IApplicationThread thread,

            int pid) {

if (app.instr != null) {

                thread.bindApplication(processName, appInfo, providers,

                        app.instr.mClass,

                        profilerInfo, app.instr.mArguments,

                        app.instr.mWatcher,

                        app.instr.mUiAutomationConnection, testMode,

                        mBinderTransactionTrackingEnabled, enableTrackAllocation,

                        isRestrictedBackupMode || !normalMode, app.persistent,

                        new Configuration(getGlobalConfiguration()), app.compat,

                        getCommonServicesLocked(app.isolated),

                        mCoreSettingsObserver.getCoreSettingsLocked(),

                        buildSerial);

            } else {

                thread.bindApplication(processName, appInfo, providers, null, profilerInfo,

                        null, null, null, testMode,

                        mBinderTransactionTrackingEnabled, enableTrackAllocation,

                        isRestrictedBackupMode || !normalMode, app.persistent,

                        new Configuration(getGlobalConfiguration()), app.compat,

                        getCommonServicesLocked(app.isolated),

                        mCoreSettingsObserver.getCoreSettingsLocked(),

                        buildSerial);

            }

}

中间着部分代码的前半段做了一些进程的相关操作,后半段做了一些安全的验证检查下这个进程中是否还遗留一些activity,广播什么的主要看中间代码

IApplicationThread,发现这个是个ActivityThread的内部类,并且作为一个final常量被使用,在这个方法中调用了IApplicationThread的bindApplication方法发送了一个消息,去绑定applaction,并把相关的包信息啊什么的传过去,反正经过饶了AMS一圈还是回到了activityThread来处理...

public final void bindApplication(String processName, ApplicationInfo appInfo,

                List<ProviderInfo> providers, 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) {

            if (services != null) {

                // Setup the service cache in the ServiceManager

                ServiceManager.initServiceCache(services);

            }

            setCoreSettings(coreSettings);

            AppBindData data = new AppBindData();

            data.processName = processName;

            data.appInfo = appInfo;

            data.providers = providers;

            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;

            sendMessage(H.BIND_APPLICATION, data);

        }

然后我们找一下handler是怎们处理的,这个方法也比较长,大部分代码为进行一些启动app前的配置操作,比如配置时区啊等等一些根据data的内容进行的,所以我们删除一些不重要的,慢慢看,留下几个看起来有用的代码

private void handleBindApplication(AppBindData data) {

  // 将UI线程注册为敏感线程

        VMRuntime.registerSensitiveThread();

        if (data.trackAllocation) {

            DdmVmInternal.enableRecentAllocations(true);

        }

    ...

    mInstrumentation = (Instrumentation)

        cl.loadClass(data.instrumentationName.getClassName())

        .newInstance();

    //通过反射初始化一个Instrumentation仪表。

    ...

    Application app = data.info.makeApplication(data.restrictedBackupMode, null);

    //通过LoadedApp命令创建Application实例

    mInitialApplication = app;

    ...

    mInstrumentation.callApplicationOnCreate(app);

    //让仪器调用Application的onCreate()方法

    ...

}

发现mInstrumentation的调用了applaction的onCreat方法,只是简单的调用了一下 app.onCreate(),

public void callApplicationOnCreate(Application app) {

        app.onCreate();

    }

我们先看mInstrumentation这个是什么?

Android instrumentation是Android系统里面的一套控制方法或者”钩子“。这些钩子可以在正常的生命周期(正常是由操作系统控制的)之外控制Android控件的运行,其实指的就是Instrumentation类提供的各种流程控制方法.

然后我们继续发现callApplicationOnCreate要一个app参数,这个app是从哪里来的?继续像上看代码发现app产自这么一个方法makeApplication()

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 {

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

            }

            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

            app = mActivityThread.mInstrumentation.newApplication(

                    cl, appClass, appContext);

...........

}

发现是由一个叫LoadedApk的类去执行的,这个类是维护这本地已经加载的apk

如果有这个app就直接返回,没有就用反射创建一个,创建过程又交给了仪表盘mInstrumentation

static public Application newApplication(Class<?> clazz, Context context)

            throws InstantiationException, IllegalAccessException,

            ClassNotFoundException {

        Application app = (Application)clazz.newInstance();

        app.attach(context);

        return app;

    }

简单的反射创建了applaction

然后就是Application初始化完毕之后会给主线程的handler发送一个启动activity的消息,最终会走这么一个方法

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {

      创建一个activty

      Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {

            r.createdConfig = new Configuration(mConfiguration);

            reportSizeConfigurations(r);

            Bundle oldState = r.state;

            handleResumeActivity(r.token, false, r.isForward,

                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

}

首先调用performLaunchActivity方法创建一个activity,然后就可以handleResumeActivity,就是可以走onResume方法了

performLaunchActivity方法():

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

.....

activity = mInstrumentation.newActivity(

                    cl, component.getClassName(), r.intent);

.....

Application app = r.packageInfo.makeApplication(false, mInstrumentation);

.....

  activity.attach(appContext, this, getInstrumentation(), r.token,

                        r.ident, app, r.intent, r.activityInfo, title, r.parent,

                        r.embeddedID, r.lastNonConfigurationInstances, config,

....

  if (r.isPersistable()) {

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

                } else {

                    mInstrumentation.callActivityOnCreate(activity, r.state);

                }

....

}

发现任然是由仪表盘去创建的这个activity,然后做一个attach操作绑定界面,然后就是一些流程控制的操作,callActivityOnCreate,就可以执行activity的oncreat方法了...最后返回一个activity.

mInstrumentation.newActivity来创建activity其实就是一个反射区创建,很简单

基本走到handleResumeActivity方法

一个app的启动并展示第一个界面的过程就完成了

相关文章

网友评论

      本文标题:app的启动流程

      本文链接:https://www.haomeiwen.com/subject/bpulzqtx.html