阅读 106

Android 源码解读-startActivity(含启动新应用)

开局一张图

源码版本:Android 11(SDK 30)

涉及到的类

  • Instrumentation:负责 ApplicationActivity 的建立和生命周期控制。

  • ActivityTaskManager:此类提供有关Activity及其容器(如任务、堆栈和显示)的信息并与之交互。

  • ActivityTaskManagerService:用于管理Activity及其容器(任务、显示等)的系统服务。之前这个活是AMS的,现在从AMS中剥离出来了。

  • ActivityStartController:用于委托Activity启动的控制器。

  • ActivityStarter:专门负责一个 Activity 的启动操做。它的主要做用包括解析 Intent、建立 ActivityRecord、若是有可能还要建立 TaskRecordflex

  • ActivityStack:Activity在ATMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程。

  • RootWindowContainer:设备的Root WindowContainer。

  • TaskRecord:ATMS抽象出来的一个"任务"的概念,是记录ActivityRecord的栈,一个"Task"包含若干个ActivityRecord。ATMS用TaskRecord确保Activity启动和退出的顺序。

  • ActivityStackSupervisor:负责所有Activity栈的管理。内部管理了mHomeStack、mFocusedStack和mLastFocusedStack三个Activity栈。其中,mHomeStack管理的是Launcher相关的Activity栈;mFocusedStack管理的是当前显示在前台Activity的Activity栈;mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈。

  • ActivitySupervisor:管理 activity 任务栈。

  • ActivityThread:ActivityThread 运行在UI线程(主线程),App的真正入口。

  • ApplicationThread:用来实现ATMS和ActivityThread之间的交互。

  • ApplicationThreadProxy:ApplicationThread 在服务端的代理。ATMS就是通过该代理与ActivityThread进行通信的。

  • ClientLifecycleManager:能够组合多个客户端生命周期 transaction 请求和/或回调,并将它们作为单个 transaction 执行。

  • TransactionExecutor:已正确的顺序管理 transaction 执行的类。

1、Activity.java

1.1 startActivity()

