笔友城堡 - 可定义的个人主页

前言

上次有跟踪过Android的Launcher启动和startActivity的源码分析(看文末链接,部分内容比较旧了),这次简单记录一下Android开机动画退出的源码分析。

因为Launcher启动完成且空闲后会通知系统退出开机动画。

借力AI分析源码,很准的,只要自己了解跳转流程。

正文

进入正题。

我们知道Launcher就是作为第一个可跟用户交互的App,第一次开机后先启动进程,然后启动Activity,我们知道,当我们可见Activity时是onResume()阶段。

根据以为内容,进入ActivityThread.java中。

ActivityThread.java

frameworks\base\core\java\android\app\ActivityThread.java
handleResumeActivity()
@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
        boolean isForward, String reason) {
    //略
    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        l.softInputMode |= forwardBit;
        if (r.mPreserveWindow) {
            a.mWindowAdded = true;
            r.mPreserveWindow = false;
            ViewRootImpl impl = decor.getViewRootImpl();
            if (impl != null) {
                impl.notifyChildRebuilt();
            }
        }
        if (a.mVisibleFromClient) {
            if (!a.mWindowAdded) {
                a.mWindowAdded = true;
                //添加decor
                wm.addView(decor, l);
            } else {
                a.onWindowAttributesChanged(l);
            }
        }
    } else if (!willBeVisible) {
        r.hideForNow = true;
    }
    //略
    r.nextIdle = mNewActivities;
    //这里赋值,不为null,下面Idler中要用
    mNewActivities = r;
    //【关注点】
    //1. 创建Idler对象
    //2. 添加到消息队列中
    Looper.myQueue().addIdleHandler(new Idler());
}

从上面可以知道

  1. decor添加到wm

  2. Looper.myQueue().addIdleHandler(new Idler())

第二个比较重要,添加一个Idler对象。

Idler
private class Idler implements MessageQueue.IdleHandler {
    @Override
    public final boolean queueIdle() {
        //上面赋值了,不为null
        ActivityClientRecord a = mNewActivities;
        //略
        if (a != null) {
            mNewActivities = null;
            final ActivityClient ac = ActivityClient.getInstance();
            ActivityClientRecord prev;
            do {
                if (a.activity != null && !a.activity.mFinished) {
                    //进入这里,调用ActivityClient中的activityIdle
                    ac.activityIdle(a.token, a.createdConfig, stopProfiling);
                    a.createdConfig = null;
                }
                prev = a;
                a = a.nextIdle;
                prev.nextIdle = null;
            } while (a != null);
        }
        if (stopProfiling) {
            mProfiler.stopProfiling();
        }
        return false;
    }
}

Idler实现于MessageQueue.IdleHandler,实现了queueIdle方法。

public static interface IdleHandler {
    boolean queueIdle();
}

把Idler对象添加到消息队列中,然后会执行MessageQueue.next() ,这里只看部分

@UnsupportedAppUsage
Message next() {
    //略
    for (;;) {
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler
            boolean keep = false;
            try {
                //这里调用了queueIdle()
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
    //略
    }
}

ActivityClient.java

frameworks\base\core\java\android\app\ActivityClient.java
activityIdle()
/** Reports the main thread is idle after the activity is resumed. */
public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
    try {
        getActivityClientController().activityIdle(token, config, stopProfiling);
    } catch (RemoteException e) {
        e.rethrowFromSystemServer();
    }
}

看getActivityClientController()返回值

getActivityClientController()
private static IActivityClientController getActivityClientController() {
    final IActivityClientController controller = INTERFACE_SINGLETON.mKnownInstance;
    return controller != null ? controller : INTERFACE_SINGLETON.get();
}

返回ActivityClientController的对象。

具体细节这里不展开

ActivityClientController.java

frameworks\base\services\core\java\com\android\server\wm\ActivityClientController.java
activityIdle()
@Override
public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
    final long origId = Binder.clearCallingIdentity();
    try {
        synchronized (mGlobalLock) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");
            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
            if (r == null) {
                return;
            }
            //这里
            mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */,
                    false /* processPausingActivities */, config);
            //略
        }
    } finally {
        //略
    }
}

mTaskSupervisor是ActivityTaskSupervisor对象

private final ActivityTaskSupervisor mTaskSupervisor;

ActivityTaskSupervisor.java

