Android AMS(ActivityManagerService) 原理

什么是 AMS

AMS(ActivityManagerService)主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作。通常情况下我们不会把 AMS 单独的拆分出来讲解,因为 AMS 需要通过 PMS(PackageManagerService)获取信息。

下面的节点在讲解 AMS 时会穿插 PMS(PackageManagerService) 相关的内容,关于 PMS 的原理具体可以查看 Android PMS 原理,这里不会过多赘述。

没有 PMS 和 AMS 会发生什么

Android PMS 原理 可以了解到,PMS 在手机开机的时候会运行解析所有 apk 的 AndroidManifest.xml,将每个 apk 信息存到内存中,并提供查询接口,可以认为 PMS 充当着包信息缓存的作用

而 AMS 其中一个职责是管理调度 Activity,需要启动某个 Activity 时都会先找 PMS 查询要跳转的 Activity 信息再处理后续一系列的操作

我们可以思考一个问题:为什么 Android 要提供 AMS 和 PMS?如果没有 AMS 和 PMS 会发生什么?

假设现在要启动某个进程的 Activity,简单梳理下会经历五个步骤:

  • 遍历 data/app 目录获取到该目录下所有 apk 文件

  • 解压所有 apk 获取 AndroidManifest.xml

  • dom 解析 AndroidManifest.xml 解析出 Activity 标签生成对应数据类存到内存

  • 从内存查找到要跳转的 Activity 信息,获取到 Activity 全类名,反射构建对象

  • 依次执行 Activity 的生命周期

如果每次进程调度都要这么处理,可以想象效率是很低的。

为了能快速的定位到要跳转的 Activity,前面的三个步骤将会交由 PMS,PMS 提前在开机启动时先解析完成存到内存,这样当 AMS 需要跳转某个 Activity 时,直接从 PMS 存储到内存的数据去提取信息,就能更快的完成操作

AMS 从 PMS 拿到创建 Activity 的信息创建出来后,就会需要考虑 Activity 的生命周期,总不能 Activity 一退出就销毁,所以 AMS 就需要管理创建出来的 Activity 的生命周期。每个应用每个进程都有自己的 ActivityThread,所以 AMS 也需要一个缓存中心管理 Activity 的生命周期,就是由 ActivityThread 充当这个角色(更具体说是 ActivityThread 下的 mActivities 变量)

ActivityThread.java

final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
	...
	Activity activity = null;
	try {
		// 创建 Activity
		java.lang.ClassLoader cl = appContext.getClassLoader();
		activity = mInstrumentation.newActivity(
			cl, component.getClassName(), r.intent);
		...
	} catch (Exception e) {
		...
	}
	...
	try {
		...
		if (activity != null) {
			...
 			r.activity = activity; // ActivityClientRecord 记录 Activity
		}
		mActivities.put(r.token, r); // 将创建的 Activity 存储到 map
	} catch (SuperNotCalledException e) {
		...
	}
	...
	return activity;
}

public static final class ActivityClientRecord {
	...
	Activity activity; // 持有 Activity
	...
}

可以看到 ActivityThread 的源码中有一个 mActivities 的成员变量,ActivityClientRecord 是持有 Activity 的引用。在后续的 performXxxActivity() 等处理生命周期的方法中都会用 mActivities 管理。

App 的启动过程

在 Android 无论是启动一个应用还是启动应用内的 Activity,都是调用的 startActivity() 方法。总体会经历三个步骤:

  • 告知 AMS 要启动一个指定的 Activity

  • AMS 从 PMS 查找要启动的 Activity 信息

  • 启动指定 Activity

接下来我们具体通过源码(API 28)分析 startActivity() 的整个过程。

Activity.java

@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 {
        // Note we want to go through this call for compatibility with
        // applications that may have overridden the method.
        startActivityForResult(intent, -1);
    }
}

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
           	@Nullable Bundle options) {
	if (mParent == null) {
		...
		// 委托给 Instrumentation
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        ....
	}
	...
}

当我们调用 startActivity() 时,最终都会调用到 startActivityForResult(),应用上层对接 Android 核心服务会委托给 Instrumentation。Instrumentation 是专门负责 Application 和 Activity 的相关所有活动处理,就是和 AMS 通信会委托给 Instrumentation

Instrumentation.java

public ActivityResult execStartActivity(
          Context who, IBinder contextThread, IBinder token, Activity target,
          Intent intent, int requestCode, Bundle options) {
	...
	try {
		...
		// 找到 AMS 告知要启动 Activity
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);	
        ...            	
	}
	...
}

Instrumentation 会告知 AMS 要启动一个 Activity。

需要注意的是,在这里不同系统版本的源码处理也不一样,在 9.0 之前是使用 AMS,9.0 之后是使用 ATMS(ActivityTaskManagerService):

public ActivityResult execStartActivity(
          Context who, IBinder contextThread, IBinder token, Activity target,
          Intent intent, int requestCode, Bundle options) {
	...
	try {
		...
		// 9.0 之后会通过 ATMS 告知要启动 Activity
        int result = ActivityTaskManager.getService().startActivity(whoThread,
        		 who.getBasePackageName(), who.getAttributionTag(), intent,
        		 intent.resolveTypeIfNeeded(tho.getContentResolver()), token,
        		 target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);	
        ...            	
	}
	...
}

