AMS核心机制:Activity生命周期与进程管理深度解析

引言

在上一篇文章中,我们见证了Zygote如何"孵化"应用进程,但进程诞生后的生命历程由谁来管理?Activity如何启动?进程优先级如何决定?内存不足时哪个进程会被杀掉?

这一切的答案都指向ActivityManagerService(AMS)------Android系统中最核心、最复杂的系统服务之一。

想象这样一个场景:你同时打开了微信、Chrome和抖音,切换应用时系统秒开,内存吃紧时后台应用自动被杀掉却不影响前台体验。这背后的"指挥官"就是AMS

scss 复制代码
你点击应用图标
    ↓
Launcher通知AMS
    ↓
AMS检查进程是否存在
    ↓ (不存在)
AMS通知Zygote fork新进程
    ↓
AMS启动Activity并管理生命周期
    ↓
AMS持续监控进程状态,调整优先级
    ↓ (内存不足时)
AMS决定杀掉哪个进程(基于adj值)

📖 系列前置阅读:建议先阅读第13篇(Zygote进程孵化),理解应用进程的创建过程。


AMS是什么?

AMS的"分家"史:从AMS到AMS+ATMS

在Android 10之前,ActivityManagerService是一个"超级服务",负责Activity、Service、Broadcast、ContentProvider、进程管理、内存管理等几乎所有应用生命周期相关的工作。这导致代码臃肿(超过2万行)、职责不清、难以维护。

Android 10重大重构:Google将AMS拆分为两部分:

服务 职责 核心功能
AMS 进程与生命周期管理 进程启动/销毁、OOM Adj调整、Service/Broadcast管理
ATMS Activity任务管理 Activity启动/生命周期、任务栈管理、窗口状态

拆分的好处:

  • 职责清晰: ATMS专注窗口任务,AMS专注进程管理
  • 代码简化: 单个服务代码量减少约40%
  • 性能优化: 减少锁竞争,提升多任务切换性能
  • 可维护性: 模块化设计,更容易添加新特性

AMS的核心职责

1. 进程生命周期管理

  • 进程创建请求(通过Zygote)
  • 进程优先级调整(OOM Adj机制)
  • 进程销毁决策(LMK配合)

2. 四大组件管理

  • Service启动/绑定/停止
  • Broadcast注册/发送/接收
  • ContentProvider发布/查询
  • Activity管理(Android 10+由ATMS负责)

3. 系统状态管理

  • 应用ANR监控
  • 内存状态监控
  • 电池优化(Doze/App Standby)

ATMS的核心职责

1. Activity任务管理

  • Activity启动流程协调
  • 生命周期回调管理
  • 配置变更处理

2. 任务栈管理

  • Task栈创建/切换
  • 启动模式处理(standard/singleTop/singleTask/singleInstance)
  • Recent任务管理

3. 窗口状态管理

  • 与WindowManagerService协作
  • 多窗口/分屏模式
  • 画中画(PiP)模式

AMS与ATMS的架构关系

整体架构图

为了帮助理解AMS和ATMS的协作关系,下图展示了完整的架构:

图:AMS与ATMS分工协作,ATMS负责Activity任务管理,AMS负责进程与生命周期管理,两者通过ActivityManagerInternal/ActivityTaskManagerInternal接口通信

这张图涵盖了:

  • 应用层: App进程通过Binder调用AMS/ATMS
  • ATMS层: Activity启动、栈管理、生命周期
  • AMS层: 进程管理、OOM Adj、Service/Broadcast
  • 底层协作: Zygote进程创建、WMS窗口管理、LMK内存回收

接下来,我们将逐一深入这些核心机制的源码实现。


Activity启动流程深度解析

启动流程全景

Activity启动涉及多个进程和系统服务的协作,是Android中最复杂的流程之一。

scss 复制代码
┌─────────────────────────────────────────────────────────────┐
│  应用进程A (Launcher)                                        │
│  - 调用startActivity()                                      │
│  - 通过Binder调用ATMS                                       │
└────────────┬────────────────────────────────────────────────┘
             │ Binder IPC
             ↓