frameworks\base\services\core\java\com\android\server\wm\ActivityTaskSupervisor.java
activityIdleInternal()
void activityIdleInternal(ActivityRecord r, boolean fromTimeout,
        boolean processPausingActivities, Configuration config) {
    if (r != null) {
        mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
		//略
        // 标记该 Activity 已进入空闲状态
        r.idle = true;
		// 判断条件:系统正在启动 & 所有 Resumed Activity 均已空闲 || 超时兜底
        if ((mService.isBooting() && mRootWindowContainer.allResumedActivitiesIdle())
                || fromTimeout) {
            checkFinishBootingLocked();
        }
        r.mRelaunchReason = RELAUNCH_REASON_NONE;
    }
	//略
}
checkFinishBootingLocked()
/**
 * Called when all resumed tasks/root-tasks are idle.
 */
@GuardedBy("mService")
private void checkFinishBootingLocked() {
    final boolean booting = mService.isBooting();
    boolean enableScreen = false;
    mService.setBooting(false);
    if (!mService.isBooted()) {
        mService.setBooted(true);
        enableScreen = true;
    }
    //enableScreen为true,满足条件
    if (booting || enableScreen为true,满足条件) {
    	//重点
        mService.postFinishBooting(booting, enableScreen);
    }
}

重点关注postFinishBooting

final ActivityTaskManagerService mService;

ActivityTaskManagerService.java

frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java
void postFinishBooting(boolean finishBooting, boolean enableScreen) {
    mH.post(() -> {
        if (finishBooting) {
            //ActivityManagerInternal mAmInternal;
            mAmInternal.finishBooting();
        }
        if (enableScreen) {
           //final ActivityTaskManagerInternal mInternal;
            mInternal.enableScreenAfterBoot(isBooted());
        }
    });
}

下面分别介绍一下mAmInternal和mInternal

ActivityManagerInternal mAmInternal;
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);

ActivityManagerInternal是一个抽象类,其实现是ActivityManagerService.java中的LocalService

public final class LocalService extends ActivityManagerInternal
            implements ActivityManagerLocal {
        //略 
     	@Override
        public void finishBooting() {
        	//调用ActivityManagerService中的
            ActivityManagerService.this.finishBooting();
        }
        //略 
}

下面看

final ActivityTaskManagerInternal mInternal;
mInternal = new LocalService();

其LocalService为ActivityTaskManagerService.java中的

final class LocalService extends ActivityTaskManagerInternal {
	//略
    @Override
    public void enableScreenAfterBoot(boolean booted) {
        writeBootProgressEnableScreen(SystemClock.uptimeMillis());
        mWindowManager.enableScreenAfterBoot();
        synchronized (mGlobalLock) {
            updateEventDispatchingLocked(booted);
        }
    }
    //略
}

一个一个看,先看mAmInternal然后mInternal

ActivityManagerService.java

frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

根据上面

ActivityManagerService.this.finishBooting();

直接看finishBooting()

finishBooting()
/**
 * 系统启动流程的最终阶段:
 * 当开机动画结束、系统核心服务就绪后,AMS 在此完成启动收尾工作。
 *
 * 主要职责:
 * 1. 等待 boot animation 真正完成
 * 2. 通知 ART / Zygote 启动完成
 * 3. 注册关键广播监听
 * 4. 通知 StorageManager / SystemServiceManager
 * 5. 启动被挂起的进程
 * 6. 设置 boot_completed 系统属性
 * 7. 发送 BOOT_COMPLETED 相关广播
 */
