深入浅出系列之从new一个Activity的操作延伸到Activity启动流程

151 阅读7分钟

前言

前段时间在公司一个老项目中 , 看到一个操作——直接new了一个activity,当然最后他没有调用,估计是调用后发现崩溃了,当时的第一反应是怎么敢这样干的啊 , activity 的创建应该是 AMS 干的,自己 new 的 activity 系统就没办法进行管理 , 关于 activity 的生命周期等等全部都乱套了 , 然后就在想 , 那 Android 的 activity 是如何启动的 , 甚至与 Android 系统是如何启动的 ?

image.png

**一、为什么不能直接new一个Activity?

从本质上看,Activity 只是一个普通的类,继承自 Object,直接 new 一个 Activity 并不会在编译时出错。然而,Android 系统中的 Activity 是通过 AMS 和 Instrumentation 配合创建的,直接 new 出来的 Activity 不在系统的生命周期管理中,进而导致问题。

系统创建的 Activity 和自己 new 的区别

1、系统创建(Instrumentation 的 newInstance 方法)
系统通过类加载器的 newInstance 方法创建 Activity 实例,这种方式更灵活,能更好地解耦系统与类之间的依赖。

2、自己 new 的 Activity
直接 new 创建的类没有经过类加载器初始化,依赖于 public 构造方法,类名变化时也需要手动调整,强耦合问题显著。

为什么自己 new 会报错?

Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference

(报错信息)

当执行 super.onCreate() 方法时,系统会为 Activity 添加窗口(Window),而直接 new 出来的 Activity 不在系统管理中,没有窗口实例,调用相关方法时自然会报错。

值得一提的是,如果只调用与视图无关的方法(例如普通的逻辑处理),new 出来的 Activity 确实可以正常运行,但这显然违背了 Android 的设计初衷。

二、 简述 Android 系统的启动流程

在研究Activity的启动流程时,我就在想,Android系统的启动流程是什么样子的,所以先大概了解了一下,如果有如果的话,我再找时间深入了解一下Android的启动流程,然后继续分享。这里直接说结论 :

  1. 电源按下
    设备引导芯片开始执行,加载 BootLoader 到内存。
  2. 引导程序 BootLoader
    引导程序启动操作系统。
  3. Linux 内核启动
    初始化缓存、驱动和基本系统服务,并启动 init 进程。
  4. init 进程
    加载配置文件,启动 Zygote 进程。
  5. Zygote 进程
    创建 JVM 环境,为应用进程提供运行环境。
  6. SystemServer 进程
    启动系统服务,例如 AMS、WMS 等。
  7. Launcher 启动
    由 AMS 启动 Launcher,负责展示桌面应用图标。

三、Android 系统中的重要角色

ActivityManagerService (AMS)

ActivityManagerService(简称AMS)是系统服务端对象,负责管理系统中所有Activity的生命周期。在SystemServer进程启动时,会初始化AMS,完成成员变量的赋值。在此之前,系统通过createSystemContext()完成了系统上下文mSystemContext和ActivityThread的创建。
系统启动流程中,AMS初始化后会启动Launcher程序,加载并显示系统界面。

AMS作为服务端对象,主要通过Binder进行IPC通信,负责调度应用间的操作。例如,当调用startActivity()启动一个App时,实际上是通过AMS通知zygote进程fork一个新进程来完成。AMS统一调度Activity的启动、暂停、关闭等生命周期操作。需要注意,AMS(SystemServer进程)、应用进程和zygote是独立的进程,通过Binder或Socket进行通信。


Launcher

Launcher本质上是一个继承自Activity的应用程序,用于启动其他应用。它实现了点击、长按等回调接口来接收用户输入,并通过startActivity()发送Intent启动目标App。


Instrumentation

每个应用进程只有一个Instrumentation对象,负责管理Activity的创建和生命周期操作。调用startActivityForResult()时,最终会调用mInstrumentation.execStartActivity()。Instrumentation可视为应用进程的“管家”,ActivityThread依赖它完成Activity的创建、暂停等具体操作。


ActivityThread

ActivityThread是App的真正入口,通过main()方法启动消息循环队列,也就是主线程。ActivityThread与AMS通过Binder进行IPC通信,共同管理Activity的生命周期。当调用startActivity时,实际流程是:

  1. 调用Instrumentation的execStartActivity

  2. 通过ActivityManagerNative.getDefault().startActivity(),获取AMS的远程代理(ActivityManagerProxy)。

  3. 使用Binder的transact()方法封装参数,向AMS发送启动请求。

ApplicationThread & ApplicationThreadProxy

  • ApplicationThread:ActivityManagerService与ActivityThread交互的桥梁,负责接收AMS对Activity生命周期管理的请求。

  • ApplicationThreadProxy:AMS端的ApplicationThread代理,通过它与客户端的ApplicationThread通讯。


ActivityStack & ActivityRecord

  • ActivityStack:AMS中用于管理Activity的栈结构,记录Activity的启动顺序和状态。AMS通过ActivityStack判断是否需要启动新进程。

  • ActivityRecord:ActivityStack中的单个Activity记录对象,映射服务器端Activity的状态信息。


TaskRecord