┌─────────────────────────────────────────────────────────────┐
│  SystemServer进程                                            │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  ATMS (ActivityTaskManagerService)                  │   │
│  │  1. 权限检查                                        │   │
│  │  2. 解析Intent,找到目标Activity                     │   │
│  │  3. 检查目标进程是否存在                            │   │
│  │  4. 如果不存在,通知AMS创建进程                      │   │
│  │  5. 如果存在,直接启动Activity                       │   │
│  └──────────────┬──────────────────────────────────────┘   │
│                 │                                            │
│  ┌──────────────▼──────────────────────────────────────┐   │
│  │  AMS (ActivityManagerService)                       │   │
│  │  - 调用Process.start()通知Zygote                    │   │
│  │  - 等待新进程启动完成                               │   │
│  └─────────────────────────────────────────────────────┘   │
└────────────┬────────────────────────────────────────────────┘
             │ Socket: /dev/socket/zygote
             ↓
┌─────────────────────────────────────────────────────────────┐
│  Zygote进程                                                  │
│  - fork()创建新进程                                         │
│  - 新进程调用ActivityThread.main()                          │
└────────────┬────────────────────────────────────────────────┘
             │
             ↓
┌─────────────────────────────────────────────────────────────┐
│  应用进程B (新创建)                                          │
│  1. ActivityThread.main()启动                               │
│  2. 通过Binder通知ATMS: "我准备好了"                         │
│  3. ATMS调用ApplicationThread.scheduleLaunchActivity()     │
│  4. ActivityThread通过Handler发送LAUNCH_ACTIVITY消息        │
│  5. 创建Activity实例                                        │
│  6. 依次调用: onCreate() → onStart() → onResume()           │
│  7. Activity界面显示                                        │
└─────────────────────────────────────────────────────────────┘

核心源码分析

1. startActivity入口(应用进程)

java 复制代码
// frameworks/base/core/java/android/app/Activity.java
public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

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) {
    // mParent通常为null(非嵌套Activity)
    if (mParent == null) {
        // 关键:通过Instrumentation启动Activity
        // mMainThread.getApplicationThread()返回ApplicationThread(Binder Stub)
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this,                              // 当前Activity上下文
                mMainThread.getApplicationThread(), // ApplicationThread
                mToken,                            // Activity的IBinder token
                this,                              // 目标Activity
                intent,                            // Intent
                requestCode,                       // 请求码
                options);                          // Bundle选项
    } else {
        // 嵌套Activity逻辑(已废弃)
    }
}

关键点:

  • mInstrumentation: 应用进程的"代理人",负责与系统交互
  • mMainThread.getApplicationThread(): 返回ApplicationThread,是AMS回调应用进程的Binder接口

2. Instrumentation跨进程调用(应用进程)

java 复制代码
// frameworks/base/core/java/android/app/Instrumentation.java
public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {

    // 获取ApplicationThread(Binder Stub)
    IApplicationThread whoThread = (IApplicationThread) contextThread;

    try {
        intent.migrateExtraStreamToClipData(who);
        intent.prepareToLeaveProcess(who);

        // 关键:跨进程调用ATMS的startActivity
        int result = ActivityTaskManager.getService().startActivity(
            whoThread,              // 应用进程的Binder接口
            who.getBasePackageName(), // 调用者包名
            who.getAttributionTag(),
            intent,                 // Intent
            intent.resolveTypeIfNeeded(who.getContentResolver()),
            token,                  // Activity token
            target != null ? target.mEmbeddedID : null,
            requestCode,            // 请求码
            0,                      // flags
            null,                   // profilerInfo
            options);               // Bundle

        // 检查启动结果,如果失败抛出异常
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

关键点:

  • ActivityTaskManager.getService(): 获取ATMS的Binder代理
  • 跨进程调用通过Binder完成,数据通过Parcel序列化传输

3. ATMS处理启动请求(SystemServer进程)

java 复制代码
// frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
        String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
        Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, callingFeatureId, intent,
            resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
            bOptions, UserHandle.getCallingUserId());
}

