Android 6.0 Launcher 启动 Activity 过程源码分析(一)

目录

技术答疑,成长进阶,可以加入我的知识星球:音视频领域专业问答的小圈子

当 Android 系统在启动时,会扫描系统特定目录,然后自动安装里面的 Android 应用程序。当系统启动完成之后,会启动一个 Home 应用程序来显示安装在系统中的 Android 应用程序。

这个应用程序就是 Launcher 应用,也就是手机屏幕上显示的各种应用图标,Launcher 是 Android 系统启动的第一个应用程序。

而当我们点击应用程序图标时,也就开启了从 Launcher 启动 Activity 的过程。

过程概述

Activity 其实也还是 Java 里的一个类,但是在 Android 开发中可不能把它当做一个普通类来处理,它可是 Android 四大组件之一。

Activity 的启动是由 ActivityManagerService 来完成的,由于 Launcher 组件、Activity 组件、ActivityManagerService 组件分别是运行在三个不同的进程中的,这三个进程的通信是通过 Binder 进程间通信机制来完成。

Launcher 组件通过 ServiceManager 得到 ActivityManagerService 的代理对象 Binder ,通过它向 ActivityManagerService 发起进程间通信请求,同时把自己应用程序进程(ActivityThread)的 Binder 对象(ApplicationThread)传递给 ActivityManagerService,以便 ActivityManagerService 调用 Launcher 组件的方法。这样就形成了一个有来有去的双方通信机制。

Launcher 组件启动 Activity 的过程大致如下所示:

  1. Launcher 组件向 ActivityManagerService 组件发送一个启动 Activity 组件的进程间通信请求。 2ActivityManagerService 首先将要启动的 Activity 组件的信息保存下来,然后再向 Launcher 组件发送一个进入中止状态(onPause 方法)的进程间通信请求。
  2. Launcher 组件进入到中止状态(onPause 方法)之后,就会向 ActivityManagerService 发送一个已进入中止状态的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 Activity 组件的操作。
  3. ActivityManagerService 会检查当前 Activity 组件的应用程序进程是否存在,如果不存在,则会通过 Binder 进程间通信机制来请求 Zygote 进程将当前应用程序进程启动起来。
  4. 新的应用程序进程启动完毕后,就会向 ActivityManagerService 发送一个启动完成的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 Activity 组件的操作。
  5. ActivityManagerService 将第二步保留的 Activity 组件的信息发送给第四步创建的应用程序进程,以便它可以将 Activity 组件启动起来。

代码过程分析

Launcher 类的 startActivitySafely() 方法

Launcher 毕竟是一个系统应用,它的源代码位于 packages/apps/Launcher2/src/com/android/launcher2/Launcher.java

1/**
2 * Default launcher application.
3 */
4public final class Launcher extends Activity
5        implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, View.OnTouchListener {
JAVA

从代码中可以看到 Launcher 继承自 Activity,并且实现了点击、长按、触摸等接口。

所以在onClick方法中就能找到启动 Activity 组件的调用方法 startActivitySafely。其中Intent参数包含了相应的信息。

 1 boolean startActivitySafely(View v, Intent intent, Object tag) {
 2        boolean success = false;
 3        try {
 4	        // 调用 Launcher 类的 startActivity 函数,不是 Activity 里面的,参数形式不对。
 5            success = startActivity(v, intent, tag);
 6        } catch (ActivityNotFoundException e) {
 7            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
 8            Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
 9        }
10        return success;
11    }
JAVA

startActivitySafely函数又调用了 Launcher 里面封装的 startActivity(View view, Intent intent, Object tag)

Launcher 类的 startActivity() 方法

 1 boolean startActivity(View v, Intent intent, Object tag) {
 2        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 3        try {
 4            // Only launch using the new animation if the shortcut has not opted out (this is a
 5            // private contract between launcher and may be ignored in the future).
 6            boolean useLaunchAnimation = (v != null) &&  
 7                    !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
 8            // 安卓多用户相关 UserHandle 
 9            UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
10            LauncherApps launcherApps = (LauncherApps) // 
11                    this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
12            if (useLaunchAnimation) {  // 是否使用启动动画
13                ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
14                        v.getMeasuredWidth(), v.getMeasuredHeight());
15                if (user == null || user.equals(android.os.Process.myUserHandle())) {
16                    // Could be launching some bookkeeping activity
17                    startActivity(intent, opts.toBundle()); // 使用动画,启动Activity
18                } else {
19                    launcherApps.startMainActivity(intent.getComponent(), user,
20                            intent.getSourceBounds(),
21                            opts.toBundle());
22                }
23            } else {
24                if (user == null || user.equals(android.os.Process.myUserHandle())) {
25                    startActivity(intent);
26                } else {
27                    launcherApps.startMainActivity(intent.getComponent(), user,
28                            intent.getSourceBounds(), null);
29                }
30            }
31            return true;
32        } catch (SecurityException e) {
33            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
34        }
35        return false;
36    }
JAVA

由于启动的 Activity 和 Launcher 组件不在同一进程,则在 Intent 上添加了 FLAG_ACTIVITY_NEW_TASK的 Flag 启动标识,以便可以在新的 TASK中启动。