final void finishBooting() {
    synchronized (this) {
        // 如果开机动画还没结束,先标记“需要补调用 finishBooting”
        // 等动画结束后再真正执行后续逻辑
        if (!mBootAnimationComplete) {
            mCallFinishBooting = true;
            t.traceEnd();
            return;
        }
        // 动画已完成,清除标记
        mCallFinishBooting = false;
    }

    // ==================== 通知运行时 ====================
    // 告诉 Zygote 和系统 Server 的 ART 虚拟机:系统启动完成
    // 用于触发 JIT 编译、堆整理、预加载优化等
    ZYGOTE_PROCESS.bootCompleted();
    VMRuntime.bootCompleted();

    // ==================== 注册包重启查询广播 ====================
    // 用于判断某个 package 是否可以被安全地 force-stop
    // 例如:ANR / 低内存清理前做安全检查
    IntentFilter pkgFilter = new IntentFilter();
    pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
    pkgFilter.addDataScheme("package");
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
            if (pkgs != null) {
                for (String pkg : pkgs) {
                    synchronized (ActivityManagerService.this) {
                        // 如果包可以被 force-stop,则返回 OK
                        if (forceStopPackageLocked(pkg, -1, false, false, false, false, false,
                                0, "query restart")) {
                            setResultCode(Activity.RESULT_OK);
                            return;
                        }
                    }
                }
            }
        }
    }, pkgFilter);

    // ==================== 存储 Checkpoint 提交 ====================
    // 用于 FBE(文件级加密)或 A/B 更新后的数据一致性保障
    try {
        Slog.i(TAG, "About to commit checkpoint");
        IStorageManager storageManager = InstallLocationUtils.getStorageManager();
        storageManager.commitChanges();
    } catch (Exception e) {
        // 如果提交失败,直接重启设备以保证数据安全
        PowerManager pm = (PowerManager)
                mInjector.getContext().getSystemService(Context.POWER_SERVICE);
        pm.reboot("Checkpoint commit failed");
    }

    // ==================== 通知所有 SystemService ====================
    // 触发 PHASE_BOOT_COMPLETED
    // 各服务(WMS / PMS / PKMS 等)在此阶段完成最后初始化
    Slog.w(TAG, "finishBooting PHASE_BOOT_COMPLETED : ");
    mSystemServiceManager.startBootPhase(t, SystemService.PHASE_BOOT_COMPLETED);

    synchronized (this) {
        // ==================== 启动被挂起的进程 ====================
        // 某些进程在启动早期被放入 mProcessesOnHold
        // 现在统一批量启动
        final int NP = mProcessesOnHold.size();
        if (NP > 0) {
            ArrayList<ProcessRecord> procs = new ArrayList<>(mProcessesOnHold);
            for (int ip = 0; ip < NP; ip++) {
                if (DEBUG_PROCESSES) {
                    Slog.v(TAG_PROCESSES, "Starting process on hold: " + procs.get(ip));
                }
                mProcessList.startProcessLocked(
                        procs.get(ip),
                        new HostingRecord(HostingRecord.HOSTING_TYPE_ON_HOLD),
                        ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
            }
        }

        // 工厂测试模式(低级)下,启动流程到此为止
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            return;
        }

        // ==================== 功耗监控 ====================
        // 启动后开始监控异常 WakeLock 使用
        Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
        mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);

        // ==================== Userspace Reboot 处理 ====================
        // 如果是用户空间重启,记录成功事件
        if (InitProperties.userspace_reboot_in_progress().orElse(false)) {
            UserspaceRebootLogger.noteUserspaceRebootSuccess();
        }

        // ==================== 设置 boot_completed 属性 ====================
        // sys.boot_completed = 1 是系统启动完成的“黄金标志”
        // init / native 进程都会监听这个属性
        SystemProperties.set("sys.boot_completed", "1");

        // dev.bootcomplete = 1 用于更早阶段的服务判断
        if (!"trigger_restart_min_framework".equals(VoldProperties.decrypt().orElse(""))
                || "".equals(VoldProperties.encrypt_progress().orElse(""))) {
            SystemProperties.set("dev.bootcomplete", "1");
        }

        // ==================== 发送 BOOT_COMPLETED ====================
        // 通知所有用户、所有应用:系统启动完成
        // 这是第三方应用收到的最重要的启动广播
        Slog.v(TAG, "--------sendBootCompleted----1------ ");
        mUserController.sendBootCompleted(
                new IIntentReceiver.Stub() {
                    @Override
                    public void performReceive(Intent intent, int resultCode,
                            String data, Bundle extras, boolean ordered,
                            boolean sticky, int sendingUser) {
                        synchronized (mProcLock) {
                            // 广播发送后,立即收集一次所有进程的 PSS 信息
                            mAppProfiler.requestPssAllProcsLPr(
                                    SystemClock.uptimeMillis(), true, false);
                        }
                    }
                });

        // 记录 userspace reboot 相关指标
        maybeLogUserspaceRebootEvent();
        // 启动用户 profile(多用户场景)
        mUserController.scheduleStartProfiles();
    }

    // ==================== 控制台 / MTE 警告 ====================
    // 如果 UART console 开启,发出安全提醒
    showConsoleNotificationIfActive();
    showMteOverrideNotificationIfActive();
    t.traceEnd();
}
  1. 通知zygote、VMRuntime、mSystemServiceManager等开机完成

  2. 设置sys.boot_completed为1,表示开机完成

  3. 发送ACTION_BOOT_COMPLETED

这里重点就是设置开机完成以及设置开机完成属性为1,然后通知开机完成广播。