private 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) {
    // 权限检查
    enforceNotIsolatedCaller("startActivityAsUser");

    // 检查调用者身份
    userId = mAmInternal.handleIncomingUser(Binder.getCallingPid(),
            Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY,
            "startActivityAsUser", null);

    // 关键:通过ActivityStarter处理启动
    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. ActivityStarter启动协调器(SystemServer进程)

ActivityStarter是Activity启动的核心协调器,负责:

  • 解析Intent,找到目标Activity
  • 检查权限和启动条件
  • 决定创建新任务还是复用现有任务
  • 协调进程创建(如果需要)
java 复制代码
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
int execute() {
    try {
        // 如果Intent包含多个Activity,批量启动
        if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        // 核心启动逻辑
        int res;
        synchronized (mService.mGlobalLock) {
            res = executeRequest(mRequest);
        }

        return res;
    } finally {
        onExecutionComplete();
    }
}

private int executeRequest(Request request) {
    // ...权限检查、Intent解析...

    // 获取ActivityInfo(目标Activity的信息)
    ActivityInfo aInfo = mSupervisor.resolveActivity(mRequest.intent, mRequest.resolvedType,
            mRequest.startFlags, profilerInfo, mRequest.userId, mRequest.filterCallingUid);

    // 检查目标Activity是否被禁用
    if (aInfo != null) {
        // 检查调用者是否有权限启动
        // 检查目标Activity的exported属性
        // 检查权限保护级别
    }

    // 关键:启动Activity
    final ActivityRecord r = new ActivityRecord(...); // 创建ActivityRecord
    mLastStartActivityRecord = r;

    // 调用startActivityUnchecked继续处理
    return startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor,
            startFlags, true /* doResume */, checkedOptions, inTask, inTaskFragment,
            balCode, intentGrants, restrictedBgActivity);
}

Activity启动的状态机

Activity启动过程是一个复杂的状态机,涉及多个状态转换:

scss 复制代码
INITIALIZING (初始化)
    ↓
STARTED (已启动,等待进程)
    ↓
RESUMED (已恢复,前台显示)
    ↓
PAUSED (暂停,部分可见)
    ↓
STOPPED (停止,完全不可见)
    ↓
DESTROYED (已销毁)

Activity生命周期管理

生命周期回调顺序

Activity生命周期是Android开发者最熟悉的概念,但背后的实现机制涉及多个系统组件的协作。

scss 复制代码
Activity A启动    → onCreate() → onStart() → onResume() (前台运行)
                     ↓
点击Home键或打开新Activity
                     ↓
Activity A暂停    → onPause() (仍可见,失去焦点)
                     ↓
Activity A完全被覆盖
                     ↓
Activity A停止    → onStop() (不可见)
                     ↓
内存不足或用户主动销毁
                     ↓
Activity A销毁    → onDestroy()

生命周期源码分析

1. onCreate()触发时机

java 复制代码
// frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // 1. 创建Activity实例
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
    } catch (Exception e) {
        // 处理异常
    }

    try {
        // 2. 创建Application(如果还未创建)
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {
            // 3. 初始化Activity上下文
            Context appContext = createBaseContextForActivity(r);

            // 4. attach Activity(关联Window、PhoneWindow等)
            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);

            // 5. 调用onCreate()
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state,
                        r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }

            // 6. 调用onStart()
            if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }
        }
    } catch (Exception e) {
        // 处理异常
    }

    return activity;
}

2. onResume()触发时机

java 复制代码
// frameworks/base/core/java/android/app/ActivityThread.java
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {
    // 1. 执行onResume()回调
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);

    if (r != null) {
        final Activity a = r.activity;

        // 2. 将Activity的DecorView添加到WindowManager
        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;

            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l); // 添加到WindowManager
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }
        }

        // 3. 让Activity可见
        if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
            r.activity.mVisibleFromServer = true;
            mNumVisibleActivities++;
            if (r.activity.mVisibleFromClient) {
                r.activity.makeVisible(); // 设置DecorView为VISIBLE
            }
        }
    }
}

配置变更处理(Configuration Change)

当设备配置发生变化时(如屏幕旋转、语言切换、深色模式切换),Android默认会销毁并重建Activity

java 复制代码
// frameworks/base/core/java/android/app/ActivityThread.java
@Override
public void handleConfigurationChanged(Configuration config, int displayId) {
    // 更新Application的配置
    if (mApplication != null) {
        mApplication.onConfigurationChanged(config);
    }

    // 通知所有Activity配置变更
    synchronized (mResourcesManager) {
        // 遍历所有ActivityClientRecord
        for (int i = mActivities.size() - 1; i >= 0; i--) {
            ActivityClientRecord r = mActivities.valueAt(i);
            if (r.activity != null) {
                // 如果Activity声明了configChanges,调用onConfigurationChanged
                // 否则销毁重建Activity
                if ((r.activityInfo.configChanges & ActivityInfo.CONFIG_ORIENTATION) == 0) {
                    // 未声明configChanges,需要重启Activity
                    scheduleRelaunchActivity(r.token);
                } else {
                    // 已声明configChanges,只回调onConfigurationChanged
                    r.activity.onConfigurationChanged(config);
                }
            }
        }
    }
}

如何避免重建 :在AndroidManifest.xml中声明android:configChanges:

xml 复制代码
<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|keyboardHidden" />

