前言
在 Android 开发中,由于某些需求常常需要获取当前顶层的 Activity 信息。比如 App 中获取顶层 Activity 界面信息来判断某一个 app 是否在前台运行、统计某一个 app 的使用时长、更有恶意程序通过监听界面伪造 app 进行盗号以及欺诈、自动化开发中通过顶层 Activity 进行页面元素定位点击(比如基于辅助功自动化、uiautomator 自动化)等等操作。 在逆向工程中,获取当前运行 app 运行顶层 activity 也比较常用。通过顶层 Activity 可以快速定位界面中的功能在哪一个页面。
一、获取当前运行的顶层 Activity的几种方式
1、调用ActivityManager的getRunningTasks方法
1)在AndroidManifest文件中添加权限:
<uses-permission android:name = "android.permission.GET_TASKS"/>
2)获取顶层 activity 参考代码:
private String getTopActivityByActivityManager() {
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> listTask = activityManager.getRunningTasks(0);
String activityName = "";
if (listTask != null && !listTask.isEmpty()) {
ActivityManager.RunningTaskInfo runningTaskInfo = listTask.get(1);
activityName = runningTaskInfo.topActivity.getClassName();
}
return activityName;
}
2、调用UsageStatsManager的queryEvents方法:
1)在AndroidManifest文件中添加权限:
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
2)需要启动授权页面,让用户授权app获取应用使用情况统计权限。:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
context.startActivity(intent);
3)获取顶层 activity的参考代码:
public String getTopActivityByUsageStatsManager() {
long endTime = System.currentTimeMillis();
long beginTime = endTime - 10000;
UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
String activityInfo = "";
UsageEvents.Event event = new UsageEvents.Event();
UsageEvents usageEvents = usageStatsManager.queryEvents(beginTime, endTime);
while (usageEvents.hasNextEvent()) {
usageEvents.getNextEvent(event);
if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
activityInfo = event.getPackageName() + "/" + event.getClassName();
}
}
return activityInfo;
}
3、使用adb命令
1)输入dumpsys指令
adb shell "dumpsys activity | grep "ResumedActivity:"
2)得到的结果如下所示:
ResumedActivity: ActivityRecord{17ea57d u10 com.example.appcenter/.activity.MainActivity t1000085}
二、ActivityManager的getRunningTasks方法源码分析
1、Android12系统源码中,页面信息ActivityRecord、页面栈Task、页面栈管理者ActivityStarter、ActivityStartController
1、ActivityManager的getRunningTasks方法如下所示:
frameworks/base/core/java/android/app/ActivityManager.java
@SystemService(Context.ACTIVITY_SERVICE)
public class ActivityManager {
...代码省略...
public List<RunningTaskInfo> getRunningTasks(int maxNum)
throws SecurityException {
return ActivityTaskManager.getInstance().getTasks(maxNum);
}
...代码省略...
}
getRunningTasks方法内部直接调用了getTasks方法。
2、ActivityTaskManager的getTasks方法如下所示:
frameworks/base/core/java/android/app/ActivityTaskManager.java
@TestApi
@SystemService(Context.ACTIVITY_TASK_SERVICE)
public class ActivityTaskManager {
...代码省略...
public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
return getTasks(maxNum, false /* filterForVisibleRecents */);
}
public List<ActivityManager.RunningTaskInfo> getTasks(
int maxNum, boolean filterOnlyVisibleRecents) {
return getTasks(maxNum, filterOnlyVisibleRecents, false /* keepIntentExtra */);
}
public List<ActivityManager.RunningTaskInfo> getTasks(
int maxNum, boolean filterOnlyVisibleRecents, boolean keepIntentExtra) {
try {
return getService().getTasks(maxNum, filterOnlyVisibleRecents, keepIntentExtra);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
...代码省略...
}
getTasks(int maxNum)方法首先会调用getTasks(int maxNum, boolean filterOnlyVisibleRecents)方法,然后再调用getTasks( int maxNum, boolean filterOnlyVisibleRecents, boolean keepIntentExtra)方法,该方法会调用getService()方法获取IActivityTaskManager实例对象并调用该对象的getTasks方法。
3、ActivityTaskManager的getService方法如下所示:
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
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);
}
};
getService方法会返回一个IActivityTaskManager类型的单例对象。
4、在Android12源码中并不存在IActivityTaskManager.java这样一个文件,只能找到 IActivityTaskManager.aidl文件:
frameworks/base/core/java/android/app/IActivityTaskManager.aidl
interface IActivityTaskManager{
...代码省略...
List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, boolean filterOnlyVisibleRecents,boolean keepIntentExtra);
...代码省略...
}
我们知道源码编译的时候会将aidl文件转化为 java 文件,IActivityTaskManager的getTasks方法的调用最终是通过binder来实现跨进程通信的。而IActivityTaskManager.aidl中getTasks方法的具体实现类,其实是ActivityTaskManagerService。
5、ActivityTaskManagerService的getTasks方法如下所示:
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
...代码省略...
RootWindowContainer mRootWindowContainer;
...代码省略...
@Override
public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum,
boolean filterOnlyVisibleRecents, boolean keepIntentExtra) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
int flags = filterOnlyVisibleRecents ? RunningTasks.FLAG_FILTER_ONLY_VISIBLE_RECENTS : 0;
flags |= (keepIntentExtra ? RunningTasks.FLAG_KEEP_INTENT_EXTRA : 0);
final boolean crossUser = isCrossUserAllowed(callingPid, callingUid);
flags |= (crossUser ? RunningTasks.FLAG_CROSS_USERS : 0);
final int[] profileIds = getUserManager().getProfileIds(
UserHandle.getUserId(callingUid), true);
ArraySet<Integer> callingProfileIds = new ArraySet<>();
for (int i = 0; i < profileIds.length; i++) {
callingProfileIds.add(profileIds[i]);
}
ArrayList<ActivityManager.RunningTaskInfo> list = new ArrayList<>();
synchronized (mGlobalLock) {
if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum);
final boolean allowed = isGetTasksAllowed("getTasks", callingPid, callingUid);
flags |= (allowed ? RunningTasks.FLAG_ALLOWED : 0);
mRootWindowContainer.getRunningTasks(
maxNum, list, flags, callingUid, callingProfileIds);
}
return list;
}
...代码省略...
}
ActivityTaskManagerService的getTasks在进行一系列判断之后,会调用RootWindowContainer的getRunningTasks方法。
6、RootWindowContainer的getRunningTasks方法如下所示:
class RootWindowContainer extends WindowContainer<DisplayContent>
implements DisplayManager.DisplayListener {
...代码省略...
ActivityTaskSupervisor mTaskSupervisor;
...代码省略...
void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list,
int flags, int callingUid, ArraySet<Integer> profileIds) {
mTaskSupervisor.getRunningTasks().getTasks(maxNum, list, flags, this, callingUid,
profileIds);
...代码省略...
}
该方法内部直接调用了ActivityTaskSupervisor的getRunningTasks方法获取RunningTasks实例对象,然后调用RunningTasks的getTasks方法。
7、先来看下ActivityTaskSupervisor的getRunningTasks方法:
public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
...代码省略...
private RunningTasks mRunningTasks;
...代码省略...
RunningTasks getRunningTasks() {
return mRunningTasks;
}
...代码省略...
}
8、再来看下RunningTasks的getTasks方法:
class RunningTasks {
...代码省略...
void getTasks(int maxNum, List<RunningTaskInfo> list, int flags,
RootWindowContainer root, int callingUid, ArraySet<Integer> profileIds) {
// Return early if there are no tasks to fetch
if (maxNum <= 0) {
return;
}
// Gather all of the tasks across all of the tasks, and add them to the sorted set
mTmpSortedSet.clear();
mCallingUid = callingUid;
mUserId = UserHandle.getUserId(callingUid);
mCrossUser = (flags & FLAG_CROSS_USERS) == FLAG_CROSS_USERS;
mProfileIds = profileIds;
mAllowed = (flags & FLAG_ALLOWED) == FLAG_ALLOWED;
mFilterOnlyVisibleRecents =
(flags & FLAG_FILTER_ONLY_VISIBLE_RECENTS) == FLAG_FILTER_ONLY_VISIBLE_RECENTS;
mTopDisplayFocusRootTask = root.getTopDisplayFocusedRootTask();
mRecentTasks = root.mService.getRecentTasks();
mKeepIntentExtra = (flags & FLAG_KEEP_INTENT_EXTRA) == FLAG_KEEP_INTENT_EXTRA;
if (mTopDisplayFocusRootTask.getAdjacentTaskFragment() != null) {
mTopDisplayAdjacentTask = mTopDisplayFocusRootTask.getAdjacentTaskFragment().asTask();
} else {
mTopDisplayAdjacentTask = null;
}
final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
PooledLambda.__(Task.class));
root.forAllLeafTasks(c, false);
c.recycle();
// Take the first {@param maxNum} tasks and create running task infos for them
final Iterator<Task> iter = mTmpSortedSet.iterator();
while (iter.hasNext()) {
if (maxNum == 0) {
break;
}
final Task task = iter.next();
list.add(createRunningTaskInfo(task));
maxNum--;
}
}
...代码省略...
private RunningTaskInfo createRunningTaskInfo(Task task) {
final RunningTaskInfo rti = new RunningTaskInfo();
task.fillTaskInfo(rti, !mKeepIntentExtra);
// Fill in some deprecated values
rti.id = rti.taskId;
return rti;
}
...代码省略...
}