继续回调上面mInternal的调用。

ActivityTaskManagerService.java

mInternal就是ActivityTaskManagerService.java中的LocalService。

LocalService.enableScreenAfterBoot()
/**
 * ActivityTaskManagerService 对外暴露的本地服务实现(LocalService),
 * 供 SystemServer 或其他同一进程内的组件调用。
 *
 * 此类继承自 ActivityTaskManagerInternal,
 * 是 ATMS 与 WMS / AMS 等系统服务交互的重要桥梁。
 */
final class LocalService extends ActivityTaskManagerInternal {
    // ... 省略其他实现 ...

    /**
     * 系统启动完成后,通知 ATMS 启用屏幕。
     *
     * 该方法通常由 SystemServer 在启动流程末尾调用,
     * 是“系统已启动完成”的关键信号之一。
     *
     * @param booted 当前系统是否已处于 boot completed 状态
     */
    @Override
    public void enableScreenAfterBoot(boolean booted) {
        // ==================== Boot Timing ====================
        // 记录“点亮屏幕”这一关键启动节点的时间戳
        // 用于:
        // - dumpsys bootinfo
        // - 开机性能分析
        // - 对比 system_server 各阶段耗时
        writeBootProgressEnableScreen(SystemClock.uptimeMillis());

        // ==================== 核心调用 ====================
        // 委托 WindowManagerService 执行真正的亮屏逻辑:
        // - 停止开机动画
        // - 通知 SurfaceFlinger
        // - 启用输入分发
        // - 触发 performEnableScreen()
        mWindowManager.enableScreenAfterBoot();

        // ==================== 事件分发控制 ====================
        // 根据系统启动状态,更新窗口输入事件的派发策略
        // 例如:
        // - 启动未完成时屏蔽用户输入
        // - 启动完成后恢复正常触摸 / 按键响应
        synchronized (mGlobalLock) {
            updateEventDispatchingLocked(booted);
        }
    }

    // ... 省略其他实现 ...
}

这里主要看

mWindowManager.enableScreenAfterBoot();

WindowManagerService.java

enableScreenAfterBoot()
/**
 * 系统启动完成后,由 WMS 调用,用于最终点亮屏幕并完成启动收尾工作。
 * 该方法通常由 performEnableScreen() 触发,
 * 是 WindowManagerPolicy(PhoneWindowManager)介入启动流程的关键入口。
 */
public void enableScreenAfterBoot() {
    synchronized (mGlobalLock) {
        // ==================== 调试日志 ====================
        // 打印当前启动状态,并附带调用栈,便于排查开机卡屏 / 黑屏问题
        ProtoLog.i(WM_DEBUG_BOOT, "enableScreenAfterBoot: mDisplayEnabled=%b "
                        + "mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. "
                        + "%s",
                mDisplayEnabled, mForceDisplayEnabled, mShowingBootMessages, mSystemBooted,
                new RuntimeException("here").fillInStackTrace());

        // ========== Unisoc 厂商定制逻辑(bug2400846)==========
        // 强制提前退出开机动画,避免动画阻塞亮屏
        SystemProperties.set("service.bootanim.exit", "1");
        mBootAnimationStopped = true;

        // 强制认为显示已可用,跳过部分等待逻辑
        mForceDisplayEnabled = true;
        // ===================================================

        // 如果系统已经标记为启动完成,直接返回,避免重复执行
        if (mSystemBooted) {
            return;
        }

        // 标记系统正式启动完成
        mSystemBooted = true;

        // 隐藏开机阶段显示的文字(如 "Android"、进度条等)
        hideBootMessagesLocked();

        // ===== 兜底保护机制 =====
        // 如果屏幕在 30 秒内仍未正常点亮,
        // 通过 Handler 强制触发亮屏流程,防止系统“假死”
        mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000);
    }

    // ==================== 通知 Policy ====================
    // 让 PhoneWindowManager 知道系统已经启动完成
    // 典型行为包括:
    // - 允许锁屏显示
    // - 允许唤醒设备
    // - 允许接收用户输入
    mPolicy.systemBooted();

    Slog.w(TAG, "enableScreenAfterBoot");

    // ==================== 真正点亮屏幕 ====================
    // 执行最终的屏幕启用流程:
    // - 停止开机动画
    // - 通知 SurfaceFlinger
    // - 启用输入分发
    // - 通知 AMS bootAnimationComplete
    performEnableScreen();
}

这里再关注一下performEnableScreen()

