乐于分享
好东西不私藏

Android Framework源码解析(六):Launcher3 启动流程详解——AMS 如何拉起系统桌面?

Android Framework源码解析(六):Launcher3 启动流程详解——AMS 如何拉起系统桌面?

前文回顾

在前面的系列文章中,我们沿着 Android 系统启动链路,完整梳理了 Framework 从无到有的初始化全过程。

首先,init 进程作为 Android 用户空间的首个进程,负责解析 init.rc 配置、挂载系统文件、拉起各类 Native 服务,为系统运行搭建基础环境。

随后 Zygote 进程 启动,预加载 Framework 核心类、系统资源与通用依赖库,通过 fork 机制孵化出 system_server 进程与所有应用进程,是 Android 高效进程管理的核心基石。

紧接着 SystemServer 完成 Framework 顶层初始化,依次启动 AMS、PMS、WMS 等数百个核心系统服务。上一篇文章我们重点解析了 SystemServiceManager,搞懂了系统服务的统一创建、管理逻辑,以及 BootPhase 开机阶段的核心设计思想。

至此,整个 Android 开机启动链路还剩下最后两块核心拼图:

  1. 开机系统如何自动拉起 Launcher 桌面;
  2. 用户点击桌面图标后,应用完整启动交互流程。

我们日常开机后自动展示的 Launcher 桌面,本质只是一个普通 APK,既不是 Native 服务,也不是 Framework 内置的 SystemService。衍生出几个核心疑问:

  • Launcher 究竟是谁触发启动的?
  • AMS 如何精准匹配、找到系统默认的 Launcher 桌面应用?
  • 为什么开机只会自动启动桌面,而非其他普通应用?
  • Launcher 凭什么成为系统默认的 Home 桌面应用?
  • 点击桌面图标后,从触摸到打开 App 完整链路是什么?

本文延续 Framework 启动源码链路,从 SystemServer 启动收尾阶段开始,逐层拆解 Launcher3 完整启动流程,覆盖系统拉起 Launcher、Activity 初始化、桌面数据加载、UI 渲染、图标点击交互全流程,彻底打通 Android 开机进桌面、点击图标启动应用的底层原理。

一、Launcher 启动入口:SystemServer 收尾触发

Launcher 并非独立自启动,而是由 system_server 进程 在系统服务初始化完成后主动拉起。核心入口在 SystemServer 的 startOtherServices 方法中。

1.1 SystemServer 核心触发源码