进程优先级管理:OOM Adj机制

什么是OOM Adj?

OOM Adj(Out-Of-Memory Adjustment) 是Android进程优先级的核心机制,用于决定:

  • 哪些进程可以获得更多CPU资源
  • 内存不足时优先杀掉哪些进程
  • 后台限制策略(如网络访问、定位服务)

Adj值越低,优先级越高,越不容易被杀死。

Adj值定义

java 复制代码
// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
public final class ProcessList {
    // 最高优先级(Native守护进程)
    static final int NATIVE_ADJ = -1000;

    // 系统进程(SystemServer)
    static final int SYSTEM_ADJ = -900;

    // 持久化进程(system/persistent应用)
    static final int PERSISTENT_PROC_ADJ = -800;

    // 持久化服务进程
    static final int PERSISTENT_SERVICE_ADJ = -700;

    // 前台进程(用户正在交互)
    static final int FOREGROUND_APP_ADJ = 0;

    // 可见进程(Activity可见但不在前台)
    static final int VISIBLE_APP_ADJ = 100;

    // 可感知进程(Activity部分可见,如悬浮窗)
    static final int PERCEPTIBLE_APP_ADJ = 200;

    // 备份进程
    static final int BACKUP_APP_ADJ = 300;

    // 服务进程(后台Service)
    static final int SERVICE_ADJ = 500;

    // Home进程(Launcher)
    static final int HOME_APP_ADJ = 600;

    // 上一个可见进程(按Back键回到后台)
    static final int PREVIOUS_APP_ADJ = 700;

    // 缓存进程(最低优先级)
    static final int CACHED_APP_MIN_ADJ = 900;
    static final int CACHED_APP_MAX_ADJ = 999;
}

OOM Adj调整时机

AMS会在以下场景触发adj值重新计算:

java 复制代码
// frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
void updateOomAdjLocked(String oomAdjReason) {
    final long now = SystemClock.uptimeMillis();
    final long oldTime = now - mConstants.MAX_EMPTY_TIME; // 30分钟

    // 1. 遍历所有进程
    for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
        final ProcessRecord app = mProcessList.mLruProcesses.get(i);

        // 2. 计算新的adj值
        final int prevAppAdj = app.mState.getCurAdj();
        final int prevProcState = app.mState.getCurProcState();

        computeOomAdjLocked(app, cachedAdj, topApp, now, oomAdjReason, true);

        // 3. 如果adj值或procState变化,应用新值
        if (app.mState.getCurAdj() != prevAppAdj
                || app.mState.getCurProcState() != prevProcState) {
            applyOomAdjLocked(app, true, now, SystemClock.elapsedRealtime());
        }
    }
}

触发时机:

  • ✅ Activity启动/切换
  • ✅ Service启动/绑定/解绑
  • ✅ Broadcast发送/接收
  • ✅ ContentProvider查询
  • ✅ 进程启动/死亡
  • ✅ 内存压力变化

Adj值计算逻辑

java 复制代码
// frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
private boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
        ProcessRecord topApp, long now, String oomAdjReason, boolean doingAll) {

    // 1. 如果是前台进程,直接设置为FOREGROUND_APP_ADJ
    if (app == topApp && app.hasTopUi()) {
        app.mState.setCurAdj(ProcessList.FOREGROUND_APP_ADJ);
        app.mState.setCurProcState(PROCESS_STATE_TOP);
        return true;
    }

    // 2. 如果有前台Service,设置为PERCEPTIBLE_APP_ADJ
    if (app.mServices.hasForegroundServices()) {
        app.mState.setCurAdj(ProcessList.PERCEPTIBLE_APP_ADJ);
        app.mState.setCurProcState(PROCESS_STATE_FOREGROUND_SERVICE);
        return true;
    }

    // 3. 如果有可见Activity,设置为VISIBLE_APP_ADJ
    if (app.hasVisibleActivities()) {
        app.mState.setCurAdj(ProcessList.VISIBLE_APP_ADJ);
        app.mState.setCurProcState(PROCESS_STATE_TOP);
        return true;
    }

    // 4. 如果有Service被前台进程绑定,提升优先级
    for (int is = app.mServices.numberOfRunningServices() - 1; is >= 0; is--) {
        ServiceRecord sr = app.mServices.getRunningServiceAt(is);
        if (sr.connections.size() > 0) {
            for (int conni = sr.connections.size() - 1; conni >= 0; conni--) {
                ConnectionRecord cr = sr.connections.valueAt(conni);
                if (cr.binding.client == topApp) {
                    // 被前台应用绑定的Service,提升为VISIBLE_APP_ADJ
                    app.mState.setCurAdj(ProcessList.VISIBLE_APP_ADJ);
                    return true;
                }
            }
        }
    }

    // 5. 如果是缓存进程,设置为CACHED_APP_ADJ
    app.mState.setCurAdj(cachedAdj);
    app.mState.setCurProcState(PROCESS_STATE_CACHED_EMPTY);
    return true;
}