performEnableScreen()
/**
 * 点亮屏幕 & 结束开机动画。
 * 这是 WindowManagerService 启动流程中最重要的收尾函数之一。
 * 必须确保所有系统窗口绘制完成、开机动画结束,才能正式启用屏幕和输入。
 */
private void performEnableScreen() {
    synchronized (mGlobalLock) {
        // 屏幕已经点亮过,直接返回(防止重复执行)
        if (mDisplayEnabled) {
            return;
        }
        // 系统尚未完全启动,且没有显示过开机提示信息,还不能亮屏
        if (!mSystemBooted && !mShowingBootMessages) {
            return;
        }
        // =====================================================
        // 关键前提:等待所有系统窗口绘制完成
        // 防止出现“桌面先出、状态栏后出”或黑屏问题
        // =====================================================
        if (!mForceDisplayEnabled) {
            // 第一次进入,记录等待开始时间
            if (mBootWaitForWindowsStartTime < 0) {
                mBootWaitForWindowsStartTime = SystemClock.elapsedRealtime();
            }

            // 遍历所有 RootWindowContainer 的子节点
            // 若存在需要等待的系统装饰窗口(如 SystemUI、导航栏、状态栏),
            // 则继续等待,暂不亮屏
            for (int i = mRoot.getChildCount() - 1; i >= 0; i--) {
                if (mRoot.getChildAt(i).shouldWaitForSystemDecorWindowsOnBoot()) {
                    return;
                }
            }

            // 统计等待窗口绘制的时间
            long waitTime = SystemClock.elapsedRealtime() - mBootWaitForWindowsStartTime;
            mBootWaitForWindowsStartTime = -1;
            if (waitTime > 10) {
                ProtoLog.i(WM_DEBUG_BOOT,
                        "performEnableScreen: Waited %dms for all windows to be drawn",
                        waitTime);
            }
        }

        // =====================================================
        // 停止开机动画(bootanimation)
        // 早期版本是直接 kill 进程,现在通过设置 property 通知其优雅退出
        // =====================================================
        if (!mBootAnimationStopped) {
            Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);

            // 通知 bootanimation 进程退出
            SystemProperties.set("service.bootanim.exit", "1");
            mBootAnimationStopped = true;
        }

        // ========== Unisoc 私有逻辑 ==========
        // 回收 LK(Little Kernel)阶段动画占用的资源
        Slog.w(TAG, "setprop sys.native.bootanimation to 1");
        SystemProperties.set("sys.native.bootanimation", "1");

        // 确保开机动画真的已经结束,否则继续等待
        if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
            ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: Waiting for anim complete");
            return;
        }

        // =====================================================
        // 通知 SurfaceFlinger:系统启动完成(BOOT_FINISHED)
        // SurfaceFlinger 收到后会切到正常合成模式
        // =====================================================
        try {
            IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
            if (surfaceFlinger != null) {
                ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
                Parcel data = Parcel.obtain();
                data.writeInterfaceToken("android.ui.ISurfaceComposer");
                // FIRST_CALL_TRANSACTION == BOOT_FINISHED
                surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0);
                data.recycle();
            }
        } catch (RemoteException ex) {
            ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");
        }

        // 记录开机动画结束时间点(用于性能分析)
        EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());
        Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);

        // ==================== 正式点亮屏幕 ====================
        mDisplayEnabled = true;
        ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!");

        // 启用输入事件分发(触摸、按键等)
        mInputManagerCallback.setEventDispatchingLw(mEventDispatchingEnabled);
    }

    // =========================================================
    // 通知 ActivityManagerService:开机动画已完成
    // AMS 会进一步触发 ACTION_BOOT_COMPLETED
    // =========================================================
    try {
        Slog.w(TAG, " performEnableScreen bootAnimationComplete");
        mActivityManager.bootAnimationComplete();
    } catch (RemoteException e) {
        // AMS 可能已死,忽略异常
    }

    // Policy(PhoneWindowManager)处理亮屏后的逻辑
    // 如锁屏显示、唤醒行为等
    mPolicy.enableScreenAfterBoot();

    // 确保最后一次请求的方向(横竖屏)已生效
    updateRotationUnchecked(false, false);
}

至此,开机动画退出,显示了Launcher界面。

参考文字

  1. AI

  2. Android源码

  3. Android源码之Launcher启动流程

  4. startActivity源码分析2

  5. startActivity源码分析1

  6. startActivity之进程启动

相关文章

笔友城堡 - 可定义的个人主页

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

none
暂无评论...