启动时会判断当前 Activity 组件是否使用动画效果。并且,Android 中还有 LAUNCHER_APPS_SERVICE 这样一个 Service 用来启动 Activity 组件。

这里,假设没有动画,并且 user == null 的 if 判断成立,则直接调用父类 Activity 的 startActivity(Intent intent)方法。

1@Override
2    public void startActivity(Intent intent) {
3        this.startActivity(intent, null);
4    }
JAVA

最终调用了父类 Activity 的startActivity(Intent intent, @Nullable Bundle options)方法。

1 @Override
2    public void startActivity(Intent intent, @Nullable Bundle options) {
3        if (options != null) {
4            startActivityForResult(intent, -1, options);
5        } else {
6            startActivityForResult(intent, -1); // 方法内调用的也是上一种方法形式,只是 options 为 null 
7        }
8    }
JAVA

Activity 类的 startActivityForResult() 方法

由于之前假设的 options 参数为 null,则直接调用startActivityForResult(intent, -1),方法原型如下:

1public void startActivityForResult(Intent intent, int requestCode) {
2        startActivityForResult(intent, requestCode, null);
3    }
JAVA

这里面调用的也是startActivityForResult,只不过第三个参数为 null 了,也就是上面的 options 参数。 只有当请求码 requestCode >=0,才会执行调用者的 onActivityResult()方法,这里为 -1 ,不会。

 1public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
 2        if (mParent == null) {
 3            Instrumentation.ActivityResult ar =
 4                mInstrumentation.execStartActivity(
 5                    this, mMainThread.getApplicationThread(), mToken, this,
 6                    intent, requestCode, options);
 7            if (ar != null) {
 8                mMainThread.sendActivityResult(
 9                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
10                    ar.getResultData());
11            }
12            if (requestCode >= 0) {
13                mStartedActivity = true;
14            }
15            cancelInputsAndStartExitTransition(options);
16        } else {
17			// 由于第一次从 Launcher 启动 Activity ,mParent 为 null 。
18        }
19    }
JAVA

在 if 判断里面执行了 Instrumentation 类的execStartActivity方法。

Instrumentation 类会在应用的任何代码执行前被实列化,是用来监控应用程序和系统之间的交互操作。

方法原型为:

1    public ActivityResult execStartActivity(
2            Context who, IBinder contextThread, IBinder token, Activity target,
3            Intent intent, int requestCode, Bundle options) {
JAVA

这里比较重要的就是里面传入的参数了,之前的参数都是 Intent 附带的 Activity 组件的信息。

一一对应如下:

参数类型 实际参数 含义
Context who this Context 类
IBinder contextThread mMainThread.getApplicationThread() 自己的Binder本地对象
IBinder token mToken ActivityManagerService 中的ActivityRecord 代理对象
Activity target this 目标
Intent intent intent 组件信息
int requestCode requestCode 请求码
Bundle options options 附件信息

其中,options、requestCode、intent、who 参数都比较好理解。

而 contextThread 参数是一个 IBinder 类型,实际参数为mMainThread.getApplicationThread()

其实 mMainThread 的类型为 ActivityThread,用来描述一个应用程序进程,它并不是一个线程,是一个 final 类型的类。

系统每当启动一个应用程序进程时,都会在它里面加载一个 ActivityThread类实例,并且将这个 ActivityThread类实例保存在每一个在该进程启动的 Activity 组件的父类 Activity 的成员变量 mMainThread中。

ActivityThread类的成员函数getApplicationThread()用来获取它内部的一个类型为ApplicationThreadBinder本地对象

1private class ApplicationThread extends ApplicationThreadNative {}
2public abstract class ApplicationThreadNative extends Binder implements IApplicationThread {}
JAVA

ApplicationThread类是一个 Binder 类,那么它的作用是用来与 ActivityManagerService 通信的。

之前在 Binder 学习的时候,bindService 操作会在 onServiceConnected 返回 Service 的一个 Binder 对象,通过该 Binder 对象便可以执行 Service 中的函数,此时便完成的了 Activity 与 Service 的通信。而现在,我们在 execStartActivity() 方法中把自己的 Binder 对象传递给 ActivityManagerService,不就是相当于 onServiceConnected 中回调 Binder 了嘛。有了这个 Binder 对象,ActivityManagerService 才能够通知 Launcher 组件进入 Paused 状态。

mToken类也是一个 Binder 类型,它是一个 Binder代理对象,它指向了 ActivityManagerService 中一个类型为 ActivityRecordBinder本地对象。每一个已经启动的 Activity 组件在 ActivityManagerService 中都有一个对应的ActivityRecord对象,用来维护对应的 Activity 组件的运行状态。将它传递给 ActivityManagerService,以便 ActivityManagerService 获得 Launcher 组件的详细信息了。

Instrumentation 类的 execStartActivity() 方法

 1    public ActivityResult execStartActivity(
 2            Context who, IBinder contextThread, IBinder token, Activity target,
 3            Intent intent, int requestCode, Bundle options) {
 4        IApplicationThread whoThread = (IApplicationThread) contextThread;
 5		// 省略部分代码
 6        try {
 7            intent.migrateExtraStreamToClipData();
 8            intent.prepareToLeaveProcess();
 9            int result = ActivityManagerNative.getDefault()
10                .startActivity(whoThread, who.getBasePackageName(), intent,
11                        intent.resolveTypeIfNeeded(who.getContentResolver()),
12                        token, target != null ? target.mEmbeddedID : null,
13                        requestCode, 0, null, options);
14            checkStartActivityResult(result, intent);
15        } catch (RemoteException e) {
16            throw new RuntimeException("Failure from system", e);
17        }
18        return null;
19    }
JAVA

Intent 执行了一些准备工作后,便调用 ActivityManagerService 的代理对象的 startActivity方法了。

ActivityManagerNative.getDefault() 方法返回的就是 ActivityManagerService 的代理对象,代理对象的获取在之前 Binder 学习的文章中已经了解过了。

 1public abstract class ActivityManagerNative extends Binder implements IActivityManager{
 2
 3	static public IActivityManager asInterface(IBinder obj) {
 4        if (obj == null) {
 5            return null;
 6        }
 7        IActivityManager in =
 8            (IActivityManager)obj.queryLocalInterface(descriptor);
 9        if (in != null) {
10            return in;
11        }
12
13        return new ActivityManagerProxy(obj);
14    }
15    
16	static public IActivityManager getDefault() {
17        return gDefault.get();
18    }
19	
20	private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
21        protected IActivityManager create() {
22        // 通过 ServiceManager 来获得 ActivityServiceManager 的代理对象。
23        // 再通过 asInterface 方法判断是否为同一进程,不是,则封装成 ActivityManagerProxy 代理对象。
24        // ActivityManagerProxy 代理对象的操作都是由 ActivityServiceManager 的代理对象 Binder 来完成的。
25        // ActivityManagerProxy 只是在之上对数据封装了一层。
26            IBinder b = ServiceManager.getService("activity");
27            if (false) {
28                Log.v("ActivityManager", "default service binder = " + b);
29            }
30            IActivityManager am = asInterface(b);
31            if (false) {
32                Log.v("ActivityManager", "default service = " + am);
33            }
34            return am;
35        }
36    };
37}
JAVA

