概述
前面简单介绍了AMS的启动过程。现在从启动一个APP开始分析AMS在这个过程中究竟做了哪些事情,从而找出AMS中重要的数据结构。启动App,通常是启动该App的一个Activity,一般是主Activity.
用户从Launcher程序点击应用图标可启动应用的入口Activity,Activity启动时需要多个进程之间的交互,如下图所示:
其中AMS进程实际上是SystemServer进程,因为AMS只是SystemServer启动的一个服务而已,运行在SystemServer的某个线程中。
用户在Launcher程序里点击应用图标时,会通知ActivityManagerService启动应用的主Activity,ActivityManagerService发现这个应用还未启动,则会通知Zygote进程孵化出应用进程,然后在这个新孵化的应用进程里执行ActivityThread的main方法。应用进程接下来通知ActivityManagerService应用进程已启动,ActivityManagerService保存应用进程的一个代理对象,这样ActivityManagerService可以通过这个代理对象控制应用进程,然后ActivityManagerService通知应用进程创建主Activity的实例,并执行它的生命周期方法,也就是诸如OnCreadte()等方法。
Launcher启动app的真正入口点
Launcher 使用一个带有 Intent.FLAG_ACTIVITY_NEW_TASK flag 的 Intent,调用 startActivity 方法来启动App.
源码路径:
1
| Android-6/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
Android-6/packages/apps/Launcher3/src/com/android/launcher3/AppInfo.java
|
launcher上显示的每一个app都创建了一个用来启动他的intent,是一个显示的intent。组件名字是要启动的app的主activity名字。flag在后面会在添加一个标志。
1 2 3 4 5 6 7 8 9 | public static Intent makeLaunchIntent(Context context, LauncherActivityInfoCompat info, UserHandleCompat user) { long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user); return new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setComponent(info.getComponentName()) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) .putExtra(EXTRA_PROFILE, serialNumber); } |
当在launcher点击一个app的图标时的一个简要调用流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /** * Launches the intent referred by the clicked shortcut. * * @param v The view representing the clicked shortcut. */ public void onClick(View v) { ............ Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { onClickAppShortcut(v); } ........... } protected void onClickAppShortcut(final View v) { ...... // Start activities startAppShortcutOrInfoActivity(v); ....... } void startAppShortcutOrInfoActivity(View v) { ............ // 得到launcher提供的启动这个app主activity的intent intent = shortcut.intent; ........... boolean success = startActivitySafely(v, intent, tag); ............ } boolean startActivitySafely(View v, Intent intent, Object tag) { ................... success = startActivity(v, intent, tag); ................... } private boolean startActivity(View v, Intent intent, Object tag) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ........... startActivity(intent, optsBundle); ............... } |
从以上代码流程可知当Launcher启动一个app时,会在自己的startActivity()方法中为Intent中添加一个FLAG_ACTIVITY_NEW_TASK flag,然后调用继承自Activity的startActivity()方法来进一步启动app.
这样就找到了launcher启动一个app时的真正入口点了:Activity类的startActivity()方法。
1 2 3 4 5 6 7 | public void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); } else { startActivityForResult(intent, -1); } } |
Activity向AMS发起请求启动App
这个过程调用时序图如下所示:
Instrumentation和Activity有点类似,只不过Activity是需要一个界面的,而Instrumentation并不是这样的,我们可以将它理解为一种没有图形界面的,具有启动能力的,用于监控其他类(用Target Package声明)的工具类。在Android系统中常用来监控应用程序和系统交互。在App开发中可以用来编写测试用例。
另外两个类ActivityManagerNative和ActivityManagerProxy,在前面的文章已经介绍过了。这里就是获取AMS的一个代理对象,然后调用代理对象的startActivity(),实际上就是调用AMS的startActivity()方法来启动app。
这里要还要重点注意一下execStartActivity的第二个参数IBinder contextThread:
1 2 3 4 5 6 7 8 9 10 11 | public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; Uri referrer = target != null ? target.onProvideReferrer() : null; .................... int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target, requestCode, 0, null, options); ....... |
它是Activity类的startActivityForResult()方法中以下面代码所示的方法传入的:
1 2 3 4 5 6 7 8 | public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { Instrumentation.ActivityResult ar = //注意第二个参数 mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); ................. |
变量mMainThread是Activity类中ActivityThread类型的成员。
ActivityThread类是Android应用进程的核心类,这个类包含了应用框架中其他重要的类。
源码路径:
1
| Android-6/frameworks/base/core/java/android/app/ActivityThread.java
|
节选定义如下,先看源码对其的注释,就知道这个类的重要性了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /** * This manages the execution of the main thread in an * application process, scheduling and executing activities, * broadcasts, and other operations on it as the activity * manager requests. * * {@hide} */ public final class ActivityThread { ........ private ContextImpl mSystemContext; static IPackageManager sPackageManager; // 保存该app中所有的Activity final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>(); // 保存该app中所有的service final ArrayMap<IBinder, Service> mServices = new ArrayMap<>(); // 保存该app中所有的provider final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<ProviderKey, ProviderClientRecord>(); //管理应用的资源 private final ResourcesManager mResourcesManager; // 存储包含代码,即dex文件的apk文件保存在该变量中 final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<String, WeakReference<LoadedApk>>(); // 不包含代码,紧紧包含资源的apk放在该变量中 final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages // 如果app中自己实现了Application的子类,并在清单文件中声明了,那么该变量就指向自己实现的那个子类对象 Application mInitialApplication; AppBindData mBoundApplication; // 用于binder通信,AMS通过它来调用应用的接口 final ApplicationThread mAppThread = new ApplicationThread(); // 主线程中的Handler static Handler sMainThreadHandler; // set once in main() final Looper mLooper = Looper.myLooper(); // H继承自Handler,mH用来发送和处理ApplicationThread通过binder接受的AMS请求 final H mH = new H(); ......... } |
ActivityThread类中没有定义数据结构来存储BroadcastReceiver对象,因为BroadcastReceiver对象生命周期很短暂,属于调用一次运行一次的类型,因此不需要保存其对象。
AppBindData类为ActivityThread的内部类,定义如下,记录了与之绑定的app的相关数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | static final class AppBindData { LoadedApk info; String processName; ApplicationInfo appInfo; List<ProviderInfo> providers; ComponentName instrumentationName; Bundle instrumentationArgs; IInstrumentationWatcher instrumentationWatcher; IUiAutomationConnection instrumentationUiAutomationConnection; int debugMode; boolean enableOpenGlTrace; boolean restrictedBackupMode; boolean persistent; Configuration config; CompatibilityInfo compatInfo; /** Initial values for {@link Profiler}. */ ProfilerInfo initProfilerInfo; public String toString() { return "AppBindData{appInfo=" + appInfo + "}"; } } |
其中 ApplicationThread类型的变量mAppThread用于AMS所在app的接口,应用进程需要调用AMS提供的功能,而AMS也需要主动调用应用进程以控制应用进程并完成指定操作。这样AMS就需要应用进程的一个Binder代理对象。
如下图所示
AMS通过IApplicationThread接口管理应用进程,ApplicationThread类实现了IApplicationThread接口,实现了管理应用的操作,ApplicationThread对象运行在应用进程里。ApplicationThreadProxy对象是ApplicationThread对象在AMS线程 (AMS线程运行在system_server进程)内的代理对象,AMS通过ApplicationThreadProxy对象调用ApplicationThread提供的功能,比如让应用进程启动某个Activity。
ApplicationThread中的scheduleDestroyActivity方法如下:
1 2 3 4 5 | public final void scheduleDestroyActivity(IBinder token, boolean finishing, int configChanges) { sendMessage(H.DESTROY_ACTIVITY, token, finishing ? 1 : 0, configChanges); } |
作为Binder服务端的方法实际上是调用ActivityThread类的下面两个方法完成的。(ApplicationThread是ActivityThread内部类)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | private void sendMessage(int what, Object obj, int arg1, int arg2) { sendMessage(what, obj, arg1, arg2, false); } private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { if (DEBUG_MESSAGES) Slog.v( TAG, "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj); Message msg = Message.obtain(); msg.what = what; msg.obj = obj; msg.arg1 = arg1; msg.arg2 = arg2; if (async) { msg.setAsynchronous(true); } mH.sendMessage(msg); } |
那么在ActivityThread类中内部类H(继承自Handler,mH就是H的对象),中肯定义了处理消息的handleMessage()方法,
1 2 3 4 5 6 | case DESTROY_ACTIVITY: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy"); handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0, msg.arg2, false); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; |
handleDestroyActivity是ActivityThread类中定义的方法。也就是说实际的处理都是在ActivityThread类中完成的,Handler类仅仅负责通信而已。
这里利用Handler机制,很巧妙的以异步方式执行了binder的请求。理解了这个过程后,在分析ApplicationThread类中的接口时,就不用再关心消息传递过程了,直接在ActivityThread类查找对应的方法。
binder中定义的方法以”schedule”开头,与之对应的ActivityThread类中的处理方法以”handle”开头。
AMS启动app
前面分析到开始调用AMS的startActivity方法了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) { return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, options, UserHandle.getCallingUserId()); } public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) { // 如果是隔离的应用的话,不允许其打开其他app的activity // appid是99000-99999之间的属于隔离app enforceNotIsolatedCaller("startActivity"); userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivity", null); // TODO: Switch to user app stacks here. return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, null, null, options, false, userId, null, null); } |
判断发起者是否是隔离的app,不允许隔离的app调用其他app。然后调用ActivityStackSupervisor类中的startActivityMayWait方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | final int startActivityMayWait( IApplicationThread caller,//AMS通过这个参数可以和发起者进行交互 int callingUid,//发起者uid String callingPackage,//发起者包名 Intent intent, // 启动activity的intent String resolvedType, // intent的类型,也就是MIME type IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo,//用于接收startActivityForResult的结果,launcher启动app这种情景下没有用,为null String resultWho, int requestCode,//这个是调用者来定义其意义,若值大于等于0,则AMS内部保存该值并通过onActivityResult返回调用者,这里为-1 int startFlags,// 传入的为0 ProfilerInfo profilerInfo, WaitResult outResult, Configuration config, Bundle options, boolean ignoreTargetSecurity, int userId, IActivityContainer iContainer, // 传入的为null TaskRecord inTask)/ // 传入为null { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); } // 当启动一个app时 ,launcher会构造一个intent,前面已经介绍了,是一个显示的intent // 所以这里为true, boolean componentSpecified = intent.getComponent() != null; // Don't modify the client's object! // 创建一个新的intent,方便改动 intent = new Intent(intent); // 收集 要启动的app的主activity的信息 ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId); // 传入的该参数为null ActivityContainer container = (ActivityContainer)iContainer; synchronized (mService) { if (container != null && container.mParentActivity != null && container.mParentActivity.state != RESUMED) { // Cannot start a child activity if the parent is not resumed. return ActivityManager.START_CANCELED; } .................................... final ActivityStack stack; if (container == null || container.mStack.isOnHomeDisplay()) { stack = mFocusedStack; } else { stack = container.mStack; } // 传入的config为null stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0; if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = " + stack.mConfigWillChange); final long origId = Binder.clearCallingIdentity(); if (aInfo != null && (aInfo.applicationInfo.privateFlags &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { ....................... } int res = startActivityLocked(caller, intent, resolvedType, aInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, null, container, inTask); Binder.restoreCallingIdentity(origId); if (stack.mConfigWillChange) { ............. } // 传入的为null if (outResult != null) { ....................... mService.wait(); //等待应用进程的activity启动完成 ........... } ............. } return res; } } |
startActivityAsUser()方法最主要的目地是进行权限检查,检查发起者是否被隔离,是的话,是不允许调用别的app的activity的。然后就是检查调用者的是否有权限执行启动app的操作.
startActivityMayWait()方法主要是利用传入的intent去向PMS搜集要启动的APP的信息,储存到aInfo中.名字中有wait字眼,预示着该方法可能导致线程等待.不过在我们这个场景中不会出现这种情况.因为wait出现在对结果的处理中,我们这个场景中是不需要处理结果的.
获取到的activity信息是使用类ActivityInfo表示的,该类中记录的activity信息主要来自 AndroidManifest.xml.该xml中记录了activity的启动模式,主题,持久化能力,任务栈名称,flags等信息
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class ActivityInfo extends ComponentInfo{ public int theme; ........... public int launchMode; ......... public int persistableMode; ......... public String taskAffinity; ...... public int flags; ........... } |
接下去就调用startActivityLocked进一步处理了。
到这里为止的时序图如下所示:
最后
以上就是怕黑跳跳糖为你收集整理的Android6.0之AMS如何启动app上篇的全部内容,希望文章能够帮你解决Android6.0之AMS如何启动app上篇所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复