Low Memory Killer (LMK)

LMK工作原理

当系统内存不足时,Low Memory Killer(LMK) 会根据adj值杀掉低优先级进程来释放内存。

makefile 复制代码
内存压力级别:
Critical (严重) → 杀掉adj >= 900的进程(缓存进程)
Moderate (中等) → 杀掉adj >= 700的进程(上一个应用)
Low (轻微)      → 杀掉adj >= 800的进程(部分缓存进程)

LMK的实现演进

Android版本 LMK实现 说明
Android 1.0-9 Kernel LMK 内核驱动,根据adj值杀进程
Android 10-11 lmkd守护进程 用户空间守护进程,更灵活
Android 12+ lmkd+PSI 结合PSI(Pressure Stall Information)预测内存压力

lmkd守护进程

cpp 复制代码
// system/core/lmkd/lmkd.cpp
static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_params) {
    // 读取PSI内存压力信息
    int64_t mem_usage = get_memory_usage(&mem_st);

    // 根据内存压力等级决定杀掉哪些进程
    if (mem_usage > critical_threshold) {
        // 严重内存压力,杀掉adj >= 900的进程
        kill_processes(CACHED_APP_MIN_ADJ, "critical");
    } else if (mem_usage > moderate_threshold) {
        // 中等内存压力,杀掉adj >= 800的进程
        kill_processes(PREVIOUS_APP_ADJ, "moderate");
    }
}

static int kill_processes(int min_oom_adj, const char* reason) {
    // 从AMS获取进程列表
    std::vector<ProcessRecord> procs = get_process_list();

    // 按adj值排序(从高到低)
    std::sort(procs.begin(), procs.end(),
        [](const ProcessRecord& a, const ProcessRecord& b) {
            return a.oom_adj > b.oom_adj;
        });

    // 杀掉adj值 >= min_oom_adj的进程
    for (const auto& proc : procs) {
        if (proc.oom_adj >= min_oom_adj) {
            kill(proc.pid, SIGKILL);
            ALOGI("Killed %s (pid %d, adj %d) reason: %s",
                  proc.process_name, proc.pid, proc.oom_adj, reason);
            break; // 杀一个进程后重新评估内存
        }
    }
}

查看进程adj值

bash 复制代码
# 查看所有进程的adj值
adb shell "cat /proc/$(adb shell pidof com.android.systemui | tr -d '\r')/oom_score_adj"
# 输出: 0 (FOREGROUND_APP_ADJ,前台应用)

# 查看进程详细信息
adb shell dumpsys activity processes | grep -A 10 "com.example.app"

Service与Broadcast管理

Service启动流程

Service有两种启动方式:

  • startService(): 独立运行,不与调用者绑定
  • bindService(): 绑定运行,随调用者生命周期
java 复制代码
// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service,
        String resolvedType, int callingPid, int callingUid, boolean fgRequired,
        String callingPackage, final int userId) {

    // 1. 解析Intent,找到目标Service
    ServiceLookupResult res = retrieveServiceLocked(service, null, resolvedType,
            callingPackage, callingPid, callingUid, userId, true, callerFg, false, false);

    ServiceRecord r = res.record;

    // 2. 检查是否需要创建进程
    if (r.app == null || r.app.getThread() == null) {
        // 进程不存在,通知AMS创建进程
        app = mAm.getProcessRecordLocked(processName, r.appInfo.uid);
        if (app == null || app.getThread() == null) {
            app = mAm.startProcessLocked(processName, r.appInfo, true, 0,
                    hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, false);
        }
    }

    // 3. 调用Service的onCreate()
    realStartServiceLocked(r, app, execInFg);
}

Broadcast发送流程

Broadcast分为两种:

  • 普通广播: 异步发送,所有接收者并行接收
  • 有序广播: 按优先级顺序发送,可以被拦截