在 ActivityManagerNative 中还看到了一个有意思的单例写法:

 1public abstract class Singleton<T> {
 2    private T mInstance;
 3    protected abstract T create();
 4    public final T get() {
 5        synchronized (this) {
 6            if (mInstance == null) {
 7                mInstance = create();
 8            }
 9            return mInstance;
10        }
11    }
12}
JAVA

ActivityManagerProxy 类的 startActivity() 方法

Instrumentation 类的 execStartActivity() 方法最终调用了ActivityManagerProxy 类的 startActivity() 方法,由 ActivityManagerService 的代理对象 Binder 去发起类型为 START_ACTIVITY_TRANSACTION 的进程间通信请求。参数信息如注释所示:

 1    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
 2            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
 3            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
 4        Parcel data = Parcel.obtain();
 5        Parcel reply = Parcel.obtain();
 6        data.writeInterfaceToken(IActivityManager.descriptor);
 7        // caller 参数为 Launcher 组件所运行的应用程序进程的 ApplicationThread Binder 本地对象。
 8        data.writeStrongBinder(caller != null ? caller.asBinder() : null); 
 9        // Launcher 组件的包名
10        data.writeString(callingPackage);
11        // 需要启动的 Activity 组件的信息
12        intent.writeToParcel(data, 0);
13        data.writeString(resolvedType);
14        // ActivityManagerService 内部的 ActivityRecord 对象,保存了 Launcher 组件的详细信息。
15        data.writeStrongBinder(resultTo);
16        data.writeString(resultWho);
17        data.writeInt(requestCode);
18        data.writeInt(startFlags);
19        if (profilerInfo != null) {
20            data.writeInt(1);
21            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
22        } else {
23            data.writeInt(0);
24        }
25        if (options != null) {
26            data.writeInt(1);
27            options.writeToParcel(data, 0);
28        } else {
29            data.writeInt(0);
30        }
31        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
32        reply.readException();
33        int result = reply.readInt();
34        reply.recycle();
35        data.recycle();
36        return result;
37    }
JAVA

以上五步,就完成了启动一个 Activity ,在 Launcher 组件中的步骤,这五步都在 Launcher 应用程序进程内执行的。

剩下的步骤将会在 ActivityManagerService 进程去执行。

涉及到的其他类

  • UserHandle
  • LauncherApps
  • ActivityOptions
  • Instrumentation
    • 监控应用程序和系统之间的交互操作
  • ActivityRecord
    • 维护 Activity 组件的运行状态
  • ActivityThread
    • 表示 Android 应用程序进程
  • ApplicationThread
    • Binder 类型变量,用来和 ActivityManagerService 通信

参考

  1. Android 6.0 源码
  2. 《Android 系统源代码情景分析》

欢迎关注微信公众号:音视频开发进阶

Licensed under CC BY-NC-SA 4.0
粤ICP备20067247号
使用 Hugo 构建    主题 StackedJimmy 设计,Jacob 修改