privatevoidstartOtherServices() {    // 省略大量系统服务初始化逻辑...    // 所有核心服务启动完成后,调用AMS的systemReady方法    mActivityManagerService.systemReady(() -> {/* 开机收尾回调逻辑 */}, BOOT_TIMINGS_TRACE_LOG);}

当所有系统服务初始化完毕后,会调用 AMS.systemReady(),标志系统开机流程进入收尾阶段,Launcher 桌面的启动逻辑就封装在该方法中

1.2 AMS.systemReady 启动桌面核心逻辑

publicvoidsystemReady(final Runnable goingCallback, TimingsTraceLog traceLog){    // 省略系统就绪校验、服务初始化收尾逻辑...    // 核心:触发所有屏幕的Home桌面启动    mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");}

关键说明

  • mAtmInternal
     类型为 ActivityTaskManagerInternal,是 ATMS(ActivityTaskManagerService)的内部本地服务实现类
  • 设计核心:解耦 AMS 与 ATMS,避免两大核心服务循环依赖、强耦合

两大服务职责拆分(核心设计思想):

  • AMS
    :管控进程生命周期、应用权限、广播、四大组件服务、系统任务调度
  • ATMS
    :专注 Activity 栈管理、Task 任务栈、窗口层级、屏幕显示、桌面启动、页面跳转

ActivityTaskManagerInternal 是 ATMS 暴露给 AMS、SystemServer 等系统模块的唯一调用入口,保证模块间低耦合。

二、ATMS 逐层分发:多屏幕桌面启动逻辑

2.1 全局桌面启动入口

ATMS 中 startHomeOnAllDisplays 为多屏幕桌面启动统一入口,支持主屏、副屏、车载扩展屏等多设备场景。

@Overridepublic boolean startHomeOnAllDisplays(int userId, String reason) {    synchronized (mGlobalLock) {        // 全局锁保证桌面启动线程安全        return mRootWindowContainer.startHomeOnAllDisplays(userId, reason);    }}

2.2 核心容器:RootWindowContainer 层级架构

RootWindowContainer 是 Android 窗口容器树的唯一根节点,所有屏幕、窗口、任务栈、应用页面都挂载在其下,继承关系:RootWindowContainer → WindowContainer → ConfigurationContainer

完整窗口容器树层级(自上而下):

RootWindowContainer(全局窗口根节点)├─ DisplayContent #0(设备主屏)│  ├─ DisplayArea.Root│  │  ├─ TaskDisplayArea(APP任务窗口区域)│  │  │  ├─ Task(独立任务栈,Launcher为独立RootHomeTask)│  │  │  │  └─ ActivityRecord(Launcher Activity实例)│  │  │  │     └─ WindowState(应用DecorView顶层窗口)│  │  │  └─ Task(普通应用任务栈)│  │  ├─ ImeContainer(输入法窗口容器)│  │  └─ DisplayArea.Tokens(状态栏、弹窗、壁纸等系统窗口)│  └─ NonAppWindowContainers(系统装饰窗口)├─ DisplayContent #1(副屏/车载后座屏/虚拟屏)└─ DisplayContent #2(扩展屏幕)

文件路径:frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

2.3 遍历所有屏幕启动桌面

boolean startHomeOnAllDisplays(int userId, String reason) {    boolean homeStarted = false;    // 倒序遍历所有屏幕设备    for (int i = getChildCount() - 1; i >= 0; i--) {        final int displayId = getChildAt(i).mDisplayId;        // 逐个屏幕触发桌面启动        homeStarted |= startHomeOnDisplay(userId, reason, displayId);    }    return homeStarted;}// 单屏幕桌面启动重载方法boolean startHomeOnDisplay(int userId, String reason, int displayId) {    return startHomeOnDisplay(userId, reason, displayId, false /* 不允许自动化测试启动 */,            false /* 非Home键触发,开机流程固定false */);}

五参方法参数详细释义(开机流程标准入参):

  • userId
    :当前系统用户 ID,设备开机默认用户为 0
  • reason
    :触发标识,开机为 systemReady,手动点 Home 键为 homeKey
  • displayId
    :目标启动桌面的屏幕 ID
  • allowInstrumenting
    :是否允许自动化测试拉起桌面,正常开机为 false
  • fromHomeKey
    :是否为用户点击 Home 键触发,开机流程为 false

2.4 单屏幕任务区域桌面启动逻辑

boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,        boolean fromHomeKey) {    // 兼容无效屏幕ID,兜底聚焦屏幕/默认主屏    if (displayId == INVALID_DISPLAY) {        final Task rootTask = getTopDisplayFocusedRootTask();        displayId = rootTask != null ? rootTask.getDisplayId() : DEFAULT_DISPLAY;    }    // 根据屏幕ID获取对应屏幕实例    final DisplayContent display = getDisplayContent(displayId);    // 遍历当前屏幕所有任务区域,尝试启动桌面    return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->                    result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,                            allowInstrumenting, fromHomeKey),            false /* 初始值 */);}

三、核心流程:匹配默认 Launcher 桌面应用

startHomeOnTaskDisplayArea 是启动 Launcher 的核心方法,负责构建桌面专属 Intent、通过 PMS 匹配系统默认桌面应用、校验启动权限,最终拉起 Launcher。

boolean startHomeOnTaskDisplayArea(    int userId,                // 当前系统用户ID    String reason,              // 启动触发来源    TaskDisplayArea taskDisplayArea, // 当前任务显示区域    boolean allowInstrumenting, // 是否允许自动化测试启动    boolean fromHomeKey         // 是否为Home键触发) {    // 兜底无效任务区域    if (taskDisplayArea == null) {        final Task rootTask = getTopDisplayFocusedRootTask();        taskDisplayArea = rootTask != null ? rootTask.getDisplayArea()                : getDefaultTaskDisplayArea();    }    Intent homeIntent = null;    ActivityInfo aInfo = null;    // 主屏/主桌面启动逻辑    if (taskDisplayArea == getDefaultTaskDisplayArea()            || mWmService.shouldPlacePrimaryHomeOnDisplay(                    taskDisplayArea.getDisplayId(), userId)) {        // 获取标准HOME桌面Intent        homeIntent = mService.getHomeIntent();        // 核心:通过PMS查询系统默认的Launcher桌面Activity        aInfo = resolveHomeActivity(userId, homeIntent);    }     // 副屏/车载二级桌面启动逻辑    else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {        Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);        aInfo = info.first;        homeIntent = info.second;    }    // 未查询到桌面应用,直接返回    if (aInfo == null || homeIntent == null) {        return false;    }    // 校验当前区域是否允许启动桌面    if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea, allowInstrumenting)) {        return false;    }    // 主题动画延时配置,延迟启动桌面    if (mService.mAmInternal.shouldDelayHomeLaunch(userId)) {        Slog.d(TAG, "ThemeHomeDelay: Home launch was deferred with user " + userId);        return false;    }    // 绑定真实Launcher组件信息    homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));    // 新建独立任务栈启动桌面    homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);    // Home键专属逻辑,开机流程不执行    if (fromHomeKey) {        homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);        if (mWindowManager.getRecentsAnimationController() != null) {            mWindowManager.getRecentsAnimationController().cancelAnimationForHomeStart();        }    }    // 携带启动原因参数,用于日志调试    homeIntent.putExtra(WindowManagerPolicy.EXTRA_START_REASON, reason);    // 组装完整调试标识:触发原因:用户ID:应用UID:屏幕ID    final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(            aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId();    // 进入标准Activity启动流水线,拉起Launcher    mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,            taskDisplayArea);    return true;}

3.1 标准桌面 Intent 构建规则

系统通过固定 Action、Category 唯一匹配桌面应用,这也是普通应用无法成为默认桌面的核心原因。

Intent getHomeIntent() {    Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);    intent.setComponent(mTopComponent);    intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);    // 工厂测试模式除外,普通开机添加HOME分类    if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {        intent.addCategory(Intent.CATEGORY_HOME);    }    return intent;}

核心匹配规则:桌面应用必须匹配 Intent.ACTION_MAIN + Intent.CATEGORY_HOME

四、ActivityStartController 拉起 Launcher 桌面

文件目录:/frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java

通过系统启动控制器,将桌面 Activity 加入独立 RootHomeTask 任务栈,全屏启动 Launcher。

void startHomeActivity(    Intent intent,               // 组装完成的HOME Intent    ActivityInfo aInfo,          // Launcher桌面Activity信息    String reason,               // 调试日志标识    TaskDisplayArea taskDisplayArea // 目标任务区域) {    // 构建Activity启动配置    final ActivityOptions options = ActivityOptions.makeBasic();    // 全屏模式启动桌面    options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);    // 标记为HOME类型Activity,区别于普通应用    if (!ActivityRecord.isResolverActivity(aInfo.name)) {        options.setLaunchActivityType(ACTIVITY_TYPE_HOME);    }    final int displayId = taskDisplayArea.getDisplayId();    options.setLaunchDisplayId(displayId);    options.setLaunchTaskDisplayArea(taskDisplayArea.mRemoteToken            .toWindowContainerToken());    // 延迟Resume,避免递归启动、重复刷新    mSupervisor.beginDeferResume();    final Task rootHomeTask;    try {        // 创建/获取桌面专属根任务栈        rootHomeTask = taskDisplayArea.getOrCreateRootHomeTask(ON_TOP);    } finally {        mSupervisor.endDeferResume();    }    // 执行标准Activity启动流水线    mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)            .setOutActivity(tmpOutRecord)            .setCallingUid(0)            .setActivityInfo(aInfo)            .setActivityOptions(options.toBundle())            .execute();    mLastHomeActivityStartRecord = tmpOutRecord[0];    // 调度顶层Activity Resume,完成桌面显示    if (rootHomeTask.mInResumeTopActivity) {        mSupervisor.scheduleResumeTopActivities();    }}

五、Launcher3 客户端初始化与数据加载流程

系统服务端完成 Launcher 进程拉起、Activity 创建后,进入 Launcher3 客户端初始化逻辑,完成布局加载、应用数据刷新、桌面 UI 渲染。

5.1 Launcher 主页面 onCreate 初始化

protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    // 初始化Launcher全局状态    LauncherAppState app = LauncherAppState.getInstance(this);    mModel = app.getModel(); // 桌面核心数据源模型    mRotationHelper = new RotationHelper(this); // 屏幕旋转监听    InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); // 屏幕尺寸适配配置    initDeviceProfile(idp);    idp.addOnChangeListener(this);    mSharedPrefs = LauncherPrefs.getPrefs(this); // 桌面本地配置    mIconCache = app.getIconCache(); // 应用图标缓存    mAccessibilityDelegate = createAccessibilityDelegate();    initDragController(); // 图标拖拽、文件夹拖动控制器    mAllAppsController = new AllAppsTransitionController(this); // 全部应用列表动画控制器    mStateManager = new StateManager<>(this, NORMAL); // 桌面状态管理(普通/全部应用/弹窗)    setupViews();  // 初始化桌面布局:Workspace、全部应用列表、Dock栏    updateDisallowBack();    // 桌面小组件初始化    mAppWidgetManager = new WidgetManagerHelper(this);    mAppWidgetHolder = createAppWidgetHolder();    mAppWidgetHolder.startListening();    mAppWidgetHolder.addProviderChangeListener(() -> refreshAndBindWidgetsForPackageUser(null));    // 核心:注册回调并加载所有应用数据    if (!mModel.addCallbacksAndLoad(this)) {        if (!internalStateHandled) {            // 同步绑定失败时,延迟绘制,等待数据加载完成            mOnInitialBindListener = Boolean.FALSE::booleanValue;        }    }    setContentView(getRootView()); // 加载根布局    ComposeInitializer.initCompose(this);    // 触控板滚动配置监听    settingsCache.register(TOUCHPAD_NATURAL_SCROLLING, mNaturalScrollingChangedListener);    mIsNaturalScrollingEnabled = settingsCache.getValue(TOUCHPAD_NATURAL_SCROLLING);    // 屏幕亮灭状态监听    ScreenOnTracker.INSTANCE.get(this).addListener(mScreenOnListener);    getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,            Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));    mRotationHelper.initialize(); // 初始化屏幕旋转逻辑}

5.2 核心:后台线程加载全量应用数据

文件路径:src/com/android/launcher3/LauncherModel.kt 初始化链路:Launcher.onCreate() -> mModel.addCallbacksAndLoad() -> 后台线程加载数据

// addCallbacksAndLoad 核心逻辑funaddCallbacksAndLoad(callbacks: Callbacks)Boolean {    addCallbacks(callbacks) // 注册UI回调    return startLoader(callbacks) // 启动数据加载器}funstartLoader(newCallbacks: Callbacks)Boolean {    return if (mModelLoaded) {        // 数据已加载,直接同步绑定UI        bindDirectly(newCallbacks)        true    } else {        // 未加载,创建LoaderTask,投递到后台线程执行        MODEL_EXECUTOR.post(mLoaderTask)        false    }}

5.3 LoaderTask 后台全量数据加载流程

文件路径:src/com/android/launcher3/model/LoaderTask.java

后台线程异步加载桌面所有数据源,避免阻塞 UI,核心四大步骤:

@Overridepublic void run() {    // Step1:加载桌面布局、快捷方式、小组件配置(本地数据库)    loadWorkspace(...);    mLauncherBinder.bindWorkspace(...);    // Step2:加载系统所有已安装应用(核心步骤)    loadAllApps();    mLauncherBinder.bindAllApps();    // Step3:加载应用深度快捷方式    loadDeepShortcuts();    mLauncherBinder.bindDeepShortcuts();    // Step4:加载桌面Widget小组件数据    loadWidgets();    mLauncherBinder.bindWidgets();}

5.4 loadAllApps 应用列表查询核心逻辑

遍历系统所有用户空间,查询所有可在桌面展示的应用,封装为应用数据模型。

private List<LauncherActivityInfo> loadAllApps() {    // 获取所有用户空间(主用户、工作空间、私有空间)    List<UserHandle> profiles = mUserCache.getUserProfiles();    mBgAllAppsList.clear();    for (UserHandle user : profiles) {        // 调用系统服务,查询当前用户下所有可启动应用        // packageName传null:查询全局所有应用        List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);        // 封装为桌面应用数据模型        for (LauncherActivityInfo app : apps) {            AppInfo appInfo = new AppInfo(app, ...);            mBgAllAppsList.add(appInfo, app, false);        }    }    // 批量缓存应用图标、名称,优化加载速度    mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);}

六、Binder 跨进程通信:Launcher 与系统服务数据交互

Launcher 作为第三方应用,无法直接访问 PMS 核心数据,通过 LauncherApps 系统 API + Binder IPC 跨进程调用 system_server 服务获取应用列表。

6.1 客户端:LauncherApps 调用入口

文件:frameworks/base/core/java/android/content/pm/LauncherApps.java

public List<LauncherActivityInfogetActivityList(String packageName, UserHandle user) {    logErrorForInvalidProfileAccess(user);    try {        // Binder跨进程调用系统服务        return convertToActivityList(                mService.getLauncherActivities(mContext.getPackageName(), packageName, user),                user);    } catch (RemoteException re) {        throw re.rethrowFromSystemServer();    }}

mService 为 AIDL 代理对象,通过 ServiceManager 获取系统常驻的 launcherapps 服务。

6.2 服务端:LauncherAppsService 核心实现

文件:frameworks/base/services/core/java/com/android/server/pm/LauncherAppsService.java

系统服务端接收 Launcher 跨进程请求,通过 PMS 解析符合桌面规则的应用。

public ParceledListSlice<LauncherActivityInfoInternalgetLauncherActivities(        String callingPackage, String packageName, UserHandle user) {    // 核心Intent规则:匹配所有桌面可展示应用    ParceledListSlice<LauncherActivityInfoInternal> launcherActivities =            queryActivitiesForUser(callingPackage,                    new Intent(Intent.ACTION_MAIN)                            .addCategory(Intent.CATEGORY_LAUNCHER)                            .setPackage(packageName),                    user);    // 处理归档应用、隐藏应用合成图标    return result;}

6.3 最终底层:PMS 意图解析应用

private List<LauncherActivityInfoInternal> queryIntentLauncherActivities(        Intent intent, int callingUid, UserHandle user) {    // 调用PMS核心方法,解析所有匹配Intent的Activity    final List<ResolveInfo> apps = mPackageManagerInternal.queryIntentActivities(            intent,            intent.resolveTypeIfNeeded(mContext.getContentResolver()),            PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,            callingUid,            user.getIdentifier());    // 封装数据返回}

核心规则总结:只有 AndroidManifest 中声明 ACTION_MAIN + CATEGORY_LAUNCHER 的应用,才会被桌面识别、展示图标。

七、跨进程调用全链路图示

┌─────────────────────────────────────────────────────────────┐│  Launcher3 应用进程(客户端)                                ││                                                             ││  LoaderTask.loadAllApps()                                   ││    └─ mLauncherApps.getActivityList(nulluser)             ││        └─ mService.getLauncherActivities(...)               ││            │  ← ILauncherApps AIDL代理发起请求               │└────────────┼────────────────────────────────────────────────┘             │ Binder IPC 跨进程通信┌────────────▼────────────────────────────────────────────────┐│  system_server 系统进程(服务端)                            ││                                                             ││  LauncherAppsService.getLauncherActivities(...)              ││    └─ queryActivitiesForUser(...)                            ││        └─ queryIntentLauncherActivities(...)                 ││            └─ PMS.queryIntentActivities(                     ││                   Intent(ACTION_MAIN + CATEGORY_LAUNCHER)    ││               )                                              ││  最终:解析所有声明桌面入口的应用,返回给Launcher3           │└─────────────────────────────────────────────────────────────┘

八、UI 数据绑定与桌面最终渲染

8.1 后台数据快照拷贝与主线程切换

文件路径:src/com/android/launcher3/model/BaseLauncherBinder.java

publicvoidbindAllApps() {    // 拷贝排序后的稳定数据快照,避免后台线程数据篡改    AppInfo[] apps = mBgAllAppsList.copyData();    int flags = mBgAllAppsList.getFlags();    // 构建包名-UID映射表    Map<PackageUserKey, Integer> packageUserKeytoUidMap = Arrays.stream(apps).collect(            Collectors.toMap(                    appInfo -> new PackageUserKey(appInfo.componentName.getPackageName(),                            appInfo.user),                    appInfo -> appInfo.uid,                    (a, b) -> a));    // 切换主线程执行UI绑定    executeCallbacksTask(c -> c.bindAllApplications(apps, flags, packageUserKeytoUidMap),            mUiExecutor);}

8.2 数据更新与 RecyclerView 高效刷新

通过 AllAppsStore 统一管理数据源,采用 DiffUtil 差分刷新,避免全局重绘,提升桌面流畅度。

public void setApps(@NullableAppInfo[] apps, int flags, Map<PackageUserKeyInteger> map) {    mApps = apps == null ? EMPTY_ARRAY : apps; // 存储最新应用数据    mModelFlags = flags;    notifyUpdate(); // 通知UI刷新    mPackageUserKeytoUidMap = map;}// 通知所有监听者更新UIprivate void notifyUpdate() {    if (mDeferUpdatesFlags != 0) {        mUpdatePending = true;        return;    }    for (OnUpdateListener listener : mUpdateListeners) {        listener.onAppsUpdated();    }}

8.3 最终 UI 渲染流程

  1. AlphabeticalAppsList
    :过滤、排序应用列表,生成有序数据源
  2. DiffUtil
    :计算新旧数据差异,精准刷新 RecyclerView
  3. BaseAllAppsAdapter
    :创建 BubbleTextView(图标 + 文字控件),绑定应用信息
  4. ActivityAllAppsContainerView
    :多用户场景 Tab 栏管理、列表切换

九、Launcher3 图标点击事件完整执行流程

前文我们梳理完 Launcher 开机启动、数据加载、UI 渲染全流程,桌面展示图标后,核心交互就是应用图标点击启动事件。本节详解 Launcher3 图标点击监听器注册、事件分发、Intent 构建、应用启动的完整源码逻辑,吃透桌面点击交互的分层设计。

9.1 点击监听器统一注册机制

Launcher 桌面所有应用图标(桌面常驻图标、全部应用抽屉图标)的控件均为 BubbleTextView,全局共用同一个点击处理器,单例复用,规避重复创建监听器造成的内存浪费。

9.1.1 桌面图标监听器注册(ItemInflater.kt)

private funcreateShortcut(info: WorkspaceItemInfo, parent: ViewGroup): View {    val favorite = LayoutInflater.from(parent.context)            .inflate(R.layout.app_icon, parent, falseas BubbleTextView    favorite.applyFromWorkspaceItem(info)    favorite.setOnClickListener(clickListener)  // ← ItemClickHandler.INSTANCE 全局单例    return favorite}

9.1.2 全部应用抽屉图标监听器注册(BaseAllAppsAdapter.java)

icon.setOnClickListener(mOnIconClickListener);  // 同样指向 ItemClickHandler.INSTANCE

9.1.3 全局监听器绑定原理

为什么两处点击监听最终都是 ItemClickHandler.INSTANCE

  1. Launcher
     继承 BaseDraggingActivity
  2. Launcher 重写 getItemOnClickListener() 方法
  3. 页面上下文 mActivityContext 实际为 Launcher 实例,方法固定返回全局单例 ItemClickHandler.INSTANCE

设计优势:全局图标事件统一入口,便于统一拦截、埋点、动画、异常处理,架构简洁易扩展。

9.2 统一事件分发入口:ItemClickHandler.onClick ()

所有图标点击事件都会进入该静态统一方法,通过 View.getTag() 取出控件绑定的数据对象,根据实体类型分发不同启动逻辑。 文件: ItemClickHandler.java

public static final OnClickListener INSTANCE = ItemClickHandler::onClick;private static void onClick(View v) {    if (v.getWindowToken() == nullreturn;  // view已脱离窗口,忽略无效点击    Launcher launcher = Launcher.getLauncher(v.getContext());    if (!launcher.getWorkspace().isFinishedSwitchingState()) return;  // 桌面切换动画中,拦截点击    Object tag = v.getTag();  // 每个BubbleTextView的tag存储对应业务数据模型    if (tag instanceof WorkspaceItemInfo) {        onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);   // 桌面常驻图标    } else if (tag instanceof FolderInfo) {        onClickFolderIcon(v);                                        // 文件夹图标    } else if (tag instanceof AppInfo) {        startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher); // 应用抽屉图标    }}

关键设计:每个 BubbleTextView 的 tag 字段提前绑定数据对象(AppInfo / WorkspaceItemInfo),点击无需二次查询,直接类型判断分发,性能高效。

9.3 桌面图标专项处理逻辑

针对桌面常驻图标(WorkspaceItemInfo),单独做异常状态拦截,适配禁用应用、安装中占位图标等特殊场景。

public static void onClickAppShortcut(View v, WorkspaceItemInfo shortcut, Launcher launcher) {    // 检查应用是否被禁用、暂停、设备管理器限制    if (shortcut.isDisabled() && handleDisabledItemClicked(shortcut, launcher)) {        return;  // 弹出提示Toast,不执行启动    }    // 处理应用安装中占位图标(承诺图标)    if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {        String packageName = shortcut.getIntent().getComponent().getPackageName();        if (!TextUtils.isEmpty(packageName)) {            onClickPendingAppItem(v, launcher, packageName, ...);  // 跳转应用商店            return;        }    }    // 正常应用统一进入启动汇合方法    startAppShortcutOrInfoActivity(v, shortcut, launcher);}

9.4 应用启动汇合核心方法:startAppShortcutOrInfoActivity ()

桌面图标、全部应用抽屉图标最终都会进入此方法,统一处理 Intent 适配、特殊场景、启动动画,再调用安全启动接口。

private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {    // ① 获取预构建好的启动 Intent    Intent intent = item.getIntent();    // ② 特殊处理:正在安装中的应用,替换商店跳转Intent    if (item instanceof ItemInfoWithIcon itemInfoWithIcon) {        if ((itemInfoWithIcon.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) {            intent = ApiWrapper.INSTANCE.get(launcher)                    .getAppMarketActivityIntent(packageName, Process.myUserHandle());        }    }    // ③ 特殊处理:支持Web UI的快捷方式,清除包名允许浏览器选择器    if (item instanceof WorkspaceItemInfo si) {        if (si.hasStatusFlag(FLAG_SUPPORTS_WEB_UI) && ACTION_VIEW.equals(intent.getAction())) {            intent = new Intent(intent);            intent.setPackage(null);        }    }    // ④ 初始化图标放大过渡动画    if (v != null && launcher.supportsAdaptiveIconAnimation(v)) {        FloatingIconView.fetchIcon(launcher, v, item, true);    }    // ⑤ 调用分层安全启动入口    launcher.startActivitySafely(v, intent, item);}

9.5 Intent 预构建逻辑

Launcher 所有应用启动 Intent 全部预构建、持久化存储,点击时直接复用,无需实时拼接,提升点击响应速度。

9.5.1 全部应用图标 AppInfo

// AppInfo.javapublic static Intent makeLaunchIntent(ComponentName cn) {    return new Intent(Intent.ACTION_MAIN)            .addCategory(Intent.CATEGORY_LAUNCHER)            .setComponent(cn)    // 绑定应用唯一组件名            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);}

9.5.2 桌面常驻图标 WorkspaceItemInfo

桌面图标信息持久化存储在 launcher.db 的 favorites 表中,开机加载时直接从数据库反序列化还原 intent 字段。

public Intent intent;  // 序列化存入数据库,启动直接读取

9.6 分层安全启动:多层 startActivitySafely 职责拆分

采用分层架构,三层 startActivitySafely 层层包装,各司其职、解耦业务逻辑。

9.6.1 第一层 QuickstepLauncher:桌面 UI 动画适配

负责 Hotseat 预测行 UI 暂停与恢复,避免启动动画时界面闪烁错乱。

@Overridepublic RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {    // 暂停Hotseat预测行UI刷新    mHotseatPredictionController.setPauseUIUpdate(true);    PredictionRowView predictionRowView = ...;    predictionRowView.setPredictionUiUpdatePaused(true);    // 调用父类启动逻辑    RunnableList result = super.startActivitySafely(v, intent, item);    // 应用启动动画结束后恢复UI更新    if (result != null) {        result.add(() -> {            mHotseatPredictionController.setPauseUIUpdate(false);            predictionRowView.setPredictionUiUpdatePaused(false);        });    }    return result;}

9.6.2 第二层 Launcher:页面生命周期保护

处理 Launcher 页面未 Resume 场景延迟启动,添加图标按压视觉反馈。

@Overridepublic RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {    // Launcher未恢复前台,延迟至Resume后再启动应用    if (!hasBeenResumed()) {        addEventCallback(EVENT_RESUMED, () -> {            startActivitySafely(v, intent, item);        });        return result;    }    // 调用底层启动逻辑    RunnableList result = super.startActivitySafely(v, intent, item);    // 图标保持按下状态,动画结束后取消    if (result != null && v instanceof BubbleTextView btv) {        btv.setStayPressed(true);        result.add(() -> btv.setStayPressed(false));    }    return result;}

9.6.3 第三层 ActivityContext:底层系统启动入口

最底层核心,安全校验、动画参数封装、区分三种启动路径,最终调用 Framework 启动 Activity。

default RunnableList startActivitySafely(View v, Intent intent, @Nullable ItemInfo item) {    Context context = (Context) this;    // 安全模式校验:禁止启动第三方应用    if (isAppBlockedForSafeMode() && !appInfo.isSystem()) {        Toast.makeText(context, R.string.safemode_shortcut_error, ...).show();        return null;    }    // 构建启动动画参数,携带图标坐标、尺寸    ActivityOptionsWrapper options = v != null            ? getActivityLaunchOptions(v, item)            : makeDefaultActivityOptions(...);    UserHandle user = item.user;    Bundle optsBundle = options.toBundle();    // 新建独立任务栈    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);    if (v != null) {        intent.setSourceBounds(Utilities.getViewBounds(v)); // 动画起始坐标    }    try {        boolean isShortcut = (item instanceof WorkspaceItemInfo)                && item.itemType == ITEM_TYPE_DEEP_SHORTCUT;        // 三条启动分支        if (isShortcut) {            // 路径A:长按深度快捷方式            String id = ((WorkspaceItemInfo) item).getDeepShortcutId();            context.getSystemService(LauncherApps.class)                    .startShortcut(packageName, id, sourceBounds, optsBundle, user);        } else if (user == null || user.equals(Process.myUserHandle())) {            // 路径B:同用户普通App(最主流)            context.startActivity(intent, optsBundle);        } else {            // 路径C:工作Profile/跨用户应用            context.getSystemService(LauncherApps.class)                    .startMainActivity(intent.getComponent(), user, sourceBounds, optsBundle);        }        // 埋点记录应用启动日志        logAppLaunch(getStatsLogManager(), item, instanceId);        return options.onEndCallback;    } catch (ActivityNotFoundException | SecurityException e) {        Toast.makeText(context, R.string.activity_not_found, ...).show();    }    return null;}

9.7 三种启动路径对比表

场景
调用方式
说明
普通 App(同用户)
context.startActivity(intent, optsBundle)
最常用,直接调用 Activity 启动 API,性能最优
工作 profile / 跨用户 App
LauncherApps.startMainActivity(component, user, ...)
多用户隔离,通过系统服务代理,权限管控
深度快捷方式(长按菜单)
LauncherApps.startShortcut(pkg, id, ...)
专属快捷方式启动逻辑,支持快捷参数透传

9.8 图标点击事件完整全链路流程图

┌──────────────────────────────────────────────────────────────────┐│  用户手指触摸 BubbleTextView                                      ││  (tag = AppInfo / WorkspaceItemInfo)                             │└───────────────┬──────────────────────────────────────────────────┘                │ View.OnClickListener.onClick()                ▼┌──────────────────────────────────────────────────────────────────┐│  ItemClickHandler.onClick(view)                                   ││  ├── 检查窗口有效性,过滤已销毁View                               ││  ├── 检查Workspace动画状态,动画中拦截点击                        ││  └── 根据tag实体类型分发桌面图标/抽屉图标/文件夹逻辑              │└───────────────┬──────────────────────────────────────────────────┘                │                ▼┌──────────────────────────────────────────────────────────────────┐│  startAppShortcutOrInfoActivity(v, item, launcher)               ││  ├── 取出预构建 Intent(ACTION_MAIN + CATEGORY_LAUNCHER + ComponentName) ││  ├── 处理安装中应用、Web快捷方式特殊场景                          ││  ├── 初始化图标放大过渡动画 FloatingIconView                     ││  └── 调用 launcher.startActivitySafely(v, intent, item)           │└───────────────┬──────────────────────────────────────────────────┘                │                ▼┌──────────────────────────────────────────────────────────────────┐│  QuickstepLauncher.startActivitySafely()                         ││  └── 暂停Hotseat预测行UI更新 → 调用父类方法                       │└───────────────┬──────────────────────────────────────────────────┘                │                ▼┌──────────────────────────────────────────────────────────────────┐│  Launcher.startActivitySafely()                                   ││  ├── 页面未Resume则延迟至前台后启动                                ││  ├── 设置图标持续按压视觉反馈                                     ││  └── 调用底层ActivityContext启动接口                              │└───────────────┬──────────────────────────────────────────────────┘                │                ▼┌──────────────────────────────────────────────────────────────────┐│  ActivityContext.startActivitySafely()         ← 系统最终启动入口  ││  ├── 安全模式第三方应用拦截校验                                   ││  ├── 构造ActivityOptions动画参数,携带图标坐标                    ││  ├── intent添加FLAG_ACTIVITY_NEW_TASK标识                         ││  ├── 分支1:深度快捷方式 → LauncherApps.startShortcut()           ││  ├── 分支2:同用户普通应用 → context.startActivity() ★核心路径    ││  └── 分支3:跨用户工作区应用 → LauncherApps.startMainActivity()   ││  最后:logAppLaunch 记录启动埋点日志                              │└───────────────┬──────────────────────────────────────────────────┘                │                ▼┌──────────────────────────────────────────────────────────────────┐│  Android Framework (AMS) 系统层                                   ││  AMS接收启动请求 → 创建/复用应用进程 → 启动目标Activity → 渲染应用窗口 │└──────────────────────────────────────────────────────────────────┘

9.9 点击交互核心设计总结

  1. 全局统一单例监听器
    :所有图标共用 ItemClickHandler.INSTANCE,通过 Tag 区分数据模型,统一管控点击逻辑,易埋点、易拦截、易扩展;
  2. Intent 预加载机制
    :应用启动 Intent 在桌面初始化 / 数据库加载阶段提前构建存储,点击直接复用,无实时拼接耗时;
  3. 分层职责架构
    :UI 动画层、生命周期层、系统底层启动层三层拆分,代码解耦,各司其职;
  4. 多用户场景兼容
    :区分普通应用、工作 Profile 应用、深度快捷方式三套启动逻辑,适配原生多用户隔离机制;
  5. 流畅动画联动
    :通过 ActivityOptions 传递图标坐标,系统实现图标放大过渡动画,提升交互体验。

十、全文整体流程总览

┌───────────── 系统服务端流程(system_server) ─────────────┐ SystemServer.startOtherServices()                            AMS.systemReady()                                          ATMS.startHomeOnAllDisplays()                              RootWindowContainer 多屏幕遍历                              构建 HOME 专属 Intent(ACTION_MAIN+CATEGORY_HOME)          PMS 匹配系统默认 Launcher 应用                             ActivityStartController 拉起 Launcher Activity           └───────────────────────────┬───────────────────────────────┘                             启动Launcher应用进程┌───────────── Launcher3客户端开机初始化流程 ────────────────┐ Launcher.onCreate() 初始化全局组件布局缓存               后台LoaderTask线程加载桌面布局所有应用小组件数据       Binder IPC调用LauncherAppsService,从PMS查询应用列表      主线程差分刷新RecyclerView,渲染桌面图标UI               └───────────────────────────┬───────────────────────────────┘                             用户点击图标触发交互┌───────────── Launcher图标点击交互流程 ─────────────────────┐ BubbleTextView点击  ItemClickHandler统一分发                预取Intent处理各类特殊场景初始化过渡动画               分层startActivitySafely安全启动应用                        区分普通应用/跨用户应用/深度快捷方式三种启动路径            交由AMS创建进程启动目标应用Activity                    └───────────────────────────────────────────────────────────┘

十一、全文核心知识点总结

1. 系统开机拉起 Launcher 相关

  1. Launcher 由 system_server 在 systemReady 阶段主动拉起,并非自启动;
  2. AMS 与 ATMS 通过 ActivityTaskManagerInternal 本地接口解耦,避免循环依赖;
  3. 系统识别桌面的唯一标识:ACTION_MAIN + CATEGORY_HOME
  4. RootWindowContainer
     是全局窗口树根节点,原生支持多主屏、副屏、车载扩展屏,对应源码路径 frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

2. Launcher 桌面数据加载相关

  1. 应用列表通过 LauncherApps AIDL 跨进程调用 system_server 的 PMS 查询;
  2. 仅 AndroidManifest 声明ACTION_MAIN + CATEGORY_LAUNCHER的应用才会显示桌面图标;
  3. 数据后台子线程加载,主线程 DiffUtil 差分刷新 UI,避免开机卡顿。

3. 图标点击交互相关

  1. 全局单例 ItemClickHandler 统一处理所有图标点击,通过 View.tag 区分业务数据;
  2. Intent 预构建持久化存储,点击直接复用,降低耗时;
  3. 三层 startActivitySafely 分层设计,分别处理 UI 动画、页面生命周期、底层应用启动;
  4. 原生支持多用户隔离,普通应用、工作区应用、深度快捷方式拥有独立启动链路;
  5. ActivityOptions 携带图标坐标,实现桌面图标到应用窗口的流畅过渡动画。
基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-14 16:10:30 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/855736.html
  2. 运行时间 : 0.103397s [ 吞吐率:9.67req/s ] 内存消耗:4,997.95kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=08f696a7189b4ab5dec0f84b76cc54ac
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000610s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000886s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000307s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000296s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000478s ]
  6. SELECT * FROM `set` [ RunTime:0.000206s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000582s ]
  8. SELECT * FROM `article` WHERE `id` = 855736 LIMIT 1 [ RunTime:0.000698s ]
  9. UPDATE `article` SET `lasttime` = 1784016630 WHERE `id` = 855736 [ RunTime:0.014874s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000419s ]
  11. SELECT * FROM `article` WHERE `id` < 855736 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000631s ]
  12. SELECT * FROM `article` WHERE `id` > 855736 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000507s ]
  13. SELECT * FROM `article` WHERE `id` < 855736 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000658s ]
  14. SELECT * FROM `article` WHERE `id` < 855736 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.000950s ]
  15. SELECT * FROM `article` WHERE `id` < 855736 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001043s ]
0.105167s