java 复制代码
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle resultExtras,
        String[] requiredPermissions, int appOp, Bundle bOptions,
        boolean serialized, boolean sticky, int userId) {

    // 1. 权限检查
    enforceNotIsolatedCaller("broadcastIntent");

    // 2. 查找所有匹配的Receiver
    List<ResolveInfo> receivers = AppGlobals.getPackageManager()
            .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, userId);

    // 3. 创建BroadcastRecord
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
            callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
            requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
            resultData, resultExtras, ordered, sticky, false, userId, false);

    // 4. 加入广播队列
    final BroadcastQueue queue = broadcastQueueForIntent(intent);
    queue.enqueueOrderedBroadcastLocked(r);
    queue.scheduleBroadcastsLocked();
}

任务栈管理(Task Stack)

任务栈的概念

Task(任务) 是一组相关Activity的集合,以栈的形式组织(后进先出,LIFO)。

scss 复制代码
┌─────────────────────────┐
│  Task 1 (前台任务)       │
│  ┌───────────────────┐  │
│  │ Activity C (栈顶) │  │ ← 用户看到的界面
│  ├───────────────────┤  │
│  │ Activity B        │  │
│  ├───────────────────┤  │
│  │ Activity A (栈底) │  │
│  └───────────────────┘  │
└─────────────────────────┘

┌─────────────────────────┐
│  Task 2 (后台任务)       │
│  ┌───────────────────┐  │
│  │ Activity X (栈顶) │  │
│  ├───────────────────┤  │
│  │ Activity Y        │  │
│  └───────────────────┘  │
└─────────────────────────┘

启动模式(Launch Mode)

Android提供4种启动模式,控制Activity的实例化和栈行为:

启动模式 行为 使用场景
standard 每次都创建新实例,可以有多个实例 普通Activity(默认)
singleTop 如果栈顶是该Activity,复用;否则创建新实例 通知点击跳转、搜索结果页
singleTask 全局唯一实例,存在则清空其上的Activity 应用主页(MainActivity)
singleInstance 全局唯一实例,且独占一个Task 来电界面、闹钟响铃

启动模式源码实现

java 复制代码
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, Task inTask,
        TaskFragment inTaskFragment, NeededUriGrants intentGrants,
        BackgroundActivityStartController balController) {

    // 1. 根据LaunchMode决定是否复用Activity
    final int launchMode = r.launchMode;
    if (launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
        // singleTop模式:检查栈顶
        if (mTargetRootTask.getTopNonFinishingActivity() == r) {
            // 栈顶就是该Activity,复用,调用onNewIntent()
            deliverNewIntent(r, intentGrants);
            return START_DELIVERED_TO_TOP;
        }
    } else if (launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
            || launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        // singleTask/singleInstance:查找已存在的实例
        ActivityRecord intentActivity = mRootWindowContainer.findTask(r, options);
        if (intentActivity != null) {
            // 找到已存在的实例,清空其上的Activity
            intentActivity.getTask().performClearTaskForReuse(true);
            deliverNewIntent(intentActivity, intentGrants);
            return START_TASK_TO_FRONT;
        }
    }

    // 2. 没有复用,创建新实例
    mTargetRootTask.startActivityLocked(r, topRootTask, newTask, isTaskSwitch, options,
            intentGrants);
    return START_SUCCESS;
}

ANR(Application Not Responding)

ANR触发条件

ANR是Android保护用户体验的机制,当应用在主线程阻塞太久时,系统会弹出"应用无响应"对话框。

场景 超时时间 说明
Input事件 5秒 触摸/按键事件未处理完
BroadcastReceiver 10秒(前台) / 60秒(后台) onReceive()未执行完
Service 20秒(前台) / 200秒(后台) onCreate/onStartCommand未执行完
ContentProvider 10秒 ContentProvider启动超时

ANR检测机制

java 复制代码
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
void appNotResponding(ProcessRecord app, String activityShortComponentName,
        ApplicationInfo aInfo, String parentShortComponentName,
        WindowProcessController parentProcess, boolean aboveSystem, String annotation,
        boolean onlyDumpSelf) {

    synchronized (this) {
        // 1. 检查是否已在ANR
        if (app.isNotResponding()) {
            Slog.i(TAG, "Skipping duplicate ANR: " + app);
            return;
        }

        // 2. 标记为ANR状态
        app.setNotResponding(true);

        // 3. 收集ANR信息
        StringBuilder info = new StringBuilder();
        info.append("ANR in ").append(app.processName);
        if (activityShortComponentName != null) {
            info.append(" (").append(activityShortComponentName).append(")");
        }
        info.append("\n");
        info.append("PID: ").append(app.getPid()).append("\n");
        if (annotation != null) {
            info.append("Reason: ").append(annotation).append("\n");
        }

        // 4. dump堆栈信息到/data/anr/traces.txt
        final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
        final File tracesFile = ActivityManagerService.dumpStackTraces(
                app, processCpuTracker, null, null, null);

        // 5. 显示ANR对话框或直接杀掉进程
        Message msg = Message.obtain();
        msg.what = SHOW_NOT_RESPONDING_UI_MSG;
        msg.obj = new AppNotRespondingDialog.Data(app, aInfo, aboveSystem);
        mUiHandler.sendMessage(msg);
    }
}