目前源码是以 API 28 分析,所以我们回到 API 28 的源码分析。

ActivityManager.getService().startActivity() 这句代码可以拆分成两部分:ActivityManager.getService() 和 startActivity()。

我们先看 ActivityManager.getService():

ActivityManager.java

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
            	// 通过 ServiceManager 获取 AMS 服务
            	// IActivityManager 是 binder 代理
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am; 
            }
        };

public abstract class Singleton<T> {
	private T mInstance;

	protected abstract T create();

	public final T get() {
		synchronized (this) {
			if (mInstance == null) {
				mInstance = create();
			}
			return mInstance;
		}
	}
}

ActivityManager.getService() 会获取 IActivityManager,它是一个 binder 代理对象。从代码可以看出,当使用 ActivityManager.getService() 对象调用方法时,实际上已经在做跨进程通信,由 binder 代理对象和 AMS 通信,通信所在的进程是 system_server。同时这里也是一个很好的 hook 点

到这一步为止已经完成了告知 AMS 要启动 Activity 的第一个步骤。

我们继续分析源码。

ActivityManagerService.java

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    // 有多个 startActivityAsUser() 重载方法,为了方便查看省略了多个方法调用  
    return startActivityAsUser(...); 
}

public final int startActivityAsUser(...) {
	...
	// mActivityStartController.obtainStarter 返回 ActivityStarter 对象
    return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setMayWait(userId)
            .execute();
}

使用 AMS 调用 startActivity() 方法,主要是找到 mActivityStartController.obtainStarter() 获取到 ActivityStarter 对象,很明显使用了构建者模式配置相关参数,重点在 execute() 方法。

按照我们一开始设定的步骤,第二步是 AMS 要找到 PMS 获取跳转 Activity 相关的信息,那么 AMS 是怎么和 PMS 通信的?

ActivityStarter.java

int execute() {
	try {
		if (mRequest.mayWait) {
			return startActivityMayWait(...);
		} else {
			return startActivity(...);
		}
	} finally {
		...
	}
}

private int startActivityMayWait(...) {
	...
	// AMS 和 PMS 产生关联,从 PMS 获取信息
	ResolveInfo rInfo = mSupervisor.resolveIntent(...);
	...
	return res;
}

ActivityStackSupervisor.java

ResolveInfo resolveIntent(...) {
	// mService 是 AMS
	synchronized (mService) {
		...
		try {
			// mService.getPackageManagerInternalLocked() 返回 PackageManagerInternalImpl
			return mService.getPackageManagerInternalLocked().resolveIntent(...);
		} finally {
			....
		}
	}
	...
}

ActivityManagerService.java

PackageManagerInternal getPackageManagerInternalLocked() {
    if (mPackageManagerInt == null) {
        mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
    }
    return mPackageManagerInt;
}

PackageManagerService.java

// PackageManagerInternalImpl 的作用是,它作为内部类能拿到外部类的引用
// 所以可以充当 AMS 和 PMS 的桥梁,让 AMS 能获取到 PMS
private class PackageManagerInternalImpl extends PackageManagerInternal {
	...
	
    @Override
    public ResolveInfo resolveIntent(Intent intent, String resolvedType,
            int flags, int userId, boolean resolveForStart, int filterCallingUid) {
        // 作为桥梁外部调用相关方法时都转发给 PMS
        // ResolveInfo 持有 ActivityInfo、serviceInfo 等信息
        return resolveIntentInternal(
                intent, resolvedType, flags, userId, resolveForStart, filterCallingUid);
    }
      
    ...
}

ResolveInfo.java

public class ResolveInfo implements Parcelable {
	public ActivityInfo activityInfo;
	public ServiceInfo serviceInfo;
	public ProviderInfo providerInfo;
	...
}

AMS 和 PMS 通信获取的是 ResolveInfo 包装对象,它可以存储 ActivityInfo、ServiceInfo 等信息,不直接返回 ActivityInfo 的原因应该是要启动 Service 等其他组件时可以复用同一套逻辑,因为获取的方式基本是相同的

AMS 和 PMS 的通信也不是直接通信,而是通过 PMS 的 PackageManagerInternalImpl 内部类作为桥梁,内部类持有外部类的引用,所以 PackageManagerInternalImpl 可以直接访问 PMS。这样的做法既能实现功能,又能降低 AMS 和 PMS 之间的耦合,限制公开的 api 访问。

到这里已经完成第二步从 PMS 获取到要启动的 Activity 信息,就可以开始第三步启动 Activity。

ActivityStarter.java

private int startActivityMayWait(...) {
	...
	// AMS 和 PMS 产生关联,从 PMS 获取信息
	ResolveInfo rInfo = mSupervisor.resolveIntent(...);
	...
	// 从封装的 ResolveInfo 获取到要跳转的 ActivityInfo 信息
	ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
	...
	// 开始启动 Activity
	int res = startActivity(...);
	...
	return res;
}

private int startActivity(...) {
	int result = START_CANCELED;
	try {
		...
        result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                 startFlags, doResume, options, inTask, outActivity);
	} finally {
		...	
	}
	...
}

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
         IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
         int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
         ActivityRecord[] outActivity) {
	...
	mSuperVisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
			mOptions);
	...
}

ActivityStackSupervisor.java

