首页
社区
课程
招聘
玩转Android10源码开发定制(十)增加获取当前运行最顶层的Activity命令
发表于: 2021-1-5 10:38 10843

玩转Android10源码开发定制(十)增加获取当前运行最顶层的Activity命令

2021-1-5 10:38
10843

在 Android 开发中,由于某些需求常常需要获取当前顶层的 Activity 信息。比如 App 中获取顶层 Activity 界面信息来判断某一个 app 是否在前台运行、统计某一个 app 的使用时长、更有恶意程序通过监听界面伪造 app 进行盗号以及欺诈、自动化开发中通过顶层 Activity 进行页面元素定位点击(比如基于辅助功自动化、uiautomator 自动化)等等操作。 在逆向工程中,获取当前运行 app 运行顶层 activity 也比较常用。通过顶层 Activity 可以快速定位界面中的功能在哪一个页面。

在 Android app 开发中,获取顶层 Activity 有以下方式:

首先需要在 Androidmanifest 中添加权限

代码如下:

在AndroidManifest文件中添加权限:

启动授权页面,需要用户授权app获取应用使用情况统计权限。跳转授权页面参考:

获取顶层 activity 参考代码:

除了 app 中使用代码获取顶层 Activity,也可以通过 adb 命令获取当前顶层的 Activity 信息,比如 windows 系统下 Android 10 手机可以用如下 adb 命令:

由于 ActivityManager->getRunningTasks 获取顶层 Activity 比较准确一些,以下将采用 ActivityManager->getRunningTasks 方式来进行研究实现。

ActivityManager源码路径位于:

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

ActivityManager 中 getRunningTask 调用如下:

由以上代码分析可知,最终调用的是 ActivityTaskManager.getService().getTasks。接下来分析 ActivityTaskManager 中的调用情况。

ActivityTaskManager 源码路径:

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

ActivityTaskManager 中 getService 实现如下:

ActivityTaskManager.getService().getTasks 调用最终变成了 IActivityTaskManager.getTasks。在安卓源码中没有找到 IActivityTaskManager.java 文件,只找到 IActivityTaskManager.aidl 文件,说明 IActivityTaskManager.getTasks 调用最终转化了 binder 的进程间调用。安卓中 aidl 是用于 binder 通信定义服务器和客户端通信接口的一种描述语言,源码编译的时候会将 aidl 文件转化为 java 文件。

IActivityTaskManager.aidl 文件路径如下:

frameworks/base/core/java/android/app/IActivityTaskManager.aidl

在源码中搜索关键字“extends IActivityTaskManager"找到 ActivityTaskManagerService 文件使用了。那么说明 ActivityTaskManagerService 最终实现了 getTasks 的函数功能。以下追踪 ActivityTaskManagerService 中的调用情况:

ActivityTaskManagerService 代码路径:

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

ActivityTaskManagerService 中 getTasks 代码如下:

通过以上分析,已经知道系统如何实现 getRunningTask 函数功能的流程。借鉴 getRunningTask 实现,要增加一个获取顶层 Activity 的接口,只需要在 IActivityTaskManager.aidl 中增加一个接口,仿照 ActivityTaskManagerService 中 getTasks 的实现方式即可。

ActivityManager getRunningTasks大概的一个调用流程总结如下,图中省略了许多binder交互的细节:

以上工作做好之后,我们就可以通过如下代码调用获取顶层 activity 了。代码如下:

源码根目录执行编译:

source build/envsetup.sh</br>
breakfast oneplus3</br>
brunch oneplus3 </br>