ANR日志分析

ANR发生时,系统会生成日志:

bash 复制代码
# 查看ANR日志
adb shell cat /data/anr/traces.txt

# 示例输出
----- pid 12345 at 2026-02-10 10:30:15 -----
Cmd line: com.example.app

suspend all histogram:	Sum: 245us 99% C.I. 0.500us-110.500us Avg: 35us Max: 110us
DALVIK THREADS (23):
"main" prio=5 tid=1 Sleeping
  | group="main" sCount=1 ucsCount=0 flags=1 obj=0x75a0d0a0 self=0x7f8c4a4000
  | sysTid=12345 nice=-10 cgrp=default sched=0/0 handle=0x7f8c4a4000
  | state=S schedstat=( 1234567890 0 1234 ) utm=100 stm=23 core=2 HZ=100
  | stack=0x7ff0000000-0x7ff0002000 stackSize=8192KB
  | held mutexes=
  at java.lang.Thread.sleep(Native method)
  at com.example.app.MainActivity.onCreate(MainActivity.java:42) # 阻塞位置
  at android.app.Activity.performCreate(Activity.java:8000)
  ...

Android 15的AMS优化

1. 启动性能优化

Android 15对Activity启动流程进行了多项优化:

  • 并行化Intent解析: Intent解析与进程创建并行执行,减少等待时间
  • 预测性进程预创建: 根据用户使用习惯,提前预创建进程
  • 减少Binder调用次数: 合并多个小的Binder调用为批量调用
java 复制代码
// Android 15新增: 批量启动多个Activity
public int startActivities(IApplicationThread caller, String callingPackage,
        Intent[] intents, String[] resolvedTypes, IBinder resultTo,
        Bundle options, int userId) {
    // 批量处理,减少Binder往返次数
    for (int i = 0; i < intents.length; i++) {
        // ...
    }
}

2. 内存管理优化

  • Smart LMK: 结合机器学习预测应用使用频率,优先保留高频应用
  • 进程冻结(Process Freezing): 后台进程冻结而非杀掉,恢复更快
  • Compaction优化: 内存压缩技术,减少物理内存占用

3. 后台限制增强

  • 更严格的后台Service限制: 后台Service启动超时从200秒降低到100秒
  • JobScheduler优先: 推荐使用JobScheduler替代后台Service
  • 前台Service通知: 前台Service必须显示持久通知

常见问题(FAQ)

Q1: AMS和ATMS有什么区别?

A: Android 10之前只有AMS,负责所有应用管理。Android 10重构后:

  • ATMS: 管理Activity任务、栈、生命周期
  • AMS: 管理进程、Service、Broadcast、OOM Adj

两者通过ActivityManagerInternalActivityTaskManagerInternal接口通信。

Q2: 为什么Home键不会触发onDestroy()?

A: 按Home键只是让Activity进入后台(onPause → onStop),进程和Activity实例仍保留在内存中,以便快速恢复。只有内存不足或主动finish()才会触发onDestroy()。

Q3: singleTask和singleInstance有什么区别?

A:

  • singleTask: 全局唯一,但可以和其他Activity共享一个Task
  • singleInstance : 全局唯一,且独占一个Task,该Task中只有这一个Activity

Q4: 为什么后台进程会被杀掉?

A: Android通过LMK机制管理内存,当内存不足时,会根据OOM Adj值杀掉低优先级进程。缓存进程(adj=900-999)最容易被杀,前台进程(adj=0)几乎不会被杀。

Q5: 如何避免ANR?

A:

  • ✅ 耗时操作放到子线程(网络请求、数据库查询、文件IO)
  • ✅ BroadcastReceiver的onReceive()不要超过10秒
  • ✅ 使用Handler、AsyncTask、WorkManager处理异步任务
  • ✅ 避免在主线程做复杂计算

Q6: 如何监控应用的adj值?