boolean resumeFocusedStackTopActivityLocked(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
   if (!readyToResume()) {
        return false;
    }

    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }

    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    if (r == null || !r.isState(RESUMED)) {
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
    } else if (r.isState(RESUMED)) {
        // Kick off any lingering app transitions form the MoveTaskToFront operation.
        mFocusedStack.executeAppTransition(targetOptions);
    }

    return false;		
}

ActivityStack.java

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
	...
	try {
		...
		result = resumeTopActivityInnerLocked(prev, options);
		...
	}
}

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
	...
	mStackSupervisor.startSpecificActivityLocked(next, true, false);
	...
}

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
	...
	// 先判断要启动的 Activity 进程是否已经存在
	if (app != null && app.thread != null) {
		try {
			...
			// 进程已经存在,启动 Activity
			realStartActivityLocked(r, app, andResume, checkConfig);
			return;
		} catch (RemoteException e) {
			...
		}
	}
	
	// 如果进程不存在,AMS 通知 zygote 启动进程,最终反射调用 ActivityThread.main()
	// 有多个 startProcessLocked() 重载方法,为了方便查看省略了多个方法调用
    mService.startProcessLocked(...);	
}

ActivityManagerService.java

private boolean startProcessLocked(...) {
	...
	// 其中一个 startProcessLocked() 提供了要启动的进程为 ActivityThread
	final String entryPoint = "android.app.ActivityThread";
	... // 省略其他 startProcessLocked() 调用
	if (mConstants.FLAG_PROCESS_START_ASYNC) {
		...
		// 传入要启动的进程
		final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint, ...)
	}
	...
}

private ProcessStartResult startProcess(String entryPoint, ...) {
	try {
		...
		startResult = Process.start(entryPoint, ...);
		...
	} finally {
		...
	}
}

Process.java

public static final ProcessStartResult start(final String processClass, ...) {
	return zygoteProcess.start(processClass, ...);
}

按上面源码的分析,启动 Activity 前其实还需要再细分拆成两个处理:

  • 要启动的 Activity 所在进程如果没有创建,AMS 会通知 Zygote fork 进程,最终会反射调用 ActivityThread 的 main() 方法,再走后续的 Activity 创建及后续生命周期流程

  • 进程已经创建,realStartActivityLocked() 创建 Activity 及后续生命周期流程

Activity 的启动涉及到了生命周期,AMS 既然是管理调度 Activity 的服务,那就需要能和启动的 Activity 有所关联。AMS 是用什么方式管理 Activity 的生命周期的?

ActivityThread.java

final ApplicationThread mAppThread = new ApplicationThread();

public static void main(String[] args) {
	...
	ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    ...
}

private void attach(boolean system, long startSeq) {
	...
	if (!system) {
		...
		final IActivityManager mgr = ActivityManager.getService();
		try {
			// 将 ApplicationThread 给到 AMS 作为句柄管理
			mgr.attachApplication(mAppThread, startSeq);
		} catch (RemoteException ex) {
			...
		}
		...
	}
	...
}

private class ApplicationThread extends IApplicationThread.Stub {
	// AMS 下发管理四大组件,将处理转发给变量名为 mH 的 Handler
	...
	
	@Override
	public void scheduleTransaction(ClientTransaction transaction) {
		ActivityThread.this.scheduleTransaction(transaction);
	}
}

class H extends Handler {
	// Activity 生命周期等消息的处理
	...
}

在 ActivityThread 的 main() 方法,可以从源码看到创建了一个 ApplicationThread,然后将这个对象给到了 AMS,Activity 生命周期其实就是使用的 ApplicationThread 作为句柄交给 AMS,AMS 就可以通过这个句柄下发管理 Activity 的生命周期;同样的 AMS 也通过 ApplicationThread 管理四大组件和进程的其他处理,在 ApplicationThread 由 Handler 转发消息驱动处理

启动 Activity 之前,还需要先启动创建 Application。AMS 获取 ApplicationThread 调用了 attachApplication():

ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
                
    @Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            ...
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            ...
        }
    }

    @GuardedBy("this")
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
		...
		if (app.isolatedEntryPoint != null) {
			...
		} else if (app.instr != null) {
		   // 通过 ApplicationThread 和 App 进程通信
           thread.bindApplication(processName, appInfo, providers,
                   app.instr.mClass,
                   profilerInfo, app.instr.mArguments,
                   app.instr.mWatcher,
                   app.instr.mUiAutomationConnection, testMode,
                   mBinderTransactionTrackingEnabled, enableTrackAllocation,
                   isRestrictedBackupMode || !normalMode, app.persistent,
                   new Configuration(getGlobalConfiguration()), app.compat,
                   getCommonServicesLocked(app.isolated),
                   mCoreSettingsObserver.getCoreSettingsLocked(),
                   buildSerial, isAutofillCompatEnabled);			
		} else {
			...	
		}
		...

        if (normalMode) {
            try {
            	// 创建完 Application 后走 Activity 生命周期流程
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }
	}    
}

ActivityThread.java

private class ApplicationThread extends IApplicationThread.Stub {