@Override public void startActivity(Intent intent) {     //接着往里看     this.startActivity(intent, null); } @Override public void startActivity(Intent intent, @Nullable Bundle options) {     ...     if (options != null) {         startActivityForResult(intent, -1, options);     } else {         startActivityForResult(intent, -1);     } } 复制代码

最终调用了 startActivityForResult 方法,传入的 -1 表示不需要获取 startActivity 的结果。

1.2 startActivityForResult()

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,     @Nullable Bundle options) {     //mParent表示当前Activitiy的父类,     if (mParent == null) {         options = transferSpringboardActivityOptions(options);         //ActivityThread mMainThread;         Instrumentation.ActivityResult ar =             mInstrumentation.execStartActivity(             this, mMainThread.getApplicationThread(), mToken, this,                 intent, requestCode, options);         ...     } else {         ...     } } 复制代码

startActivityForResult 调用 Instrumentation.execStartActivity 方法。剩下的交给 Instrumentation 类去处理。

mMainThreadActivityThread 类型,ActivityThread 可以理解为一个进程,这就是 Activity 所在的进程。

通过 mMainThread 获取一个 ApplicationThread 的引用,这个引用就是用来实现进程间通信的,具体来说就是 AMS 所在系统进程通知应用程序进程进行的一系列操作。

上面有Instrumentation、ActivityThread、ApplicationThread 等类的介绍。

2、Instrumentation.java

frameworks/base/core/java/android/app/Instrumentation.java

/**  * Base class for implementing application instrumentation code.  */ public class Instrumentation {     ... } 复制代码

2.1 execStartActivity()

 public ActivityResult execStartActivity(             Context who, IBinder contextThread, IBinder token, Activity target,             Intent intent, int requestCode, Bundle options) {         ...         try {             intent.migrateExtraStreamToClipData();             intent.prepareToLeaveProcess(who);             int result = ActivityTaskManager.getService()                 .startActivity(whoThread, who.getBasePackageName(), intent,                         intent.resolveTypeIfNeeded(who.getContentResolver()),                         token, target != null ? target.mEmbeddedID : null,                         requestCode, 0, null, options);             //检查启动Activity的结果             checkStartActivityResult(result, intent);         } catch (RemoteException e) {             throw new RuntimeException("Failure from system", e);         }         return null;     } 复制代码

Instrumentation 中,调用了 ActivityTaskManager.getService().startActivity() 。咱们近距离观望一下。

3、ActivityTaskManage.java

frameworks/base/core/java/android/app/ActivityTaskManager.java

@TestApi @SystemService(Context.ACTIVITY_TASK_SERVICE) public class ActivityTaskManager {     ... } 复制代码

3.1 getService()

    /** @hide */     public static IActivityTaskManager getService() {         return IActivityTaskManagerSingleton.get();     } 复制代码

3.2 IActivityTaskManagerSingleton

    @UnsupportedAppUsage(trackingBug = 129726065)     private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =             new Singleton<IActivityTaskManager>() {                 @Override                 protected IActivityTaskManager create() {                     //代理对象(动态代理)                     final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);                     return IActivityTaskManager.Stub.asInterface(b);                 }             };              复制代码

这里实际上返回的是一个 ActivityTaskManagerService 这出现了跨进程 (从应用进程(app) > system_service进程) ,然后调用其 startActivity 方法。

实际上这里就是通过 AIDL 来调用 ATMSstartActivity 方法,返回 IActivityTaskManager.startActivity 的结果:Activity 已正常成功启动。

至此,startActivity 的工作重心成功地从 应用进程(app) 转移到了系统进程(system_service)ATMS 中。

4、ActivityTaskManagerService.java

frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

/**  * 用于管理 activities and their containers (task, stacks, displays,... )的 system_service(系统服务)  */ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {     ... } 复制代码

4.1 startActivity()

@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()); } 复制代码

4.2 startActivityAsUser()

@Override public int startActivityAsUser(IApplicationThread caller, String callingPackage,         String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,         String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,         Bundle bOptions, int userId) {     return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,             resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,             true /*validateIncomingUser*/); } 复制代码

4.3 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) {     assertPackageMatchesCallingUid(callingPackage);     enforceNotIsolatedCaller("startActivityAsUser");     userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,             Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");     // 在此处切换到用户app堆栈。     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();     } 复制代码

4.4 getActivityStartController()

    ActivityStartController getActivityStartController() {         return mActivityStartController;     } 复制代码

5、ActivityStartController.java

/**  * Controller for delegating activity launches.  */ public class ActivityStartController {     ... } 复制代码

5.1 obtainStarter();

    /**      * @return A starter to configure and execute starting an activity. It is valid until after      *         {@link ActivityStarter#execute} is invoked. At that point, the starter should be      *         considered invalid and no longer modified or used.      */     ActivityStarter obtainStarter(Intent intent, String reason) {         return mFactory.obtain().setIntent(intent).setReason(reason);     } 复制代码

6、ActivityStarter.java

frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

/**  * Controller for interpreting how and then launching an activity.  *  * This class collects all the logic for determining how an intent and flags should be turned into  * an activity and associated task and stack.  */ class ActivityStarter {     ... } 复制代码

6.1 execute()

    /**      * 根据前面提供的请求参数解析必要的信息,执行开始活动的请求。      * @return The starter result.      */     int execute() {         ...                 res = executeRequest(mRequest);         ...     } 复制代码

6.2 executeRequest()

    /**      * Activity启动之前需要做那些准备?      * 通常的Activity启动流程将通过 startActivityUnchecked 到 startActivityInner。      */     private int executeRequest(Request request) {         ...         //Activity的记录         ActivityRecord sourceRecord = null;         ActivityRecord resultRecord = null;         ...         //Activity stack(栈)管理         mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,                 request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,                 restrictedBgActivity, intentGrants);         ...         return mLastStartActivityResult;     } 复制代码

从上面代码可以看出,经过多个方法的调用,最终通过 obtainStarter 方法获取了 ActivityStarter 类型的对象,然后调用其 execute() 方法。

execute() 方法中,会再次调用其内部的 executeRequest() 方法。

咱们接着看看 startActivityUnchecked() ;

6.3 startActivityUnchecked()

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,                 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,                 int startFlags, boolean doResume, ActivityOptions options, Task inTask,                 boolean restrictedBgActivity, NeededUriGrants intentGrants) {         ....         try {             ...             result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,                     startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);         } finally {             ...         }         postStartActivityProcessing(r, result, startedActivityRootTask);         return result;     } 复制代码

6.4 startActivityInner()

    int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,             int startFlags, boolean doResume, ActivityOptions options, Task inTask,             boolean restrictedBgActivity, NeededUriGrants intentGrants) {         setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,                 voiceInteractor, restrictedBgActivity);         //计算启动模式         computeLaunchingTaskFlags();         computeSourceRootTask();         //设置启动模式         mIntent.setFlags(mLaunchFlags);         ...         // 关键点来了         mRootWindowContainer.resumeFocusedTasksTopActivities(                         mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);         ...         return START_SUCCESS;     } 复制代码

这个是 mRootWindowContainerRootWindowContainer

7、RootWindowContainer.java

frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

/** Root {@link WindowContainer} for the device. */ class RootWindowContainer extends WindowContainer<DisplayContent>         implements DisplayManager.DisplayListener {         ...         } 复制代码

7.1 resumeFocusedTasksTopActivities()

    boolean resumeFocusedTasksTopActivities(             Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,             boolean deferPause) {         ...         boolean result = false;         if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()                 || getTopDisplayFocusedRootTask() == targetRootTask)) {             result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,                     deferPause);         }         ...         return result;     } 复制代码

当然这里看的是 targetRootTask 是 Task 对象的实例。咱们就去追踪这个方法。

8、Task.java

frameworks/base/services/core/java/com/android/server/wm/Task.java

class Task extends WindowContainer<WindowContainer> {       ... } 复制代码

