Android 桌面App启动与startActivity流程

MannaYang / 115 /

ChatGPT 可用网址,仅供交流学习使用,如对您有所帮助,请收藏并推荐给需要的朋友。
https://ckai.xyz

本文基于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)


Android 桌面App启动与startActivity流程
作者
MannaYang
许可协议
CC BY 4.0
发布于
2023-09-25
修改于
2024-07-15
Bonnie image
尚未登录