    public final void bindApplication(...) {
		...
		// 在 ActivityThread 也是获取的 AMS 数据创建 application
		AppBindData data = new AppBindData();
        data.processName = processName;
        data.appInfo = appInfo;
        data.providers = providers;
        data.instrumentationName = instrumentationName;
        data.instrumentationArgs = instrumentationArgs;
        data.instrumentationWatcher = instrumentationWatcher;
        data.instrumentationUiAutomationConnection = instrumentationUiConnection;
        data.debugMode = debugMode;
        data.enableBinderTracking = enableBinderTracking;
        data.trackAllocation = trackAllocation;
        data.restrictedBackupMode = isRestrictedBackupMode;
        data.persistent = persistent;
        data.config = config;
        data.compatInfo = compatInfo;
        data.initProfilerInfo = profilerInfo;
        data.buildSerial = buildSerial;
        data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
        sendMessage(H.BIND_APPLICATION, data); // 消息驱动发消息给到 Handler
	}
}
	
class H extends Handler {
	public static final int BIND_APPLICATION        = 110;
	...
	
	public void handleMessage(Message msg) {
		switch (mssg.what) {
			case BIND_APPLICATION:
			AppBindData data = (AppBindData) msg.obj;
			handleBindApplication(data);
			break;
			...
		}
	}	
}
	
private void handleBindApplication(AppBindData data) {
	...
	// 反射创建 Instrumentation 负责管理 application 和 activity 相关所有活动处理
	try {
		final ClassLoader cl = instrContext.getClassLoader();
		mInstrumentation = (Instrumentation)
			cl.loadClass(data.instrumentationName.getClassName()).newInstance();
	} catch (Exception e) {
		...
	}
	...
	try {
		// info 是 LoadedApk,反射创建 application 
		app = data.info.makeApplication(data.restrictedBackupMode, null);
		...
	}
	...
} 

public final class LoadedApk {

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
		...
		// 创建 application
		Application app = null;
		try {
			ClassLoader cl = getClassLoader();
			ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
			app = mActivityThread.mInstrumentation.newApplication(
				cl, appClass, appContext);
		} catch (Exception e) {
			...
		}
		...
		if (instrumentation != null) {
			try {
				// 调用 application.onCreate()
				instrumentation.callApplicationOnCreate(app);
			} catch (Exception e) {
				...	
			}
		}
		...
	}	
}

attachApplication() 实际上做了三件事情:

  • 创建 Instrumentation,负责管理 Application 和 Activity 相关所有活动处理

  • 创建 Application

  • 创建 Activity 开始走生命周期流程

在上面我们有提到,Activity 的创建和后续生命周期流程是从 realStartActivityLocked() 方法开始的。让我们继续分析 Activity 的创建过程。

ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    final ActivityStackSupervisor mStackSupervisor;    
        
    @Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            ...
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            ...
        }
    }

    @GuardedBy("this")
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
		...
		if (mStackSupervisor.attachApplicationLocked(app)) {
		}
		...
	}    
}

ActivityStackSupervisor.java

public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
        RecentTasks.Callbacks {
        
   	boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
		...
		if (realStartActivityLocked(activity, app, top == activity) {
		}
		...
	}	

    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
		...
		// app.thread 是 ApplicationThread
		// Create activity launch transaction.
		final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
			r.appToken);
        clientTransaction.addCallback(LaunchActivityItem.obtain(...));	
        
        final ActivityLifecycleItem lifecycleItem;
        if (andResume) {
			lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
		} else {
			lifecycleItem = PauseActivityItem.obtain();
		}  
		// 执行完 LaunchActivityItem 事务后要处在的生命周期状态   				
		clientTransaction.setLifecycleStateRequest(lifecycleItem);
		
		// mService 是 AMS
		// Schedule transaction.
		mService.getLifecycleManager().scheduleTransaction(clientTransaction);
		...
	}	
}

ClientTransaction 是客户端事务管理类,通过不同的状态 LaunchActivityItem、ResumeActivityItem、PauseActivityItem 等,分别代表不同的 Activity 生命周期,以状态的方式加以管理。

在上面有提到 AMS 管理 Activity 的生命周期是通过 ApplicationThread 句柄,在创建 ClientTransaction.obtain() 也能看到是传入了 ApplicationThread 下发的生命周期处理:

ClientTransaction.java

public class ClientTransaction implements Parcelable, ObjectPoolItem {
    private IApplicationThread mClient;

	// 记录事务结束后要处在的生命周期状态,后面会用到
    public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) {
        mLifecycleStateRequest = stateRequest;
    }

    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
    }

    public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
        ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
        if (instance == null) {
            instance = new ClientTransaction();
        }
        instance.mClient = client; // 存储的 ApplicationThread
        instance.mActivityToken = activityToken;

        return instance;
    }	
}

继续分析 mService.getLifecycleManager().scheduleTransaction(clientTransaction) 做了什么事情:

ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	
	ClientLifecycleManager getLifecycleManager() { return mLifecycleManager; }
}

class ClientLifecycleManager {
	
	void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
		final IApplicationThread client = transaction.getClient();
		transaction.schedule();
		...
	}
}

ClientTransaction.java

public class ClientTransaction implements Parcelable, ObjectPoolItem {
    private IApplicationThread mClient;

    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this); // 拿着 ApplicationThread 下发通知
    }	
}

ActivityThread.java

private class ApplicationThread extends IApplicationThread.Stub {
    @Override
    public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    	// 在 ActivityThread 是找不到 scheduleTransaction 方法的
    	// 而是在 ActivityThread 的父类 ClientTransactionHandler 调用
        ActivityThread.this.scheduleTransaction(transaction);
    }	
}