TaskRecord是AMS中抽象出的“任务”概念,用于管理ActivityRecord的集合。每个TaskRecord代表一个任务栈,包含若干ActivityRecord。AMS通过TaskRecord确保Activity的启动和退出顺序,与Activity的四种launchMode密切相关。

四、Activity 启动流程详解

  • Launcher 通知 AMS
    Launcher 调用 startActivity 方法,通过 IPC 通信向 AMS 发送启动请求。
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {       ...       intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);       ...       startActivity(intent, optsBundle);       ...   }
@Override   public void startActivity(Intent intent, @Nullable Bundle options) {       ...       if (options != null) {           startActivityForResult(intent, -1, options);       } else {           startActivityForResult(intent, -1);       }   }
   public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,           @Nullable Bundle options) {           ...           Instrumentation.ActivityResult ar =               mInstrumentation.execStartActivity(                   this, mMainThread.getApplicationThread(), mToken,this,intent, requestCode, options);           ...}
public ActivityResult execStartActivity(            Context who, IBinder contextThread, IBinder token, Activity target,            Intent intent, int requestCode, Bundle options) {    ...  int result = ActivityTaskManager.getService().startActivity(whoThread,who.getBasePackageName(),        who.getAttributionTag(),intent,intent.resolveTypeIfNeeded(who.getContentResolver()),        token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);     ...}

(每一个应用程序只有一个Instrumentation对象,当我们调用startActivity,实际上是调用到了Instrumentation的execStartActivity)

  • AMS 管理请求
    AMS 通过 Binder 通信与目标应用的 ActivityThread 交互,协调 Activity 的启动。
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {    ...    if (mResumedActivity != null) {       pausing |= startPausingLocked(userLeaving, false , next);    }    ...    mStackSupervisor.startSpecificActivity(next, true, false);    ... }

(ActivityStack)

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {        final WindowProcessController wpc =                mService.getProcessController(r.processName, r.info.applicationInfo.uid);        boolean knownToBeDead = false;        if (wpc != null && wpc.hasThread()) {            try {                realStartActivityLocked(r, wpc, andResume, checkConfig);                return;            } catch (RemoteException e) {                Slog.w(TAG, "Exception when starting activity "                        + r.intent.getComponent().flattenToShortString(), e);            }
            // If a dead object exception was thrown -- fall through to            // restart the application.            knownToBeDead = true;        }        r.notifyUnknownVisibilityLaunchedForKeyguardTransition();        final boolean isTop = andResume && r.isTopRunningActivity();        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");}

(ActivityStackSupervisor)

  • ActivityThread 创建 Activity
    ActivityThread 调用 Instrumentation 的 execStartActivity 方法,通过类加载器初始化目标 Activity,并启动。
    public static void main(String[] args) {        ...        Looper.prepareMainLooper();  ...        ActivityThread thread = new ActivityThread();        thread.attach(false, startSeq);  ...        Looper.loop();  ...    }
    private void attach(boolean system, long startSeq) {            final IActivityManager mgr = ActivityManager.getService();            try {                mgr.attachApplication(mAppThread, startSeq);            } catch (RemoteException ex) {                throw ex.rethrowFromSystemServer();            }            ...}

(ActivityManagerService)

public final void bindApplication(String processName, ApplicationInfo appInfo,                ProviderInfoList providerList, ComponentName instrumentationName,                ProfilerInfo profilerInfo, Bundle instrumentationArgs,                IInstrumentationWatcher instrumentationWatcher,                IUiAutomationConnection instrumentationUiConnection, int debugMode,                boolean enableBinderTracking, boolean trackAllocation,                boolean isRestrictedBackupMode, boolean persistent, Configuration config,                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,                String buildSerial, AutofillOptions autofillOptions,                ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {                  ...                  sendMessage(H.BIND_APPLICATION, data); }                public void handleMessage(Message msg) {    switch (msg.what) {       case BIND_APPLICATION:         AppBindData data = (AppBindData)msg.obj;         handleBindApplication(data);         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);         break;        ...      }}
private void handleBindApplication(AppBindData data) {  ...  mInstrumentation.callApplicationOnCreate(app);  ...}
  • Activity 生命周期方法回调
    系统依次调用 onCreateonStartonResume 等生命周期方法,完成界面加载。

五、为什么没有跨应用的启动Activity也要用到跨进程通信

因为Android需要统一管理所有Activity及其生命周期回调,无论是在同一进程内还是跨进程启动Activity组件,操作都必须经过AMS。当需要启动其他应用的Activity且目标进程尚未存在时,AMS会通过SystemServer进程通知Zygote进程,fork出一个新的子进程作为目标Activity组件的宿主进程。这种设计确保了所有Activity的启动、暂停等操作统一由AMS调度和管理,实现系统资源的高效利用和稳定性。

六、总结

Activity 的启动是一个复杂但极具条理的过程,AMS、Instrumentation、ActivityThread 等多个组件共同协作,确保应用运行在受控环境中。这种设计不仅增强了系统的稳定性,也为开发者提供了灵活的扩展接口。

而对于 Android 系统的启动流程来说,深入了解其底层机制不仅有助于优化代码性能,也能帮助我们在调试过程中快速定位问题。

原文链接:mp.weixin.qq.com/s/P93EDa-TP…

主页地址:blog.itpub.net/69917874/li…