8.1 resumeTopActivityUncheckedLocked()

    @GuardedBy("mService")     boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,             boolean deferPause) {         ...         someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);         ...         return someActivityResumed;     } 复制代码

8.2 resumeTopActivityInnerLocked()

    @GuardedBy("mService")     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,             boolean deferPause) {         ...             try {                 ....             } catch (Exception e) {                 ....                 //重点                 mTaskSupervisor.startSpecificActivity(next, true, false);                 return true;             }         ....         return true;     } 复制代码

mTaskSupervisor:是 ActivityTaskSupervisor 对象的实例。下面咱们看看其 startSpecificActivity() 方法。

9、ActivityTaskSupervisor.class

frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java

public class ActivityTaskSupervisor implements RecentTasks.Callbacks {       ... } 复制代码

9.1 startSpecificActivity()

    void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {         // 此 Activity 的 应用程序(进程) 是否已在运行?         final WindowProcessController wpc =                 mService.getProcessController(r.processName, r.info.applicationInfo.uid);         boolean knownToBeDead = false;         if (wpc != null && wpc.hasThread()) {             try {                 //进程已启动                 //注释1:开始启动activity                 realStartActivityLocked(r, wpc, andResume, checkConfig);                 return;             } catch (RemoteException e) {                              }         }         r.notifyUnknownVisibilityLaunchedForKeyguardTransition();         final boolean isTop = andResume && r.isTopRunningActivity();         //注释2:进程未启动         mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");     } 复制代码

注释1:启动activity。

注释2:进程未启动。

9.2 进程已启动

9.2.1 realStartActivityLocked()

    boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,             boolean andResume, boolean checkConfig) throws RemoteException {         ...                 //创建 Activity 启动的 transaction                 final ClientTransaction clientTransaction = ClientTransaction.obtain(                         proc.getThread(), r.appToken);                 final boolean isTransitionForward = r.isTransitionForward();                 clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),                         System.identityHashCode(r), r.info,                         mergedConfiguration.getGlobalConfiguration(),                         mergedConfiguration.getOverrideConfiguration(), r.compat,                         r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),                         r.getSavedState(), r.getPersistentSavedState(), results, newIntents,                         r.takeOptions(), isTransitionForward,                         proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,                         r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken,                         r.getLaunchedFromBubble()));                 // Set desired final state.                 final ActivityLifecycleItem lifecycleItem;                 if (andResume) {                     lifecycleItem = ResumeActivityItem.obtain(isTransitionForward);                 } else {                     lifecycleItem = PauseActivityItem.obtain();                 }                 clientTransaction.setLifecycleStateRequest(lifecycleItem);                 // Schedule transaction.                 mService.getLifecycleManager().scheduleTransaction(clientTransaction);                   ...         return true;     } 复制代码

这的 mService 就是 ActivityTaskManagerService(ATMS) 的实例。mService.getLifecycleManager() 返回的是一个 ClientLifecycleManager 对象。想看 scheduleTransaction() 是干嘛的 只能找它了。

9.2.2 ClientLifecycleManager.scheduleTransaction()

frameworks/base/services/core/java/com/android/server/wm/ClientLifecycleManager.java

    //这里咱们传入的是一个启动 Activity 的 transaction     void scheduleTransaction(ClientTransaction transaction) throws RemoteException {         final IApplicationThread client = transaction.getClient();         //注释1         transaction.schedule();         if (!(client instanceof Binder)) {             // 如果 client 不是Binder的实例,则它是一个远程调用,此时可以安全地回收该对象。             // 在ActivityThread中的客户端上执行transaction后,将回收用于本地调用的所有对象。             transaction.recycle();         }     } 复制代码

从方法中看出 transaction 是个 ClientTransaction 。那咱直接去找他。

9.2.3 ClientTransaction.schedule()

    /** Target client. */     private IApplicationThread mClient;          public void schedule() throws RemoteException {         mClient.scheduleTransaction(this);     } 复制代码

看到 IApplicationThread ,咱们直接去找 ApplicationThread

9.2.4 ApplicationThread.scheduleTransaction()

frameworks/base/core/java/android/app/ActivityThread.java

ApplicationThread 属于 ActivityThread 的内部类。

public final class ActivityThread extends ClientTransactionHandler         implements ActivityThreadInternal {     ...     private class ApplicationThread extends IApplicationThread.Stub {         ...         @Override         public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {             ActivityThread.this.scheduleTransaction(transaction);         }         ...     }     ... } 复制代码

ActivityThread 类中是没有 scheduleTransaction 方法的,通常遇到这种状况,直接找其父类 ClientTransactionHandler

9.2.5 ClientTransactionHandler.scheduleTransaction()

frameworks/base/core/java/android/app/ClientTransactionHandler.java

public abstract class ClientTransactionHandler {     /** Prepare and schedule transaction for execution. */     void scheduleTransaction(ClientTransaction transaction) {         transaction.preExecute(this);         sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);     } } 复制代码

从这里看到 他调用 sendMessage() 方法发送了个 ActivityThread.H.EXECUTE_TRANSACTION 消息,咱们回到其子类 ActivityThread 中查看。

9.2.6 ActivityThread.H.handleMessage()

这里的 HActivityThread 的 内部类。

    // An executor that performs multi-step transactions.     private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);     class H extends Handler {         public void handleMessage(Message msg) {             switch (msg.what) {                         ...                         case EXECUTE_TRANSACTION:                     final ClientTransaction transaction = (ClientTransaction) msg.obj;                     mTransactionExecutor.execute(transaction);                     if (isSystem()) {                         transaction.recycle();                     }                     break;                     ...             }         }     } 复制代码

这里的 mTransactionExecutortransactions 的执行者。

9.2.7 TransactionExecutor.execute()

frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java

    public void execute(ClientTransaction transaction) {         ...         executeCallbacks(transaction);         ...     } 复制代码

9.2.8 TransactionExecutor.executeCallbacks()

    /** Cycle through all states requested by callbacks and execute them at proper times. */     @VisibleForTesting     public void executeCallbacks(ClientTransaction transaction) {         final List<ClientTransactionItem> callbacks = transaction.getCallbacks();         ...         final IBinder token = transaction.getActivityToken();         ActivityClientRecord r = mTransactionHandler.getActivityClient(token);         ...         final int size = callbacks.size();         for (int i = 0; i < size; ++i) {             ...             if (postExecutionState != UNDEFINED && r != null) {                 // 重点                 final boolean shouldExcludeLastTransition =                         i == lastCallbackRequestingState && finalState == postExecutionState;                 cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);             }         }     } 复制代码

这个方法的重点是 cycleToPath() ,咱们继续。

9.2.9 TransactionExecutor.cycleToPath()

    private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState,             ClientTransaction transaction) {         final int start = r.getLifecycleState();         //IntArray:实现不断增长的int基元数组。         //获取此次要执行生命周期的路径path         final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);         performLifecycleSequence(r, path, transaction);     } 复制代码

9.2.10 TransactionExecutor.performLifecycleSequence()

    /** Transition the client through previously initialized state sequence. */     private void performLifecycleSequence(ActivityClientRecord r, IntArray path,             ClientTransaction transaction) {         final int size = path.size();         for (int i = 0, state; i < size; i++) {             state = path.get(i);                          switch (state) {                 case ON_CREATE:                     mTransactionHandler.handleLaunchActivity(r, mPendingActions,                             null /* customIntent */);                     break;                 case ON_START:                     mTransactionHandler.handleStartActivity(r, mPendingActions,                             null /* activityOptions */);                     break;                 case ON_RESUME:                     mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */,                             r.isForward, "LIFECYCLER_RESUME_ACTIVITY");                     break;                 case ON_PAUSE:                     mTransactionHandler.handlePauseActivity(r, false /* finished */,                             false /* userLeaving */, 0 /* configChanges */, mPendingActions,                             "LIFECYCLER_PAUSE_ACTIVITY");                     break;                 case ON_STOP:                     mTransactionHandler.handleStopActivity(r, 0 /* configChanges */,                             mPendingActions, false /* finalStateRequest */,                             "LIFECYCLER_STOP_ACTIVITY");                     break;                 case ON_DESTROY:                     mTransactionHandler.handleDestroyActivity(r, false /* finishing */,                             0 /* configChanges */, false /* getNonConfigInstance */,                             "performLifecycleSequence. cycling to:" + path.get(size - 1));                     break;                 case ON_RESTART:                     mTransactionHandler.performRestartActivity(r, false /* start */);                     break;                 default:                     throw new IllegalArgumentException("Unexpected lifecycle state: " + state);             }         }     } 复制代码

到这里咱们终于看到了熟悉的内容,Activity的生命周期,好激动哈哈。

这里咱们以 ON_CREATE 为例。从上面代码看出 ON_CREATE 等其实就是个int值(常量),这里咱就不多描述了。mTransactionHandlerClientTransactionHandler 的实例,直接看handleLaunchActivity() 方法

9.2.11 ClientTransactionHandler.handleLaunchActivity()

frameworks/base/core/java/android/app/ClientTransactionHandler.java

public abstract class ClientTransactionHandler {     ...     /** Perform activity launch. */     public abstract Activity handleLaunchActivity(@NonNull ActivityClientRecord r,             PendingTransactionActions pendingActions, Intent customIntent);     ...     } 复制代码

从上面看出 handleLaunchActivity() 是抽象方法,ActivityThread 做为其子类,只能找其子类 ActivityThread 看看具体实现。

9.2.12 ActivityThread.handleLaunchActivity()

    /**      * Extended implementation of activity launch. Used when server requests a launch or relaunch.      */     @Override     public Activity handleLaunchActivity(ActivityClientRecord r,             PendingTransactionActions pendingActions, Intent customIntent) {         // 在创建 activity 之前初始化         if (ThreadedRenderer.sRendererEnabled                 && (r.activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {             HardwareRenderer.preload();         }         //初始化 Activity 的 WindowManager,每一个 Activity 都会对应一个"窗口"。         WindowManagerGlobal.initialize();         // 提示 GraphicsEnvironment Activity 正在进程中启动。         GraphicsEnvironment.hintActivityLaunch();         //这里重点:Activity 启动的核心实现。         final Activity a = performLaunchActivity(r, customIntent);         ...         return a;     } 复制代码

performLaunchActivity()Activity 启动的核心实现。具体咱们往下看

9.2.13 ActivityThread.performLaunchActivity()

    /**  Core implementation of activity launch. */     private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {         ...         ContextImpl appContext = createBaseContextForActivity(r);         Activity activity = null;         try {             java.lang.ClassLoader cl = appContext.getClassLoader();             //注释1: 新实例化的 Activity 对象。             activity = mInstrumentation.newActivity(                     cl, component.getClassName(), r.intent);             ...         } catch (Exception e) {             ...         }                 //重点:调用activity.attach()。                 //建立 Activity 与 Context 之间的联系。                 //创建 PhoneWindow 对象,并与 Activity 进行关联操作。                 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.configCallback,                         r.assistToken, r.shareableActivityToken);                                          //persistableMode属性设置为: ActivityInfo.PERSIST_ACROSS_REBOOTS(persistAcrossReboots);                 //注释2:执行 Activity 的 onCreate() 方法。                 if (r.isPersistable()) {                     mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);                 } else {                     mInstrumentation.callActivityOnCreate(activity, r.state);                 }         return activity;     } 复制代码

这里首先看看 mInstrumentation 其实就是 Instrumentation 。 在本文 startActivityForResult 部分也有用到。Instrumentation 负责 ApplicationActivity 的建立和生命周期控制。

这里用到了他的两个方法咱们一起看看。

9.2.14 Instrumentation.newActivity()

    /**      * @param cl 用于实例化对象的类加载器(ClassLoader)。      * @param className 实现 Activity 对象的类的名称。      * @param intent 指定要实例化的活动类的 Intent 对象。      *       * @return 新实例化的 Activity 对象。      */     public Activity newActivity(ClassLoader cl, String className,             Intent intent)             throws InstantiationException, IllegalAccessException,             ClassNotFoundException {         String pkg = intent != null && intent.getComponent() != null                 ? intent.getComponent().getPackageName() : null;         return getFactory(pkg).instantiateActivity(cl, className, intent);     } 复制代码

pkg 就是 intent 所在的包名。

getFactory(pkg) 通过获取到的包名 得到 AppComponentFactory 。然后调用其 instantiateActivity() 方法获取 Activity

9.2.14.1 Instrumentation.getFactory()

    private AppComponentFactory getFactory(String pkg) {         if (pkg == null) {             ...             return AppComponentFactory.DEFAULT;         }         if (mThread == null) {             ....             return AppComponentFactory.DEFAULT;         }         LoadedApk apk = mThread.peekPackageInfo(pkg, true);         // This is in the case of starting up "android".         if (apk == null) apk = mThread.getSystemContext().mPackageInfo;         return apk.getAppFactory();     } 复制代码

9.2.14.2 AppComponentFactory.instantiateActivity()

frameworks/base/core/java/android/app/AppComponentFactory.java

/**   * 用于控制 manifest 元素实例化的接口。   *   * @see #instantiateApplication   * @see #instantiateActivity   * @see #instantiateClassLoader   * @see #instantiateService   * @see #instantiateReceiver   * @see #instantiateProvider   */ public class AppComponentFactory {       ... } 复制代码

instantiateActivity()

    /**      * 此方法仅用于提供用于实例化的钩子。      * 它不提供对 Activity 对象的早期访问。      * 返回的对象还不会被初始化为 Context 并且不应该用于与其他 android API 交互。      */     public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,             @Nullable Intent intent)             throws InstantiationException, IllegalAccessException, ClassNotFoundException {         return (Activity) cl.loadClass(className).newInstance();     } 复制代码

这里通过反射拿到 Activity 的实例。

9.2.15 Instrumentation.callActivityOnCreate()

    /**      * 执行 Activity#onCreate方法的调用。      *      * @param activity 正在创建的 activity 。      * @param icicle 将以前冻结的状态(或null)传递给 onCreate() 。      */     public void callActivityOnCreate(Activity activity, Bundle icicle) {         prePerformCreate(activity);         //重点         activity.performCreate(icicle);         postPerformCreate(activity);     } 复制代码

从这里可以看到即将进入 Activity 的内部

9.2.15.1 Activity.performCreate()

    final void performCreate(Bundle icicle) {         performCreate(icicle, null);     }     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)     final void performCreate(Bundle icicle, PersistableBundle persistentState) {         ...         //重点         if (persistentState != null) {             onCreate(icicle, persistentState);         } else {             onCreate(icicle);         }         ...     } 复制代码

看到这里,startSpecificActivity() 方法中的 进程已启动的状态算是完结。startActivity 启动成功。结合 9.2.13 ActivityThread.performLaunchActivity() 查看 Activity 中的 attach() 方法调用早于 onCreate() 方法

下面让我们回到 9.1 startSpecificActivity() 中查看进程未启动的流程情况。

9.3 进程未启动

既然进程未启动那肯定先启动进程了。咱们接着看。

    final ActivityTaskManagerService mService;     void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {         ....         mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");     } 复制代码

从这里看到 mService 其实就是 ATMS ,走着。

9.3.1 ATMS.startProcessAsync()

    void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,             String hostingType) {         try {             ...             // 发布消息以启动进程,以避免在持有 ATMS 锁的情况下调用 AMS 可能出现死锁。             final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,                     mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,                     isTop, hostingType, activity.intent.getComponent());             mH.sendMessage(m);         } finally {             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);         }     } 复制代码

9.3.2 ActivityManagerInternal.startProcess()

frameworks/base/core/java/android/app/ActivityManagerInternal.java

/**  * Activity manager local system service interface.  */ public abstract class ActivityManagerInternal {     /** Starts a given process. */     public abstract void startProcess(String processName, ApplicationInfo info,             boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName); } 复制代码

这里是个抽象类,咱们去找其实现类 ActivityManagerService.LocalService

9.3.3 ActivityManagerService.LocalService.startProcess()

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

public class ActivityManagerService extends IActivityManager.Stub         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {        ...     @VisibleForTesting     public final class LocalService extends ActivityManagerInternal             implements ActivityManagerLocal {         ...         @Override         public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,                 boolean isTop, String hostingType, ComponentName hostingName) {             try {                 synchronized (ActivityManagerService.this) {                     // 如果该进程称为top app,请设置一个提示,以便在启动该进程时,可以立即应用最高优先级,以避免在附加top app进程之前cpu被其他进程抢占。                                          startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,                             new HostingRecord(hostingType, hostingName, isTop),                             ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,                             false /* isolated */);                 }             } finally {             }         }     } }     复制代码

9.3.4 ActivityManagerService.startProcessLocked()

    /**      * Process management.      */     final ProcessList mProcessList;     @GuardedBy("this")     final ProcessRecord startProcessLocked(String processName,             ApplicationInfo info, boolean knownToBeDead, int intentFlags,             HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,             boolean isolated, boolean keepIfLarge) {         return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,                 hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,                 keepIfLarge, null /* ABI override */, null /* entryPoint */,                 null /* entryPointArgs */, null /* crashHandler */);     } 复制代码

可以看出,这里的 mProcessList 就是 ProcessList

9.3.5 ProcessList.startProcessLocked()

frameworks/base/services/core/java/com/android/server/am/ProcessList.java

    @GuardedBy("mService")     final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,             boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,             int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,             boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs,             Runnable crashHandler) {         ...         final boolean success =                 startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);         checkSlow(startTime, "startProcess: done starting proc!");         return success ? app : null;     }     ------------分割线-------------     @GuardedBy("mService")     final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,             int zygotePolicyFlags, String abiOverride) {         return startProcessLocked(app, hostingRecord, zygotePolicyFlags,                 false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,                 false /* mountExtStorageFull */, abiOverride);     }     ------------分割线-------------     /**      * @return {@code true} if process start is successful, false otherwise.      */     @GuardedBy("mService")     boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,             int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,             boolean mountExtStorageFull, String abiOverride) {             ...             return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,                     runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,                     instructionSet, invokeWith, startTime);     }     ------------分割线-------------     @GuardedBy("mService")     boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,             int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,             String seInfo, String requiredAbi, String instructionSet, String invokeWith,             long startTime) {                 ...                 //终于到重点了。                 final Process.ProcessStartResult startResult = startProcess(hostingRecord,                         entryPoint, app,                         uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,                         requiredAbi, instructionSet, invokeWith, startTime);                                  handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,                         startSeq, false);                 ...     } 复制代码

反复调用,终于看到了关键代码 startProcess()

9.3.6 ProcessList.startProcess()

    private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,             ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,             int mountExternal, String seInfo, String requiredAbi, String instructionSet,             String invokeWith, long startTime) {             ...             final Process.ProcessStartResult startResult;             if (hostingRecord.usesWebviewZygote()) {                 //进程是否应该从 webview zygote 产生                 startResult = startWebView(entryPoint,                         app.processName, uid, uid, gids, runtimeFlags, mountExternal,                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,                         app.info.dataDir, null, app.info.packageName, app.mDisabledCompatChanges,                         new String[]{PROC_START_SEQ_IDENT + app.startSeq});             } else if (hostingRecord.usesAppZygote()) {                 //进程是否应该从应用程序 zygote 中产生                 final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);                 // 我们无法隔离应用程序数据和存储数据,因为父 zygote 已经这样做了。                 startResult = appZygote.getProcess().start(entryPoint,                         app.processName, uid, uid, gids, runtimeFlags, mountExternal,                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,                         app.info.dataDir, null, app.info.packageName,                         /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,                         app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap,                         false, false,                         new String[]{PROC_START_SEQ_IDENT + app.startSeq});             } else {                 startResult = Process.start(entryPoint,                         app.processName, uid, uid, gids, runtimeFlags, mountExternal,                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,                         app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,                         isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,                         whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,                         new String[]{PROC_START_SEQ_IDENT + app.startSeq});             }             ...    } 复制代码

无论那种情况都会调用 Process.start() ;

9.3.7 Process.start()

frameworks/base/core/java/android/os/Process.java

    /**      * State associated with the zygote process.      */     public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();     public static ProcessStartResult start(@NonNull final String processClass,                                            @Nullable final String niceName,                                            int uid, int gid, @Nullable int[] gids,                                            int runtimeFlags,                                            int mountExternal,                                            int targetSdkVersion,                                            @Nullable String seInfo,                                            @NonNull String abi,                                            @Nullable String instructionSet,                                            @Nullable String appDataDir,                                            @Nullable String invokeWith,                                            @Nullable String packageName,                                            int zygotePolicyFlags,                                            boolean isTopApp,                                            @Nullable long[] disabledCompatChanges,                                            @Nullable Map<String, Pair<String, Long>>                                                    pkgDataInfoMap,                                            @Nullable Map<String, Pair<String, Long>>                                                    whitelistedDataInfoMap,                                            boolean bindMountAppsData,                                            boolean bindMountAppStorageDirs,                                            @Nullable String[] zygoteArgs) {         return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,                     abi, instructionSet, appDataDir, invokeWith, packageName,                     zygotePolicyFlags, isTopApp, disabledCompatChanges,                     pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,                     bindMountAppStorageDirs, zygoteArgs);     } 复制代码

这里的 ZYGOTE_PROCESS 就是 ZygoteProcess 。调用其 start() 方法。

9.3.8 ZygoteProcess.start()

frameworks/base/core/java/android/os/ZygoteProcess.java

    /**      * 开始一个新的进程。      * 如果启用了进程,则会创建一个新进程并在那里执行processClass 的静态main() 函数。      * 该函数返回后进程将继续运行。      *       * 如果未启用进程,则会在调用者进程中创建一个新线程并在那里调用 processclass 的 main()。      *       * niceName 参数,如果不是空字符串,则是一个自定义名称,用于提供给进程而不是使用 processClass。      * 这允许您创建易于识别的进程,即使您使用相同的基本 processClass 来启动它们。      *      * 当 invokeWith 不为 null 时,进程将作为一个新的 app 而不是 zygote fork 启动。      * 请注意,这仅适用于 uid 0 或当runtimeFlags 包含 DEBUG_ENABLE_DEBUGGER 时。      *      * @param processClass 用作进程主入口点的类。      * @param niceName 用于进程的更易读的名称。      * @param uid 进程将在其下运行的用户 ID。      * @param gid 进程将在其下运行的组 ID。      * @param gids 与进程关联的附加组 ID。      * @param runtimeFlags 附加标志。      * @param targetSdkVersion 应用的目标 SDK 版本。      * @param seInfo null-ok 新进程的 SELinux 信息。      * @param abi 非空此应用程序应使用的 ABI。      * @param instructionsSet null-确定要使用的指令集。      * @param appDataDir null-ok 应用程序的数据目录。      * @param invokeWith null-ok 要调用的命令。      * @param packageName null-ok 这个进程所属的包名。      * @param zygotePolicyFlags 用于确定如何启动应用程序的标志。      * @param isTopApp 进程是否为高优先级应用程序启动。      * @param disabledCompatChanges 正在启动的进程的禁用兼容更改的 null-ok 列表。      * @param pkgDataInfoMap 从相关包名称映射到私有数据目录卷 UUID 和 inode 编号。      * @param allowlistedDataInfoList 从允许的包名称映射到私有数据目录卷 UUID 和 inode 编号。      * @param bindMountAppsData zygote 是否需要挂载 CE 和 DE 数据。      * @param bindMountAppStorageDirs zygote 是否需要挂载Android/obb 和Android/data。      *      * @param zygoteArgs 提供给 Zygote 进程的附加参数。      * @return 一个对象,描述尝试启动进程的结果。      * @throws RuntimeException 出现致命启动失败      */     //这里从上一个方法传来一大堆参数就不多描述了     public final Process.ProcessStartResult start(...) {         ...             return startViaZygote(processClass, niceName, uid, gid, gids,                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,                     abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,                     packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,                     pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,                     bindMountAppStorageDirs, zygoteArgs);         ...     } 复制代码

9.3.9 ZygoteProcess.startViaZygote()

    //这里从上一个方法传来一大堆参数就不多描述了     private Process.ProcessStartResult startViaZygote(...)                                                       throws ZygoteStartFailedEx {         ...         synchronized(mLock) {             // The USAP pool can not be used if the application will not use the systems graphics             // driver.  If that driver is requested use the Zygote application start path.             return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),                                               zygotePolicyFlags,                                               argsForZygote);         }     } 复制代码

在看 zygoteSendArgsAndGetResult() 之前咱们看看 openZygoteSocketIfNeeded(abi)

9.3.10 ZygoteProcess.openZygoteSocketIfNeeded()

    /**      * 尝试打开一个 session socket到具有兼容 ABI 的 Zygote 进程(如果尚未打开)。 如果兼容的 session socket已经打开,则返回该 session socket。      *       * 此功能可能会阻塞,并且可能必须尝试连接到多个 Zygotes 才能找到合适的 Zygotes。 需要保持 mLock。      */     @GuardedBy("mLock")     private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {         try {             attemptConnectionToPrimaryZygote();             ...     }     ------------分割线-------------     /**      * 如果Primary Zygote不存在或已断开连接,则为它创建一个 ZygoteState。      */     @GuardedBy("mLock")     private void attemptConnectionToPrimaryZygote() throws IOException {         if (primaryZygoteState == null || primaryZygoteState.isClosed()) {             primaryZygoteState =                     ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);             ...         }     }     ------------分割线-------------     static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,             @Nullable LocalSocketAddress usapSocketAddress)             throws IOException {         ...         //创建LocalSocket         final LocalSocket zygoteSessionSocket = new LocalSocket();             //将zygoteSessionSocket连接到端点。             //只能在尚未连接的实例上调用。             zygoteSessionSocket.connect(zygoteSocketAddress);         ...     } 复制代码

打开了 ZygoteSocket 之后咱们看看 zygoteSendArgsAndGetResult();

9.4.11 ZygoteProcess.zygoteSendArgsAndGetResult()

    @GuardedBy("mLock")     private Process.ProcessStartResult zygoteSendArgsAndGetResult(             ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)             throws ZygoteStartFailedEx {         ...         String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";                 return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);     } 复制代码

9.4.12 ZygoteProcess.attemptZygoteSendArgsAndGetResult()

    private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(             ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {         try {             final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;             final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;             //写,调用zygote(ZygoteInit)。             zygoteWriter.write(msgStr);             zygoteWriter.flush();             // Always read the entire result from the input stream to avoid leaving             // bytes in the stream for future process starts to accidentally stumble             // upon.             Process.ProcessStartResult result = new Process.ProcessStartResult();             //读,造成阻塞             result.pid = zygoteInputStream.readInt();             result.usingWrapper = zygoteInputStream.readBoolean();             if (result.pid < 0) {                 throw new ZygoteStartFailedEx("fork() failed");             }             return result;         } catch (IOException ex) {             zygoteState.close();             Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "                     + ex.toString());             throw new ZygoteStartFailedEx(ex);         }     } 复制代码

9.4.13 ZygoteInit.main()

    @UnsupportedAppUsage     public static void main(String[] argv) {             ...             // zygote 永久循环。             caller = zygoteServer.runSelectLoop(abiList);     } 复制代码

9.4.14 ZygoteService.runSelectLoop()

    /**      * 运行 zygote 进程的选择循环。 在新连接发生时接受新连接,并从连接中读取一次一个 spawn-request 值的命令。      * @param abiList 此 zygote 支持的 ABI 列表。      */     Runnable runSelectLoop(String abiList) {         ...                             //Session socket accepted from the Zygote server socket                             ZygoteConnection connection = peers.get(pollIndex);                             //通过 fork 启动 子进程(应用程序)                             final Runnable command = connection.processOneCommand(this);         ...                                        } 复制代码

9.4.15 ZygoteConnection.processOneCommand()

frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

    Runnable processOneCommand(ZygoteServer zygoteServer) {         ...         pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,                 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,                 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,                 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,                 parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList,                 parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);         ...     } 复制代码

fork 出一个新的进程(APP),一个APP的程序入口就是ActivityThread.main()

9.4.15  ActivityThread.main()

frameworks/base/core/java/android/app/ActivityThread.java

在 ActivityThread 初始化的时候,就已经创建消息循环了,所以在主线程里面创建 Handler 不需要指定 Looper,而如果在其他线程使用Handler,则需要 单独使用Looper.prepare()和Looper.loop() 创建消息循环。

    public static void main(String[] args) {         ...         //初始化当前进程的 Looper 对象         Looper.prepareMainLooper();         ...         ActivityThread thread = new ActivityThread();         //此处创建Application         thread.attach(false, startSeq);         if (sMainThreadHandler == null) {             sMainThreadHandler = thread.getHandler();         }         if (false) {             Looper.myLooper().setMessageLogging(new                     LogPrinter(Log.DEBUG, "ActivityThread"));         }         // 调用 Looper 的 loop 方法开启无限循环。         Looper.loop();         throw new RuntimeException("Main thread loop unexpectedly exited");     } 复制代码

Looper :从 MessageQueue 中取出 Message,然后处理 Message 中指定的任务(startActivity)。

至此,不管是调用 startActivity() 启动页面,还是调用 startActivity() 开启其他进程的界面都算完成了。

如有问题麻烦指正。

相关推荐


作者:Android帅次
链接:https://juejin.cn/post/7018015055108702221


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