AMS 就是拿着 ApplicationThread 句柄告知 ActivityThread 要创建 Activity,在 ActivityThread 的源码中你会发现 ActivityThread.this.scheduleTransaction() 代码没有找到,实际上它是放在了 ActivityThread 继承的父类 ClientTransactionHandler。

ClientTransactionHandler.java

public abstract class ClientTransactionHandler {
	
	void scheduleTransaction(ClientTransaction transaction) {
		transaction.preExecute(this);
		// 通过 Handler 发了一条消息
		sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
	}
}

public final class ActivityThread extends ClientTransactionHandler {
	// TransactionExecutor的构造传入的 ActivityThread
    private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);	
	
	class H extends Handler {
		public static final int EXECUTE_TRANSACTION = 159;

		public void handleMessage(Message msg) {
			switch (msg.what) {
				case EXECUTE_TRANSACTION:
				final ClientTransaction transaction = (ClientTransaction) msg.obj;
				mTransactionExecutor.execute(transaction);
				break;
			}
		}
	}
}

TransactionExecutor.java

public class TransactionExecutor {
	// ActivityThread
	private ClientTransactionHandler mTransactionHandler;

    public TransactionExecutor(ClientTransactionHandler clientTransactionHandler) {
        mTransactionHandler = clientTransactionHandler;
    }
	
	public void execute(ClientTransaction transaction) {
		...
		
		executeCallbacks(transaction); 

        executeLifecycleState(transaction);
		...	
	}

    public void executeCallbacks(ClientTransaction transaction) {
    	final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
		...
		final int size = callbacks.size();
		for (int i = 0; i < size; ++i) {
			final ClientTransactionItem item = callbacks.get(i);
			...
			// 执行事务,这里是设置了 LaunchActivityItem
			item.execute(mTransactionHandler, token, mPendingActions);
			...
		}
	}

	private void executeLifecycleState(ClientTransaction transaction) {
		final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
		...
		// 执行完事务后处在的生命周期状态,这里是 ResumeActivityItem
		lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
	}
}

在 Handler 接收到消息后启动事务的处理,处理事物交由 TransactionExecutor 负责,主要看两个函数:

  • executeCallbacks():执行具体的事务,例如 LaunchActivityItem

  • executeLifecycleState():执行事务后要处在哪个状态,例如 ResumeActivityItem、PauseActivityItem

LaunchActivityItem.java

public class LaunchActivityItem extends ClientTransactionItem {
	
	@Override
	public void execute(ClientTransactionHandler client, IBinder token,
		PendingTransactionActions pendingActions) {
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client);
        // 最终到 ActivityThread 开始创建 Activity
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);		
	}
}

ActivityThread.java

public final class ActivityThread extends ClientTransactionHandler {
	
	@Override
	public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
		...
		final Activity a = performLaunchActivity(r, customIntent);
		...
	}

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
		...
		// 通过 Instrumentation 反射创建 Activity
		ContextImpl appContext = createBaseContextForActivity(r);
		Activity activity = null;
		try {
			ClassLoader cl = appContext.getClassLoader();
			activity = mInstrumentation.newActivity(
				cl, component.getClassName(), r.intent);
			...
		}
		...
		// 调用 Activity 生命周期 onCreate()
        if (r.isPersistable()) {
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
            mInstrumentation.callActivityOnCreate(activity, r.state);
        }		
	}
}

简单总结下 realStartActivityLocked() 做了什么事情:

创建了 ClientTransaction 处理生命周期的执行事务,可以认为它是 AMS 具体处理 Activity 生命周期的执行类。不同的生命周期用不同的状态表示, LaunchActivityItem 表示的 onCreate() 的生命周期,还有 ResumeActivityItem 表示的 onResume() 的生命周期,事务具体执行最终都会下发到对应的 ActivityLifecycleItem,由这些状态类执行回调 Activity 的生命周期

至此,App 的启动流程就分析到这里。

总结下整体 App 的启动过程:

  • 调用 startActivity() 时,实际会走到 Instrumentation,由它与 AMS 通信

  • Instrumentation 会找 ServiceManager 获取 AMS(实际是获取 binder 代理)调用 startActivity()。在 9.0 之前是获取 AMS,9.0 之后是获取 ATMS

  • AMS 找到 PMS 获取启动的 Activity 信息

  • 然后判断需要启动的 Activity 所在进程是否已存在,不存在 AMS 通过 socket 通知 Zygote fork 进程,然后反射调用 ActivityThread 的 main(),创建 Instrumentation、Application 和 Activity 以及走生命周期流程

  • 如果需要启动的 Activity 所在进程已经存在,创建 Activity 以及走生命周期流程

具体流程如下:

在这里插入图片描述

hook 启动未在 AndroidManifest.xml 注册的界面

有关 AMS 的源码已经分析完毕,那么知道 AMS 的源码有哪些应用场景呢?

我们经常会在业务中遇到一种场景,如果用户未登陆就跳转到登陆界面,已登陆就跳转到其他界面,所以也就会出现类似这种写法:

if (isLogin) {
	startActivity(new Intent(context, LoginActivity.class);
} else {
	startActivity(new Intent(context, OtherActivity.class);
}

当项目有大量的地方需要判断登陆再跳转界面,后续如果有业务改动,比如跳转的登陆界面修改,这种硬编码的方式侵入性高,要修改的范围很广,并不利于维护。

或许你会说:我用隐式意图在 AndroidManifest.xml 定义 action,然后用常量类提供 action 统一管理不就行了:

AndroidManifest.xml

<manifest>
	<application>
		<activity name="LoginActivity">
			<intent-filter>
				<action name="android.intent.action.login" />
			</intent-filter>
		</activity>	
	</application>
</manifest>

public class Constants {
	public static final String ACTION_LOGIN = "android.intent.action.login";
}

if (isLogin) {
	startActivity(new Intent(context, Constants.ACTION_LOGIN);
} else {
	startActivity(new Intent(context, OtherActivity.class);
}

那我再加一个条件:我想不在 AndroidManifest.xml 注册登陆界面想正常启动,能做到吗?

正常情况是不行的,但我们在熟悉了 AMS 和 PMS 的源码后,就能通过 hook 绕过系统检测正常启动一个 Activity。

hook 简单来说就是绕过系统处理,自己用不同的方式实现同样的效果,但这个过程还是要用到系统创建的一些信息帮助我们完成处理

但是要使用 hook 一般有三个前提条件

  • 找到合适的 hook 点:在 Java 中一般是静态成员变量或成员方法,非静态成员变量是不能 hook 的,因为会借助反射获取 hook 点

  • hook 的兼容性:hook 会借助系统源码的 api,但不同版本的源码会存在不同的 hook 点,hook 方式也不一样

  • 熟悉源码原理:保证系统流程正常情况能正确 hook 处理

根据一开始提到的每次跳转都要鉴权的案例,我们尝试用 hook 实现只在代码写具体业务跳转,自动完成没有登陆就跳转登陆界面,否则就跳转具体业务界面。demo 将在 API 28 的源码上实现。

要实现这个效果有两大难点:

  • 不在 AndroidManifest.xml 注册界面,怎么绕过检查?

  • 绕过检查后,又该怎么正常启动这个 Activity?

不在 AndroidManifest.xml 注册界面,在文章最开始有提到 AMS 的原理分析是离不开 PMS的,因为 AMS 在启动 Activity 过程中会找 PMS 拿 Activity 的信息,所以这个问题更具体说是如何绕过 PMS 的检查。

为了实现这个效果,hook 能做的就是将 startActivity() 拦截下来,替换掉携带着目标 Activity 的 Intent 信息,在原始数据保留的情况下增加额外的信息到 Intent。这样也就能在 PMS 的检查下流程正常执行。

那么合适的 hook 在哪里呢?Instrumentation 有一个和 AMS 通信的处理,我们要拿到 AMS 的 binder 代理,这里重新将源码贴出来:

ActivityManager.java

// 已经创建好的 IActivityManager,更具体说要拿到 mInstance,是一个很好的 hook 点
public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am; 
            }
        };

public abstract class Singleton<T> {
	private T mInstance;

	protected abstract T create();

	public final T get() {
		synchronized (this) {
			if (mInstance == null) {
				mInstance = create();
			}
			return mInstance;
		}
	}
}

hook 并不是完全要自己创建信息,而是要利用系统 api 或提前创建好的信息加以利用,mInstance 即 IActivityManager 是我们要用到的对象,要拦截它调用 startActivity() 时的处理,替换我们的 Intent,这需要用到动态代理。代码如下:

public class Hooker {

    public void hook() throws Exception {
        hookAms();
    }

    public void hookAms() throws Exception {
        if (proxyActivity == null) {
            throw new NullPointerException("proxyActivity is null");
        }

        Class ActivityManagerClz = Class.forName("android.app.ActivityManager");
        Field IActivityManagerSingletonField = ActivityManagerClz.getDeclaredField("IActivityManagerSingleton");
        IActivityManagerSingletonField.setAccessible(true);
        // 获取到 ActivityManager 的 IActivityManagerSingleton 内部静态成员变量
        Object IActivityManagerSingletonObj = IActivityManagerSingletonField.get(null);

        Class SingletonClz = Class.forName("android.util.Singleton");
        Field mInstanceField = SingletonClz.getDeclaredField("mInstance");
        mInstanceField.setAccessible(true);
        // 拿到 ActivityManagerService 的 binder 代理
        // 做这一步是为了绕过 AMS 的鉴权,因为要设置的 LoginActivity 也是没有在 AndroidManifest.xml 注册,也就是要绕过 PMS
        Object IActivityManagerObj = mInstanceField.get(IActivityManagerSingletonObj);

        Class IActivityManagerClz = Class.forName("android.app.IActivityManager");
        Object proxyIActivityManager = Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class[] {IActivityManagerClz}, new AmsInvocationHandler(IActivityManagerObj));
        // 将 IActivityManagerSingleton 的 mInstance 成员替换为我们自己的代理对象
        // 将 mInstance 的调用都跑我们的代理
        mInstanceField.set(IActivityManagerSingletonObj, proxyIActivityManager);
    }

    private class AmsInvocationHandler implements InvocationHandler {
        private final Object iActivityManagerObject;

        public AmsInvocationHandler(Object iActivityManagerObject) {
            this.iActivityManagerObject = iActivityManagerObject;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 系统使用 mInstance 的调用都会走到代理
            if ("startActivity".contains(method.getName())) {
                Intent intent = null;
                int index = 0;
                for (int i = 0; i < args.length; i++) {
                    Object arg = args[i];
                    if (arg instanceof Intent) {
                        intent = (Intent) args[i];
                        index = i;
                        break;
                    }
                }
                if (intent != null) {
                    Intent proxyIntent = new Intent();
                    ComponentName componentName = new ComponentName(context, proxyActivity);
                    proxyIntent.setComponent(componentName);
                    proxyIntent.putExtra("oldIntent", intent);
                    args[index] = proxyIntent; // 替换真实意图
                }
            }
            return method.invoke(iActivityManagerObject, args);
        }
    }
}

绕过 PMS 的问题已经解决,接下来是第二个问题:怎么正常启动 Activity?

Activity 的创建和生命周期流程都是在 Handler 消息驱动下完成的,定位到具体源码是 ActivityThread 的 mH 成员变量:

ActivityThread.java

final H mH = new H();

class H extends Handler {
	public static final int EXECUTE_TRANSACTION = 159;

	public void handleMessage(Message msg) {
		switch (msg.what) {
			case EXECUTE_TRANSACTION:
			final ClientTransaction transaction = (ClientTransaction) msg.obj;
			mTransactionExecutor.execute(transaction);
			break;
		}
	}
}

很遗憾的是,不能在 ActivityThread 将 handleMessage() 的消息拦截下来。

实际上 Handler 已经为我们提供了 hook 点:

Handler.java

final Callback mCallback;

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
        	// 如果 mCallback 不为空,先处理 mCallback 的 handleMessage()
        	// 如果 mCallback 的 handleMessage() 返回 false,调用兜底的 handleMessage()
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

可以设置我们自己的 mCallback,这样就能在兜底的 handleMessage() 之前,提前将消息拦截处理,需要拦截的消息返回 true 不再传递,否则返回 false 按正常走不影响启动流程。

完整代码如下:

public class Hooker {
    private final Context context;
    private Class<?> proxyActivity;

    public Hooker(@NonNull Context context) {
        this.context = context;
    }

    public void setProxyActivity(@NonNull Class<?> proxyActivity) {
        this.proxyActivity = proxyActivity;
    }

    public void hook() throws Exception {
        hookAms();
        hookSystemHandler();
    }

    public void hookAms() throws Exception {
        if (proxyActivity == null) {
            throw new NullPointerException("proxyActivity is null");
        }

        Class ActivityManagerClz = Class.forName("android.app.ActivityManager");
        Field IActivityManagerSingletonField = ActivityManagerClz.getDeclaredField("IActivityManagerSingleton");
        IActivityManagerSingletonField.setAccessible(true);
        // 获取到 ActivityManager 的 IActivityManagerSingleton 内部静态成员变量
        Object IActivityManagerSingletonObj = IActivityManagerSingletonField.get(null);

        Class SingletonClz = Class.forName("android.util.Singleton");
        Field mInstanceField = SingletonClz.getDeclaredField("mInstance");
        mInstanceField.setAccessible(true);
        // 拿到 ActivityManagerService 的 binder 代理
        // 做这一步是为了绕过 AMS 的鉴权,因为要设置的 LoginActivity 也是没有在 AndroidManifest.xml 注册,也就是要绕过 PMS
        Object IActivityManagerObj = mInstanceField.get(IActivityManagerSingletonObj);

        Class IActivityManagerClz = Class.forName("android.app.IActivityManager");
        Object proxyIActivityManager = Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class[] {IActivityManagerClz}, new AmsInvocationHandler(IActivityManagerObj));
        // 将 IActivityManagerSingleton 的 mInstance 成员替换为我们自己的代理对象
        // 将 mInstance 的调用都跑我们的代理
        mInstanceField.set(IActivityManagerSingletonObj, proxyIActivityManager);
    }

    public void hookSystemHandler() throws Exception {
        Class ActivityThreadClz = Class.forName("android.app.ActivityThread");
        Field field = ActivityThreadClz.getDeclaredField("sCurrentActivityThread");
        field.setAccessible(true);
        Object ActivityThreadObj = field.get(null);

        Field mHField = ActivityThreadClz.getDeclaredField("mH");
        mHField.setAccessible(true);
        Handler mHObj = (Handler) mHField.get(ActivityThreadObj);

        Field mCallbackField = Handler.class.getDeclaredField("mCallback");
        mCallbackField.setAccessible(true);
        ProxyHandlerCallback proxyCallback = new ProxyHandlerCallback();
        mCallbackField.set(mHObj, proxyCallback);
    }

    private class ProxyHandlerCallback implements Handler.Callback {
		public static final int EXECUTE_TRANSACTION = 159;
		
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == EXECUTE_TRANSACTION) {
                try {
                    Class<?> ClientTransactionClz = Class.forName("android.app.servertransaction.ClientTransaction");
                    if (!ClientTransactionClz.isInstance(msg.obj)) {
                        return false;
                    }

                    Class<?> LaunchActivityItemClz = Class.forName("android.app.servertransaction.LaunchActivityItem");

                    Field mActivityCallbacksField = ClientTransactionClz.getDeclaredField("mActivityCallbacks");
                    mActivityCallbacksField.setAccessible(true);
                    Object mActivityCallbacksObj = mActivityCallbacksField.get(msg.obj);
                    List list = (List) mActivityCallbacksObj;
                    if (list.size() == 0) {
                        return false;
                    }
                    
                    Object LaunchActivityItemObj = list.get(0);
                    if (!LaunchActivityItemClz.isInstance(LaunchActivityItemObj)) {
                        return false;
                    }

                    Field mIntentField = LaunchActivityItemClz.getDeclaredField("mIntent");
                    mIntentField.setAccessible(true);
                    Intent mIntent = (Intent) mIntentField.get(LaunchActivityItemObj);
                    Intent realIntent = mIntent.getParcelableExtra("oldIntent");
                    if (realIntent != null) {
                        SharedPreferences sp = context.getSharedPreferences("name", MODE_PRIVATE);
                        boolean isLogin = sp.getBoolean("isLogin", false);
                        if (isLogin) {
                            mIntent.setComponent(realIntent.getComponent());
                        } else {
                            ComponentName componentName = new ComponentName(context, LoginActivity.class);
                            mIntent.putExtra("extraIntent", realIntent.getComponent().getClassName()); // 提供给登陆界面登陆成功后跳转到哪个目标页面
                            mIntent.setComponent(componentName);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return false; // 返回 false 不影响系统的执行
        }
    }

    private class AmsInvocationHandler implements InvocationHandler {
        private final Object iActivityManagerObject;

        public AmsInvocationHandler(Object iActivityManagerObject) {
            this.iActivityManagerObject = iActivityManagerObject;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 系统使用 mInstance 的调用都会走到代理
            if ("startActivity".contains(method.getName())) {
                Intent intent = null;
                int index = 0;
                for (int i = 0; i < args.length; i++) {
                    Object arg = args[i];
                    if (arg instanceof Intent) {
                        intent = (Intent) args[i];
                        index = i;
                        break;
                    }
                }
                if (intent != null) {
                    Intent proxyIntent = new Intent();
                    ComponentName componentName = new ComponentName(context, proxyActivity);
                    proxyIntent.setComponent(componentName);
                    proxyIntent.putExtra("oldIntent", intent);
                    args[index] = proxyIntent; // 替换真实意图
                }
            }
            return method.invoke(iActivityManagerObject, args);
        }
    }
}

这样就能完成我们的效果了,写个 demo 测试下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.demo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Demo">
        <activity android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- 没有注册 LoginActivity -->
        <activity android:name=".Page1Activity" />
        <activity android:name=".Page2Activity" />
    </application>
</manifest>

public class MainActivity extends AppCompatActivity {
    private Hooker hooker;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        hooker = new Hooker(this);
    }

    public void logout(View view) {
        SharedPreferences sp = getSharedPreferences("name", MODE_PRIVATE);
        sp.edit().putBoolean("isLogin", false).apply();
    }

    public void startPage1(View view) {
        hooker.setProxyActivity(Page1Activity.class);
        try {
            hooker.hook();
        } catch (Exception e) {
            e.printStackTrace();
        }
        startActivity(new Intent(this, Page1Activity.class));
    }

    public void startPage2(View view) {
        hooker.setProxyActivity(Page2Activity.class);
        try {
            hooker.hook();
        } catch (Exception e) {
            e.printStackTrace();
        }
        startActivity(new Intent(this, Page2Activity.class));
    }
}

public class LoginActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
    }

    public void login(View view) throws ClassNotFoundException {
        SharedPreferences sp = getSharedPreferences("name", MODE_PRIVATE);
        sp.edit().putBoolean("isLogin", true).apply();

        String className = getIntent().getStringExtra("extraIntent");
        if (!TextUtils.isEmpty(className)) {
            startActivity(new Intent(this, Class.forName(className)));

            finish();
        }
    }
}