刷机测试效果:

 
<uses-permission  android:name = "android.permission.GET_TASKS"/>
<uses-permission  android:name = "android.permission.GET_TASKS"/>
ActivityManager mAm = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
String activity_name = mAm.getRunningTasks(1).get(0).topActivity.getClassName();
ActivityManager mAm = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
String activity_name = mAm.getRunningTasks(1).get(0).topActivity.getClassName();
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
context.startActivity(intent);
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
context.startActivity(intent);
public static getTopActivity()
{
  long endTime = System.currentTimeMillis();
  long beginTime = endTime - 10000;
  UsageStatsManager sUsageStatsManager =null;
  if (sUsageStatsManager == null) {
  sUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
  }
   String result = "";
   UsageEvents.Event event = new UsageEvents.Event();
   UsageEvents usageEvents = sUsageStatsManager.queryEvents(beginT ime, endTime);
  while (usageEvents.hasNextEvent()) {
     usageEvents.getNextEvent(event);
  if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
   result = event.getPackageName()+"/"+event.getClassName();
    }
  }
  if (!android.text.TextUtils.isEmpty(result)) {
  return result;
  }
  }
  return "";
}
public static getTopActivity()
{
  long endTime = System.currentTimeMillis();
  long beginTime = endTime - 10000;
  UsageStatsManager sUsageStatsManager =null;
  if (sUsageStatsManager == null) {
  sUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
  }
   String result = "";
   UsageEvents.Event event = new UsageEvents.Event();
   UsageEvents usageEvents = sUsageStatsManager.queryEvents(beginT ime, endTime);
  while (usageEvents.hasNextEvent()) {
     usageEvents.getNextEvent(event);
  if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
   result = event.getPackageName()+"/"+event.getClassName();
    }
  }
  if (!android.text.TextUtils.isEmpty(result)) {
  return result;
  }
  }
  return "";
}
C:\Users\Qiang>adb shell dumpsys activity |findstr "mResume"
mResumedActivity: ActivityRecord{12f93fd u0 com.sohu.inputmethod.sogou/.SogouIMEHomeActivity t50}
C:\Users\Qiang>adb shell dumpsys activity |findstr "mResume"
mResumedActivity: ActivityRecord{12f93fd u0 com.sohu.inputmethod.sogou/.SogouIMEHomeActivity t50}
 
// getRunningTasks 方法实现
// 最终调用 getTaskService().getTasks
public List<RunningTaskInfo> getRunningTasks(int maxNum) throws SecurityException {
   try {
       return getTaskService().getTasks(maxNum);
   } catch (RemoteException e) {
         throw e.rethrowFromSystemServer();
    }
}
 
# getTaskService 方法实现
private static IActivityTaskManager getTaskService() {
return ActivityTaskManager.getService();
}
// getRunningTasks 方法实现
// 最终调用 getTaskService().getTasks
public List<RunningTaskInfo> getRunningTasks(int maxNum) throws SecurityException {
   try {
       return getTaskService().getTasks(maxNum);
   } catch (RemoteException e) {
         throw e.rethrowFromSystemServer();
    }
}
 
# getTaskService 方法实现
private static IActivityTaskManager getTaskService() {
return ActivityTaskManager.getService();
}
 
 
//getService 实现代码
public static IActivityTaskManager getService() {
   return IActivityTaskManagerSingleton.get();
}
 
//IActivityTaskManagerSingleton 初始化代码
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 实现代码
public static IActivityTaskManager getService() {
   return IActivityTaskManagerSingleton.get();
}
 
//IActivityTaskManagerSingleton 初始化代码
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);
}
};
 
 
 
 
//getTasks 实现代码,调用了 getFilteredTasks
@Override
public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
     return getFilteredTasks(maxNum, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED);
}
 
// getFilteredTasks 实现代码
@Override
public List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,@WindowConfiguration.ActivityType int ignoreActivityType,@WindowConfiguration.WindowingMode int ignoreWindowingMode) {
  final int callingUid = Binder.getCallingUid();
  final int callingPid = Binder.getCallingPid();
  final boolean crossUser = isCrossUserAllowed(callingPid, callingUid);
  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);
  mRootActivityContainer.getRunningTasks(maxNum, list, ignoreActivityType,
ignoreWindowingMode, callingUid, allowed, crossUser, callingProfileIds);
}
  return list;
}
//getTasks 实现代码,调用了 getFilteredTasks
@Override
public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
     return getFilteredTasks(maxNum, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED);
}
 
// getFilteredTasks 实现代码
@Override
public List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,@WindowConfiguration.ActivityType int ignoreActivityType,@WindowConfiguration.WindowingMode int ignoreWindowingMode) {
  final int callingUid = Binder.getCallingUid();
  final int callingPid = Binder.getCallingPid();
  final boolean crossUser = isCrossUserAllowed(callingPid, callingUid);
  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);
  mRootActivityContainer.getRunningTasks(maxNum, list, ignoreActivityType,
ignoreWindowingMode, callingUid, allowed, crossUser, callingProfileIds);
}
  return list;
}
 
 
///ADD START
String getTopActivity();
///ADD END
///ADD START

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-4-12 22:05 被蟑螂一号编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (1)
雪    币: 29177
活跃值: (63586)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
2
外链的图片失效了,能否重新上传一下?
2022-1-4 15:12
0
游客
登录 | 注册 方可回帖
返回
//