bash 复制代码
# 查看当前adj值
adb shell cat /proc/$(adb shell pidof com.example.app | tr -d '\r')/oom_score_adj

# 持续监控adj变化
adb shell "while true; do cat /proc/\$(pidof com.example.app)/oom_score_adj; sleep 1; done"

Q7: Activity启动为什么要经过这么多步骤?

A: Activity启动涉及多个进程协作:

  • Launcher进程: 发起启动请求
  • SystemServer进程: ATMS处理Intent、AMS创建进程
  • Zygote进程: fork新进程
  • 应用进程: 初始化Activity

这样设计是为了:

  • ✅ 安全隔离(权限检查)
  • ✅ 进程复用(已有进程直接启动)
  • ✅ 资源管理(统一管理生命周期)

实战:分析Activity启动性能

使用Systrace分析

bash 复制代码
# 1. 启动Systrace追踪
adb shell am start -W -n com.example.app/.MainActivity --start-profiler

# 2. 捕获启动trace
python systrace.py -o trace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res -t 10

# 3. 在Chrome中打开trace.html,查找关键阶段:
# - ActivityManager: startActivityAsUser
# - Zygote: fork进程
# - ActivityThread: handleLaunchActivity
# - Activity: onCreate/onStart/onResume

查看启动时间

bash 复制代码
# 启动Activity并测量时间
adb shell am start -W -n com.example.app/.MainActivity

# 输出:
# Starting: Intent { cmp=com.example.app/.MainActivity }
# Status: ok
# LaunchState: COLD  # COLD(冷启动)/WARM(温启动)/HOT(热启动)
# Activity: com.example.app/.MainActivity
# TotalTime: 432   # 总启动时间(ms)
# WaitTime: 445    # 包含系统开销的时间(ms)
# Complete

优化建议

  1. 减少onCreate()耗时:

    • 延迟初始化(Lazy Initialization)
    • 异步加载资源
    • 避免同步网络请求
  2. 优化Application.onCreate():

    • 第三方SDK初始化放到子线程
    • 使用ContentProvider懒加载
  3. 减少布局层级:

    • 使用ConstraintLayout
    • 避免过深的嵌套
  4. 启用硬件加速:

    xml 复制代码
    <application
        android:hardwareAccelerated="true">
    </application>

总结

本文深度剖析了AMS和ATMS的核心机制:

核心要点回顾

  1. AMS与ATMS分工:

    • ATMS负责Activity任务管理(启动、栈、生命周期)
    • AMS负责进程管理(创建、优先级、回收)
  2. Activity启动流程:

    • 应用进程(Launcher) → ATMS → AMS → Zygote → 新应用进程
    • 涉及Binder IPC、Socket通信、进程fork
  3. 生命周期管理:

    • onCreate → onStart → onResume → onPause → onStop → onDestroy
    • 配置变更默认会重建Activity,可通过configChanges避免
  4. 进程优先级(OOM Adj):

    • 前台进程(adj=0)最高,缓存进程(adj=900-999)最低
    • 动态调整,影响CPU资源和内存回收
  5. Low Memory Killer:

    • 内存不足时根据adj值杀进程
    • lmkd守护进程+PSI(压力检测)
  6. 任务栈管理:

    • Task是Activity的栈结构
    • 4种启动模式: standard/singleTop/singleTask/singleInstance
  7. ANR机制:

    • Input事件5秒、Broadcast 10秒、Service 20秒超时触发
    • 主线程不要做耗时操作

参考资料

  1. Android官方文档 - 进程和应用生命周期
  2. AOSP 15.0源码 - ActivityManagerService.java
  3. AOSP 15.0源码 - ActivityTaskManagerService.java
  4. Android Developers Blog - 进程管理优化

系列文章


本文基于Android 15 (API Level 35)源码分析,不同厂商的定制ROM可能存在差异。 欢迎来我中的个人主页找到更多有用的知识和有趣的产品

相关推荐
赏金术士3 小时前
Kotlin ViewModel
android·kotlin
vistaup4 小时前
kotlin 二维码实现高斯模糊
android·kotlin
愈努力俞幸运5 小时前
function calling与mcp
android·数据库·redis
阿巴斯甜6 小时前
LeakCanary
android
阿巴斯甜6 小时前
compose
android
阿巴斯甜6 小时前
Glide
android
-SOLO-6 小时前
使用Perfetto debug trace查看超时slice
android
阿巴斯甜6 小时前
Retrofit
android
阿巴斯甜6 小时前
OkHttp
android
阿巴斯甜7 小时前
Flow
android