共计 32212 个字符,预计需要花费 81 分钟才能阅读完成。
本文基于 android13-release 源码浏览整顿
零碎源码地址:init.h – Android Code Search
1. 前言
紧接上篇 [Android 零碎 Launcher 启动流程)] 咱们持续看看 Launcher 是如何运行并加载所有桌面利用,继而探索用户在 launcher 桌面点击 App 图标启动利用整体流程
2.Launcher 运行及生命周期办法
相熟 Android 开发的同学在启动模拟器显示桌面后,咱们能够直观看到模拟器顶部搜寻框,工夫日历小部件,可拖拽利用区域,底部导航批示条以及快捷启动图标,利用文件夹等,基于零碎 UI 层级展现形式,咱们通过源码逐渐探寻其工作形式. 上面咱们从 onCreate()函数开始
源码地位:packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
2.1 Launcher.onCreate
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); | |
// 获取 LauncherAppState 实例,次要解决 IconCache,IconCacheProvider、LauncherModel 对象初始化及凋谢对外调用办法 | |
LauncherAppState app = LauncherAppState.getInstance(this); | |
mOldConfig = new Configuration(getResources().getConfiguration()); | |
//LauncherAppState 中定义对外调用办法 | |
mModel = app.getModel(); | |
mRotationHelper = new RotationHelper(this); | |
// 依据屏幕宽高读取最靠近设施文件信息,用于桌面图标大小,行列数配置 | |
InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); | |
initDeviceProfile(idp); | |
idp.addOnChangeListener(this); | |
// 存储库 SharePreferences | |
mSharedPrefs = Utilities.getPrefs(this); | |
mIconCache = app.getIconCache(); | |
mAccessibilityDelegate = createAccessibilityDelegate(); | |
// 初始化拖拽布局控制器 | |
mDragController = new LauncherDragController(this); | |
// 解决所有 app 在桌面拖拽图标时的动画 | |
mAllAppsController = new AllAppsTransitionController(this); | |
mStateManager = new StateManager < >(this, NORMAL); | |
// 关联存储库 SharePreferences | |
mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs); | |
// 小部件治理 helper | |
mAppWidgetManager = new WidgetManagerHelper(this); | |
mAppWidgetHost = createAppWidgetHost(); | |
mAppWidgetHost.startListening(); | |
// 加载 launcher xml | |
inflateRootView(R.layout.launcher); | |
// 设置所有 apps view,放在上面大节独自剖析 | |
setupViews(); | |
// 淡入淡出动画 | |
crossFadeWithPreviousAppearance(); | |
// 设置监听 NotificationListener,PopupDataProvider 次要解决长按 app 图标显示内容 | |
mPopupDataProvider = new PopupDataProvider(this: :updateNotificationDots); | |
// 状态解决相干 | |
boolean internalStateHandled = ACTIVITY_TRACKER.handleCreate(this); | |
if (internalStateHandled) {if (savedInstanceState != null) { | |
// InternalStateHandler has already set the appropriate state. | |
// We dont need to do anything. | |
savedInstanceState.remove(RUNTIME_STATE); | |
} | |
} | |
restoreState(savedInstanceState); | |
mStateManager.reapplyState(); | |
if (savedInstanceState != null) {int[] pageIds = savedInstanceState.getIntArray(RUNTIME_STATE_CURRENT_SCREEN_IDS); | |
if (pageIds != null) {mPagesToBindSynchronously = IntSet.wrap(pageIds); | |
} | |
} | |
//LoaderTask 相干操作,放在上面大节独自剖析 | |
if (!mModel.addCallbacksAndLoad(this)) {if (!internalStateHandled) {Log.d(BAD_STATE, "Launcher onCreate not binding sync, prevent drawing"); | |
// If we are not binding synchronously, pause drawing until initial bind complete, | |
// so that the system could continue to show the device loading prompt | |
mOnInitialBindListener = Boolean.FALSE: :booleanValue; | |
} | |
} | |
// For handling default keys | |
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); | |
// 设置页面布局 | |
setContentView(getRootView()); | |
if (mOnInitialBindListener != null) {getRootView().getViewTreeObserver().addOnPreDrawListener(mOnInitialBindListener); | |
} | |
getRootView().dispatchInsets(); | |
// 注册屏幕敞开播送监听 | |
registerReceiver(mScreenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); | |
// 更新 UiState、Theme(Dark/Light) | |
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW, Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)); | |
//hook 生命周期办法 | |
if (mLauncherCallbacks != null) {mLauncherCallbacks.onCreate(savedInstanceState); | |
} | |
mOverlayManager = getDefaultOverlay(); | |
PluginManagerWrapper.INSTANCE.get(this).addPluginListener(this, LauncherOverlayPlugin.class, false | |
/* allowedMultiple */ | |
); | |
// 屏幕旋转切换配置初始化 | |
mRotationHelper.initialize(); | |
TraceHelper.INSTANCE.endSection(traceToken); | |
mUserChangedCallbackCloseable = UserCache.INSTANCE.get(this).addUserChangeListener(() - >getStateManager().goToState(NORMAL)); | |
if (Utilities.ATLEAST_R) {getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING); | |
} | |
setTitle(R.string.home_screen); | |
} |
launcher 类中 onCreate()会初始化 LauncherAppState 实例,用于获取 Icon/LauncherModel 对象,读取设施文件信息以匹配桌面图标及行列数,初始化 SharedPreferences, 布局拖拽控制器,设置布局 xml,apps view,以及 LoaderTask 相干操作, 设置页面布局及其它配置信息,上面咱们来看看源码中 setupViews()办法
2.2 Launcher.setupViews()
protected void setupViews() { | |
// 加载根布局 | |
inflateRootView(R.layout.launcher); | |
mDragLayer = findViewById(R.id.drag_layer); | |
mFocusHandler = mDragLayer.getFocusIndicatorHelper(); | |
mWorkspace = mDragLayer.findViewById(R.id.workspace); | |
// 初始化 PageIndicator | |
mWorkspace.initParentViews(mDragLayer); | |
mOverviewPanel = findViewById(R.id.overview_panel); | |
mHotseat = findViewById(R.id.hotseat); | |
// 设置快捷启动图标工作区 | |
mHotseat.setWorkspace(mWorkspace); | |
// Setup the drag layer | |
mDragLayer.setup(mDragController, mWorkspace); | |
// 初始化 DragController,更新 layer type 属性 | |
mWorkspace.setup(mDragController); | |
// 绑定工作区之前锁定壁纸默认状态 | |
mWorkspace.lockWallpaperToDefaultPage(); | |
// 初始化第一页并绑定,此处会以 CellLayout 承载页面,其自身继承于 ViewGroup, 反对对 item 拖入拖出操作 | |
mWorkspace.bindAndInitFirstWorkspaceScreen(); | |
// 拖拽监听 | |
mDragController.addDragListener(mWorkspace); | |
// Get the search/delete/uninstall bar | |
mDropTargetBar = mDragLayer.findViewById(R.id.drop_target_bar); | |
// Setup Apps | |
mAppsView = findViewById(R.id.apps_view); | |
// Setup Scrim | |
mScrimView = findViewById(R.id.scrim_view); | |
// Setup the drag controller (drop targets have to be added in reverse order in priority) | |
mDropTargetBar.setup(mDragController); | |
//mAppsView 设置 mScrimView | |
mAllAppsController.setupViews(mScrimView, mAppsView); | |
} |
以上办法初始化相干 views 并设置监听,上面咱们再看 LoaderTask 数据加载是如何进行的
源码门路:packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java
2.3 LoaderTask
public boolean addCallbacksAndLoad(@NonNull final Callbacks callbacks) {synchronized(mLock) {addCallbacks(callbacks); | |
return startLoader(new Callbacks[] {callbacks}); | |
} | |
} | |
private boolean startLoader(@NonNull final Callbacks[] newCallbacks) { | |
// Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems | |
ItemInstallQueue.INSTANCE.get(mApp.getContext()).pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING); | |
synchronized(mLock) { | |
// 进行 LoaderTask 工作线程 | |
boolean wasRunning = stopLoader(); | |
// 设置相干标记 | |
boolean bindDirectly = mModelLoaded && !mIsLoaderTaskRunning; | |
boolean bindAllCallbacks = wasRunning || !bindDirectly || newCallbacks.length == 0; | |
final Callbacks[] callbacksList = bindAllCallbacks ? getCallbacks() : newCallbacks; | |
if (callbacksList.length > 0) { | |
// 同步工作执行时革除任意挂起绑定操作 | |
for (Callbacks cb: callbacksList) {MAIN_EXECUTOR.execute(cb: :clearPendingBinds); | |
} | |
// 构建 loaderResults | |
LoaderResults loaderResults = new LoaderResults(mApp, mBgDataModel, mBgAllAppsList, callbacksList); | |
if (bindDirectly) { | |
// Divide the set of loaded items into those that we are binding synchronously, | |
// and everything else that is to be bound normally (asynchronously). | |
loaderResults.bindWorkspace(bindAllCallbacks); | |
// For now, continue posting the binding of AllApps as there are other | |
// issues that arise from that. | |
loaderResults.bindAllApps(); | |
loaderResults.bindDeepShortcuts(); | |
loaderResults.bindWidgets(); | |
return true; | |
} else {stopLoader(); | |
// 构建 LoaderTask 工作并筹备执行 | |
mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults); | |
// Always post the loader task, instead of running directly | |
// (even on same thread) so that we exit any nested synchronized blocks | |
// 通过 handler 公布 mLoaderTask,但不以內联形式运行 | |
MODEL_EXECUTOR.post(mLoaderTask); | |
} | |
} | |
} | |
return false; | |
} |
通过下面代码调用链,此时 mLoaderTask 曾经公布,咱们看下 LoaderTask.run()具体执行内容有哪些
public void run() { | |
... | |
... | |
LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger(); | |
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {List < ShortcutInfo > allShortcuts = new ArrayList < >(); | |
try { | |
// 加载工作区 | |
loadWorkspace(allShortcuts, memoryLogger); | |
} finally {Trace.endSection(); | |
} | |
... | |
// 绑定工作区 | |
mResults.bindWorkspace(true /* incrementBindId */); | |
mModelDelegate.workspaceLoadComplete(); | |
// 发送首屏播送告诉,告诉软件安装包在首屏无效装置 | |
sendFirstScreenActiveInstallsBroadcast(); | |
// 期待 workspace 加载实现 | |
waitForIdle(); | |
... | |
List < LauncherActivityInfo > allActivityList; | |
try { | |
// 加载所有 apps, 从缓存读取 user profiles, 清空利用列表,依据 profile 读取所有 LauncherActivityInfo,最终增加进缓存汇合 | |
allActivityList = loadAllApps();} finally {Trace.endSection(); | |
} | |
... | |
// 绑定所有 apps | |
mResults.bindAllApps(); | |
... | |
// 获取解决图标缓存更新 handler | |
IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); | |
setIgnorePackages(updateHandler); | |
updateHandler.updateIcons(allActivityList, LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel() : :onPackageIconsUpdated); | |
... | |
// 缓存 allShortcuts | |
updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(), mApp.getModel() : :onPackageIconsUpdated); | |
// 期待上述步骤操作实现 | |
waitForIdle(); | |
... | |
// 加载应用程序快捷方式 | |
List < ShortcutInfo > allDeepShortcuts = loadDeepShortcuts(); | |
... | |
// 绑定利用快捷启动形式 | |
mResults.bindDeepShortcuts(); | |
... | |
// 缓存 allDeepShortcuts | |
updateHandler.updateIcons(allDeepShortcuts, new ShortcutCachingLogic(), (pkgs, user) - >{}); | |
// 期待上述步骤操作实现 | |
waitForIdle(); | |
... | |
// 加载桌面小部件 allWidgetsList | |
List < ComponentWithLabelAndIcon > allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null); | |
... | |
// 绑定桌面小部件 | |
mResults.bindWidgets(); | |
... | |
// 缓存小部件图标 | |
updateHandler.updateIcons(allWidgetsList, new ComponentWithIconCachingLogic(mApp.getContext(), true), mApp.getModel() : :onWidgetLabelsUpdated); | |
... | |
// 加载桌面文件夹名称 | |
loadFolderNames(); | |
... | |
// 解决实现 | |
updateHandler.finish(); | |
mModelDelegate.modelLoadComplete(); | |
transaction.commit(); | |
memoryLogger.clearLogs();} catch(CancellationException e) { | |
// Loader stopped, ignore | |
logASplit(logger, "Cancelled"); | |
} catch(Exception e) {memoryLogger.printLogs(); | |
throw e; | |
} finally {logger.dumpToLog(); | |
} | |
TraceHelper.INSTANCE.endSection(traceToken); | |
} |
在 LoaderTask.run()中能够清晰看到加载数据的每一步操作,基于此 launcher 桌面利用相干信息根本加载实现,Launcher 类自身继承于 StatefulActivity,其生命周期办法与惯例 Activity 基本一致,感兴趣的可持续在源码外面查看相干办法具体解决内容
3. 点击桌面图标启动 App
3.1 bindWorkspace 与 createShortcut
上述步骤中在 loadWorkspace()之后紧接着调用 bindWorkpsace(), 用于将所有加载数据绑定到主线程上的理论视图
public void bindWorkspace(boolean incrementBindId) { | |
... | |
... | |
for (Callbacks cb: mCallbacksList) {new WorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId, workspaceItems, appWidgets, extraItems, orderedScreenIds).bind();} | |
} |
次要看下 bind()办法,会持续调用 bindWorkspaceItems(),用于最终 callback 调用 bindItems,此处 callback 对象为 launcher 实例,Launcher 中定义了 bindItems()
// 该办法中会循环调用 view = createShortcut(info)创立 view,createShortcut()也同样定义在 Launcher 类中,
private void bindWorkspaceItems(final ArrayList < ItemInfo > workspaceItems, final Executor executor) { | |
// Bind the workspace items | |
int count = workspaceItems.size(); | |
for (int i = 0; i < count; i += ITEMS_CHUNK) { | |
final int start = i; | |
final int chunkSize = (i + ITEMS_CHUNK <= count) ? ITEMS_CHUNK: (count - i); | |
executeCallbacksTask(c - >c.bindItems(workspaceItems.subList(start, start + chunkSize), false), executor); | |
} | |
} | |
// 创立 shortcut | |
public View createShortcut(ViewGroup parent, WorkspaceItemInfo info) {BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext()).inflate(R.layout.app_icon, parent, false); | |
favorite.applyFromWorkspaceItem(info); | |
// 设置图标点击事件,ItemClickHandler 用于解决对工作区和所有利用点击响应 | |
favorite.setOnClickListener(ItemClickHandler.INSTANCE); | |
favorite.setOnFocusChangeListener(mFocusHandler); | |
return favorite; | |
} | |
// 点击事件响应 | |
private static void onClick(View v) { | |
... | |
... | |
Object tag = v.getTag(); | |
// 起源来为 WorkspaceItemInfo,if (tag instanceof WorkspaceItemInfo) {// 持续调用 startAppShortcutOrInfoActivity(v, shortcut, launcher)用于启动 activity | |
onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher); | |
} | |
... | |
... | |
} | |
// 启动 activity | |
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) { | |
// 构建 intent | |
Intent intent; | |
if (item instanceof ItemInfoWithIcon | |
&& (((ItemInfoWithIcon) item).runtimeStatusFlags | |
& ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item; | |
intent = new PackageManagerHelper(launcher) | |
.getMarketIntent(appInfo.getTargetComponent().getPackageName()); | |
} else {intent = item.getIntent(); | |
} | |
... | |
if (item instanceof WorkspaceItemInfo) {WorkspaceItemInfo si = (WorkspaceItemInfo) item; | |
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) | |
&& Intent.ACTION_VIEW.equals(intent.getAction())) {the | |
// web ui. This only works though if the package isn't set | |
intent = new Intent(intent); | |
intent.setPackage(null); | |
} | |
if ((si.options & WorkspaceItemInfo.FLAG_START_FOR_RESULT) != 0) {launcher.startActivityForResult(item.getIntent(), 0); | |
InstanceId instanceId = new InstanceIdSequence().newInstanceId(); | |
launcher.logAppLaunch(launcher.getStatsLogManager(), item, instanceId); | |
return; | |
} | |
} | |
... | |
// 启动 activity | |
launcher.startActivitySafely(v, intent, item); | |
} | |
} |
通过 startActivitySafely 启动 activity,咱们须要看下 Launcher 继承关系,
Launcher->StatefulActivity->BaseDraggingActivity->BaseActivity implements AppLauncher,
所以 launcher.startActivitySafely 最终是调用 AppLauncher 接口中的同名办法,该办法会构建利用启动须要的显示
的宽高参数、animation、displayId,封装到 Bundle 对象中,最初调用 startShortcut(),办法源码如下:
3.2 startShortcut
default void startShortcut(String packageName, String id, Rect sourceBounds, Bundle startActivityOptions, UserHandle user) {if (GO_DISABLE_WIDGETS) {return;} | |
try {((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id, sourceBounds, startActivityOptions, user); | |
} catch(SecurityException | IllegalStateException e) {Log.e(TAG, "Failed to start shortcut", e); | |
} | |
} | |
// 通过一系列参数解决最终走到 LauncherApps.java 中,源码地位:frameworks/base/core/java/android/content/pm/LauncherApps.java | |
@UnsupportedAppUsage | |
private void startShortcut(@NonNull String packageName, @NonNull String shortcutId, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions, int userId) { | |
try { | |
// 此处 mService 对应 LauncherAppsImpl 实现类,通过 aidl 定义实现用于跨过程通信 | |
final boolean success = mService.startShortcut(mContext.getPackageName(), packageName, null | |
/* default featureId */ | |
, shortcutId, sourceBounds, startActivityOptions, userId); | |
if (!success) {throw new ActivityNotFoundException("Shortcut could not be started"); | |
} | |
} catch(RemoteException e) {throw e.rethrowFromSystemServer(); | |
} | |
} |
@SystemService(Context.LAUNCHER_APPS_SERVICE)通过注解标记零碎服务,当作用于类是可便捷获取其服务实例,此处 LAUNCHER_APPS_SERVICE 对应实例类 LauncherAppService.java 类
在被注解的 LauncherApps 类可通过 context.getSystemService 获取,具体代码位于该类构造函数中;LauncherAppsService 构造函数初始化了 LauncherAppsImpl 实例,在 onStart 启动服务办法中公布了 LAUNCHER_APPS_SERVICE 标记服务
LauncherAppsImpl 实例中定义了 startShortcut()办法,最终调用 startShortcutInner()验证调用包,用户是否有权限拜访配置文件以及异步创立快捷方式启动 intent,并配置 intent 启动标记,源边界及 Splash theme, 最初调用 startShortcutIntentsAsPublisher()启动 activity,
3.3 startShortcutInner
其源码如下
// 源码地位:/frameworks/base/services/core/java/com/android/server/pm/LauncherAppsService.java | |
private boolean startShortcutInner(int callerUid, int callerPid, int callingUserId, String callingPackage, String packageName, String featureId, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int targetUserId) {verifyCallingPackage(callingPackage, callerUid); | |
if (!canAccessProfile(targetUserId, "Cannot start activity")) {return false;} | |
if (!mShortcutServiceInternal.isPinnedByCaller(callingUserId, callingPackage, packageName, shortcutId, targetUserId)) {ensureShortcutPermission(callerUid, callerPid, callingPackage); | |
} | |
final AndroidFuture < Intent[] > ret = new AndroidFuture < >(); | |
Intent[] intents; | |
mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId, injectBinderCallingPid(), injectBinderCallingUid(), ret); | |
try {intents = ret.get(); | |
} catch(InterruptedException | ExecutionException e) {return false;} | |
if (intents == null || intents.length == 0) {return false;} | |
ActivityOptions options = ActivityOptions.fromBundle(startActivityOptions); | |
if (options != null && options.isApplyActivityFlagsForBubbles()) { | |
// Flag for bubble to make behaviour match documentLaunchMode=always. | |
intents[0].addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); | |
intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); | |
} | |
intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | |
intents[0].setSourceBounds(sourceBounds); | |
final String splashScreenThemeResName = mShortcutServiceInternal.getShortcutStartingThemeResName(callingUserId, callingPackage, packageName, shortcutId, targetUserId); | |
if (splashScreenThemeResName != null && !splashScreenThemeResName.isEmpty()) {if (startActivityOptions == null) {startActivityOptions = new Bundle(); | |
} | |
startActivityOptions.putString(KEY_SPLASH_SCREEN_THEME, splashScreenThemeResName); | |
} | |
return startShortcutIntentsAsPublisher(intents, packageName, featureId, startActivityOptions, targetUserId); | |
} | |
private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, @NonNull String publisherPackage, @Nullable String publishedFeatureId, Bundle startActivityOptions, int userId) { | |
final int code; | |
try { | |
//mActivityTaskManagerInternal - ActivityTaskManagerService 的外部抽象类 | |
code = mActivityTaskManagerInternal.startActivitiesAsPackage(publisherPackage, publishedFeatureId, userId, intents, startActivityOptions); | |
if (ActivityManager.isStartResultSuccessful(code)) {return true; // Success} else {Log.e(TAG, "Couldn't start activity, code=" + code); | |
} | |
return false; | |
} catch(SecurityException e) {if (DEBUG) {Slog.d(TAG, "SecurityException while launching intent", e); | |
} | |
return false; | |
} | |
} |
在 LauncherAppsImpl 构造函数中,会通过 LocalServices.getService(ActivityTaskManagerInternal.class)获取 ActivityTaskManagerInternal 实例
那该实例何时被增加进去的呢,这个就须要看 ActivityTaskManagerService 中的 start()办法,其中定义了外部类 LocalService 继承于 ActivityTaskManagerInternal 抽象类, 最终调用
startActivitiesAsPackage()
// 源码地位:/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java | |
@Override public int startActivitiesAsPackage(String packageName, @Nullable String featureId, int userId, Intent[] intents, Bundle bOptions) {Objects.requireNonNull(intents, "intents"); | |
final String[] resolvedTypes = new String[intents.length]; | |
// UID of the package on user userId. | |
// "= 0" is needed because otherwise catch(RemoteException) would make it look like | |
// packageUid may not be initialized. | |
int packageUid = 0; | |
final long ident = Binder.clearCallingIdentity(); | |
try {for (int i = 0; i < intents.length; i++) {resolvedTypes[i] = intents[i].resolveTypeIfNeeded(mContext.getContentResolver()); | |
} | |
packageUid = AppGlobals.getPackageManager().getPackageUid(packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId); | |
} catch(RemoteException e) {// Shouldn't happen.} finally {Binder.restoreCallingIdentity(ident); | |
} | |
return getActivityStartController().startActivitiesInPackage(packageUid, packageName, featureId, intents, resolvedTypes, null | |
/* resultTo */ | |
, SafeActivityOptions.fromBundle(bOptions), userId, false | |
/* validateIncomingUser */ | |
, null | |
/* originatingPendingIntent */ | |
, false | |
/* allowBackgroundActivityStart */ | |
); | |
} |
能够看到最重要的一行:getActivityStartController().startActivitiesInPackage()交由 ActivityStartController 治理启动 activity 相干操作,在上一篇博文中
7.AMS.systemReady 办法启动 Launcher 也会波及 ActivityStartController 执行 executeRequest,
3.4 startActivitiesInPackage
咱们持续看下调用办法源码,
// 源码地位:/frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java | |
final int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid, String callingPackage, @Nullable String callingFeatureId, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { | |
final String reason = "startActivityInPackage"; | |
// 校验指标用户 id, 并保障不是非凡用户 | |
userId = checkTargetUser(userId, validateIncomingUser, Binder.getCallingPid(), Binder.getCallingUid(), reason); | |
// 筹备启动 | |
return startActivities(null, uid, realCallingPid, realCallingUid, callingPackage, callingFeatureId, intents, resolvedTypes, resultTo, options, userId, reason, originatingPendingIntent, allowBackgroundActivityStart); | |
} | |
// 最终调用启动办法 | |
int startActivities(IApplicationThread caller, int callingUid, int incomingRealCallingPid, int incomingRealCallingUid, String callingPackage, @Nullable String callingFeatureId, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, String reason, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { | |
... | |
... | |
try {intents = ArrayUtils.filterNotNull(intents, Intent[] : :new); | |
... | |
... | |
final IBinder sourceResultTo = resultTo; | |
final ActivityRecord[] outActivity = new ActivityRecord[1]; | |
// Lock the loop to ensure the activities launched in a sequence. | |
synchronized(mService.mGlobalLock) {mService.deferWindowLayout(); | |
// To avoid creating multiple starting window when creating starting multiples | |
// activities, we defer the creation of the starting window once all start request | |
// are processed | |
mService.mWindowManager.mStartingSurfaceController.beginDeferAddStartingWindow(); | |
try {for (int i = 0; i < starters.length; i++) {final int startResult = starters[i].setResultTo(resultTo).setOutActivity(outActivity).execute(); | |
if (startResult < START_SUCCESS) { | |
// Abort by error result and recycle unused starters. | |
for (int j = i + 1; j < starters.length; j++) {mFactory.recycle(starters[j]); | |
} | |
return startResult; | |
} | |
final ActivityRecord started = outActivity[0]; | |
if (started != null && started.getUid() == filterCallingUid) { | |
// Only the started activity which has the same uid as the source caller | |
// can be the caller of next activity. | |
resultTo = started.token; | |
} else { | |
resultTo = sourceResultTo; | |
// Different apps not adjacent to the caller are forced to be new task. | |
if (i < starters.length - 1) {starters[i + 1].getIntent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | |
} | |
} | |
} | |
} finally {mService.mWindowManager.mStartingSurfaceController.endDeferAddStartingWindow(options != null ? options.getOriginalOptions() : null); | |
mService.continueWindowLayout();} | |
} | |
} finally {Binder.restoreCallingIdentity(origId); | |
} | |
return START_SUCCESS; | |
} |
在下面办法中通过对 ActivityStarter 数组循环执行启动 activity 申请,execute()最终调用该类 int execute()办法,后续调用流程就跟 startHomeActivity()统一,具体阐明参见上一篇博文中
7.AMS.systemReady 办法以及后续章节源码阐明
4. 利用内启动 startActivity()
以 Activity.startActivity()为例,
// 启动 activity | |
public void startActivity(Intent intent, @Nullable Bundle options) {if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN) && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {if (TextUtils.equals(getPackageName(), intent.resolveActivity(getPackageManager()).getPackageName())) {// Apply Autofill restore mechanism on the started activity by startActivity() | |
final IBinder token = mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN); | |
// Remove restore ability from current activity | |
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN); | |
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY); | |
// Put restore token | |
intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token); | |
intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true); | |
} | |
} | |
if (options != null) {startActivityForResult(intent, -1, options); | |
} else { | |
// Note we want to go through this call for compatibility with | |
// applications that may have overridden the method. | |
startActivityForResult(intent, -1); | |
} | |
} | |
//startActivityForResult | |
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {if (mParent == null) {options = transferSpringboardActivityOptions(options); | |
//Instrumentation.execStartActivity | |
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); | |
... | |
... | |
} else { | |
... | |
... | |
} | |
} | |
//Instrumentation.execStartActivity | |
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { | |
... | |
// 参数及监控相干解决 | |
... | |
try { | |
... | |
// 此处 getService 返回 IActivityTaskManager 抽象类,理论被 ActivityTaskManagerService 实现 | |
int result = ActivityTaskManager.getService().startActivity(whoThread, who.getBasePackageName(), who.getAttributionTag(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID: null, requestCode, 0, null, options); | |
// 校验启动后果是否胜利 | |
checkStartActivityResult(result, intent); | |
} catch(RemoteException e) {throw new RuntimeException("Failure from system", e); | |
} | |
return null; | |
} | |
//ActivityTaskManagerService.startActivity | |
// 源码地位:/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java | |
@Override public final int startActivity(IApplicationThread caller, String callingPackage, String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, UserHandle.getCallingUserId()); | |
} | |
//startActivityAsUser | |
private int startActivityAsUser(IApplicationThread caller, String callingPackage, @Nullable String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) { | |
... | |
... | |
// 此处 getActivityStartController()返回 ActivityStartController 对象,调用 obtainStarter 理论调用 ActivityStarter, 通过 execute()执行启动申请 | |
return getActivityStartController().obtainStarter(intent, "startActivityAsUser").setCaller(caller).setCallingPackage(callingPackage).setCallingFeatureId(callingFeatureId).setResolvedType(resolvedType).setResultTo(resultTo).setResultWho(resultWho).setRequestCode(requestCode).setStartFlags(startFlags).setProfilerInfo(profilerInfo).setActivityOptions(bOptions).setUserId(userId).execute();} | |
// 调用 execute()最终执行 executeRequest()启动,源码门路:/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java |
- execute()办法解决 Activity 启动申请,进入到
- executeRequest(mRequest); 执行执行一系列权限查看,进入到
- startActivityUnchecked()校验初步权限查看是否实现,进入到
- startActivityInner()启动 Activity,并确定是否将 activity 增加到栈顶, 进入到
- startActivityLocked()判断以后 activity 是否可见以及是否须要为其新建 Task,并将 ActivityRecord 退出到 Task 栈顶中, 进入到
- resumeFocusedTasksTopActivities() – RootWindowContainer.java , 次要判断 targetRootTask 是否处于栈顶,同时判断 task 是否处于暂停状态,进入到
- resumeTopActivityUncheckedLocked() – Task.java, 递归调用该办法并查找栈顶可显示 activity 以及状态是否暂停,进入到
- resumeTopActivityInnerLocked() – Task.java, 该办法次要解决 ActivityRecord、设置 resume 状态、筹备启动 activity,进入到
- resumeTopActivity() – TaskFragment.java, 查找栈顶 activity 是否处于 running,查看所有暂停操作是否实现,进入到
- startSpecificActivity() – ActivityTaskSupervisor.java, 如果 activity 已运行则间接启动,未运行则启动指标 Activity, 开启启动新过程,进入到
-
realStartActivityLocked() – ActivityTaskManagerService.java, 因为 Activity.startActivity()在调用前过程已创立,所以分支走到这里
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throws RemoteException { ... try { ... try { ... // 创立 activity 启动事务 final ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.token); // 判断 activity 是否是前向转换,即从一个 Activity 转换到另一个 Activity,后者在工作栈中的地位比前者更靠前 final boolean isTransitionForward = r.isTransitionForward(); // 获取 IBinder 对象 final IBinder fragmentToken = r.getTaskFragment().getFragmentToken(); // 将蕴含 activity 回调(蕴含生命周期申请 / 回调)增加到音讯汇合开端 clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global // and override configs. mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor, proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(), results, newIntents, r.takeOptions(), isTransitionForward, proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken)); // 设置生命周期状态申请 final ActivityLifecycleItem lifecycleItem; if (andResume) {lifecycleItem = ResumeActivityItem.obtain(isTransitionForward); } else {lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); // 获取 ClientLifecycleManager 对象,执行事务 mService.getLifecycleManager().scheduleTransaction(clientTransaction); } ... } ... } ClientLifecycleManager.scheduleTransaction()最终调用 ClientTransaction.java 中的 shedule()办法
该办法将客户端事务退出到零碎事务队列中,并按程序执行 preExecute 实现前置工作,发送事务 message,调用 TransactionExecutor.execute()执行所有回调及生命周期转换
mClient 对象为 IApplicationThread, 这是 aidl 接口,其理论执行对象为 ActivityThread, 继承于 ClientTransactionHandler,外部也实例化 TransactionExecutor 对象,
public void schedule() throws RemoteException {mClient.scheduleTransaction(this); | |
} | |
// 最终调用 ActivityThread.scheduleTransaction(),重写了父类 ClientTransactionHandler.scheduleTransaction(),执行 transaction 操作 | |
@Override | |
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {ActivityThread.this.scheduleTransaction(transaction); | |
} | |
void scheduleTransaction(ClientTransaction transaction) {transaction.preExecute(this); | |
// 发送 handle message | |
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); | |
} |
咱们接着看下 ActivityThread handleMessage() – case EXECUTE_TRANSACTION
case EXECUTE_TRANSACTION: | |
// 获取 message | |
final ClientTransaction transaction = (ClientTransaction) msg.obj; | |
// 执行 | |
mTransactionExecutor.execute(transaction); | |
if (isSystem()) { | |
// 零碎过程內的事务在客户端回收掉 | |
transaction.recycle();} | |
// TODO(lifecycler): Recycle locally scheduled transactions. | |
break; | |
//TransactionExecutor.execute() | |
public void execute(ClientTransaction transaction) { | |
... | |
// 循环执行回调申请 | |
executeCallbacks(transaction); | |
// 执行生命周期回调 | |
executeLifecycleState(transaction); | |
... | |
} |
- executeLifecycleState()会调用 cycleToPath()用于在状态之间转换客户端,进入到
- performLifecycleSequence() , 通过之前初始化的状态转换客户端,此时状态走到 ON_CREATE,进入到
- handleLaunchActivity() – ClientTransactionHandler.java, 该类为抽象类,具体实现在 ActivityThread 中,
- ActivityThread.handleLaunchActivity() , 筹备执行启动,进入到
-
performLaunchActivity() , 启动 activity 的外围实现办法,次要解决查看包信息,组件名称,Context,组装 classLoader, 调用 mInstrumentation.newActivity()
// 启动 activity 外围实现办法 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; // 校验包信息 if (r.packageInfo == null) {r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } // 校验启动组件信息 ComponentName component = r.intent.getComponent(); if (component == null) {component = r.intent.resolveActivity(mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) {component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } // 创立 context ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { // 获取 ClassLoader - /frameworks/base/core/java/android/app/ContextImpl.java java.lang.ClassLoader cl = appContext.getClassLoader(); // 实例化 activity,反射生成 activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo), appContext.getAttributionSource()); if (r.state != null) {r.state.setClassLoader(cl); } } catch(Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to instantiate activity" + component + ":" + e.toString(), e); } } try {// 获取 Application, 默认从缓存获取,不存在通过 Instrumentation.newApplication()创立新的返回,同时回调 Application.onCreate() Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation); if (localLOGV) Slog.v(TAG, "Performing launch of" + r); if (localLOGV) Slog.v(TAG, r + ": app=" + app + ", appName=" + app.getPackageName() + ", pkg=" + r.packageInfo.getPackageName() + ", comp=" + r.intent.getComponent().toShortString() + ", dir=" + r.packageInfo.getAppDir()); // updatePendingActivityConfiguration() reads from mActivities to update // ActivityClientRecord which runs in a different thread. Protect modifications to // mActivities to avoid race. synchronized(mResourcesManager) {mActivities.put(r.token, r); } if (activity != null) {CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mConfigurationController.getCompatConfiguration()); if (r.overrideConfig != null) {config.updateFrom(r.overrideConfig); } if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity" + r.activityInfo.name + "with config" + config); // 设置 Window Window window = null; if (r.mPendingRemoveWindow != null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; r.mPendingRemoveWindow = null; r.mPendingRemoveWindowManager = null; } // 初始化 Activity resources // Activity resources must be initialized with the same loaders as the // application context. appContext.getResources().addLoaders(app.getResources().getLoaders().toArray(new ResourcesLoader[0])); // 设置以后 context appContext.setOuterContext(activity); // 调用 activity attach 办法 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.activityConfigCallback, r.assistToken, r.shareableActivityToken); // 设置 activity intent if (customIntent != null) {activity.mIntent = customIntent;} r.lastNonConfigurationInstances = null; // 期待网络规定更新 - ActivityManagerService.waitForNetworkStateUpdate() checkAndBlockForNetworkAccess(); activity.mStartedActivity = false; // 设置主题 theme int theme = r.activityInfo.getThemeResource(); if (theme != 0) {activity.setTheme(theme); } if (r.mActivityOptions != null) { activity.mPendingOptions = r.mActivityOptions; r.mActivityOptions = null; } activity.mLaunchedFromBubble = r.mLaunchedFromBubble; activity.mCalled = false; // Assigning the activity to the record before calling onCreate() allows // ActivityThread#getActivity() lookup for the callbacks triggered from // ActivityLifecycleCallbacks#onActivityCreated() or // ActivityLifecycleCallback#onActivityPostCreated(). r.activity = activity; // 开始回调 activity.onCreate() if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else {mInstrumentation.callActivityOnCreate(activity, r.state); } if (!activity.mCalled) {throw new SuperNotCalledException("Activity" + r.intent.getComponent().toShortString() + "did not call through to super.onCreate()"); } mLastReportedWindowingMode.put(activity.getActivityToken(), config.windowConfiguration.getWindowingMode()); } r.setState(ON_CREATE); } catch(SuperNotCalledException e) {throw e;} catch(Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity" + component + ":" + e.toString(), e); } } // 返回 activity 实例 return activity; } 5. 小结
在 startActivity()调用启动中,Instrumentation 类表演非常重要的角色,该类中定义了一系列 call 办法,监控着 activity 生命周期办法以及 application.onCreate()、execStartActivity()等,用来解决利用和零碎过程所有交互,在 Android 插件化相干解决中,也能够看到 hook instrumentation 相干操作,理解源码调用流程也能帮忙咱们找到适合的切入点
6. 文档阐明
因为源码流程较长,整体调用链十分繁冗,可能存在错漏的中央,欢送在浏览时提出问题和有余
参考文档:
Android Code Search
/ – OpenGrok cross reference for / (aospxref.com)