在这里插入图片描述

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 中,AMS(Activity Manager Service)负责管理 Activity 的生命周期。Activity 有四个状态:运行状态、暂停状态、停止状态和销毁状态。当一个 Activity 运行时,它可以被用户看到,并响应用户的交互;当它被暂停时,它被部分遮挡,但仍然在屏幕上存在;当它被停止时,它被完全遮挡,但其状态仍然保留在内存中;当它被销毁时,它被完全删除,其状态也从内存中释放。 Activity 生命周期管理的关键是回调方法。Android 系统提供了一组回调方法,使得开发者可以在 Activity 的不同状态下执行相应的操作。 以下是 Activity 生命周期的回调方法: 1. onCreate(): Activity 被创建时调用,通常用来完成界面的初始化和数据的加载。 2. onStart(): Activity 变为可见时调用,此时 Activity 进入运行状态。 3. onResume(): Activity 处于前台并处于运行状态时调用,此时 Activity 可以响应用户的交互。 4. onPause(): 当其他 Activity 显示在前台并且当前 Activity 处于可见状态时调用,此时 Activity 进入暂停状态。 5. onStop(): Activity 完全被遮挡时调用,此时 Activity 进入停止状态。 6. onRestart(): 当 Activity 从停止状态重新进入运行状态时调用。 7. onDestroy(): Activity 被销毁时调用,通常用来释放内存或资源。 开发者应根据自己的应用需求在这些回调方法中编写相应的业务逻辑,从而实现自己的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值