2024年最全实战|Android后台启动Activity实践之路续(1),测试面试宝典

最后送福利了,现在关注我可以获取包含源码解析,自定义View,动画实现,架构分享等。
内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿

录播视频图.png

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Android P版本的机型:

  • 通过 moveTaskToFront 方法将应用切换到前台,如果切换失败的话可以多尝试几次调用 moveTaskToFront 方法;

  • 小米机型可以通过Hook相关参数来后台启动Activity;

Android Q版本的机型:

  • 通过系统全屏通知的方式调起后台 Activity;

  • 在一些另作了限制的 ROM 上可能调起失败;

后来又想到如果能够拿到这些机型 ROM 的源码,那么通过阅读 startActivity 以及后台启动权限设置页面的源码,那么就有可能找到破解的方法。至于怎么获取 ROM 的源码,我这里有两种方式:

  • 如果手里有现成的机型,则可以直接将 /system/framework/ 中的内容通过 adb pull 命令拉下来,然后通过一些反编译工具可以查阅相关的源码;

  • 去相关厂商的官网下载对应机型的 ROM 包,通过工具将其解压转换,最终也可以拿到源码。

这篇文章主要是延续上篇文章的内容,介绍一下怎么拿到 ROM 包源码,并以小米某机型为例,找出它们针对后台启动权限所做的定制化。

获取ROM源码

=======

adb pull

========

我一开始也没想到原来不需要 root 权限即可从手机里 pull /system/framework/ 里的内容,方式也很简单,手机连接电脑后运行命令即可在当前路径下拿到 framework 文件夹内容:

$ adb pull /system/framework

这种方式做过 Android 开发的应该都知道,就不再多说了。不过需要注意的是在一些机器里 pull 下来的 framework 文件夹下的 jar 文件可能都是只有 1Kb 的大小,这种 jar 文件里不含有源代码,在 framework 下还有一些 odex 文件,需要将其转换成 dex 等格式才更好反编译,具体怎么转换的可以网上搜,貌似还有挺多教程的。

解压ROM

=====

首先去对应厂商的官网下载 ROM 包,以小米为例是在 MIUI下载 里下载,下载了目标 ROM.zip 后将其解压缩,我下载的是小米 Max3(Android 9) 的 ROM 包,解压后我们需要的有两个文件: system.new.dat.br 和 system.transfer.list。接下来分步骤看看怎么反编译出它的源码:

  1. 下载 ROM 制作工具: 下载地址,下载安装打开后,选择其 实用工具 栏,然后打开 new.dat编辑 功能,如下图:

实战|Android后台启动Activity实践之路续

  1. 按照下图的两个步骤转换。首先第一步选择 system.new.dat.br 文件转换,得到 .new.dat 后缀的 system.new.dat 文件;然后第二步选择这个 system.new.dat 文件转换,可能提示需要 .transfer.list 文件,直接选择上面的 system.transfer.list 文件即可,转换后会得到一个 img 后缀的文件,将其解压缩。

实战|Android后台启动Activity实践之路续

  1. 打开解压缩后的文件夹,进入 /system/framework/ 目录下,即可看到我们需要的 jar 文件们。

反编译ROM源码

========

这一步是要将上面得到的 jar 或者 dex 文件反编译得到源码,网上有很多介绍反编译的文章,也有很多工具比如说 apktool, dex2jar, jd-gui 等,这里介绍一个傻瓜式操作的工具——jadx,如果想要省事的话可以直接使用这个工具,它可以直接打开 jar, dex, apk 等后缀的文件,直接查看反编译后的源码,是不是很方便呢?

另外如果要使用 jd-gui 查看的话,网上有很多教程了,或者直接 --help 查看相关工具的 Usage。

后台启动权限做了什么?

===========

经过上面的步骤我们得到了 ROM 反编译后的源码,这一章开始进入具体的源码分析流程。从之前 实战|Android后台启动Activity实践之路 可以知道,当我们调用 startActivity 后,会来到 AMS 这一端,AMS 进行了一些处理后,会调用到 ActivityStarter.startActivity 方法,对这个流程有疑问的可以看看 Activity 的启动流程,可以参考 Android-Activity启动流程。查看反编译后的代码,发现里面调用了小米自定义的 Inject 类中的静态方法(在 services.jar 中):

private int startActivity(IApplicationThread paramIApplicationThread, Intent paramIntent1, …) {

// …

// 这个 i 在 AOSP 源码中原名叫 boolean abort

i = activityStackSupervisor.checkStartAnyActivityPermission(…) ^ true | this.mService.mIntentFirewall.checkStartActivity(…) ^ true;

paramInt1 = i;

if (i == 0) { // 表示 !abort

paramInt1 = i;

if (!ActivityTaskManagerServiceInjector.isAllowedStartActivity(this.mService, this.mSupervisor, paramIntent1, …))

paramInt1 = 1;

}

// 根据上面的bool值判断是否接着执行 startActivity 流程

// …

}

其实这样的 XXXInject 类在源码中还有很多,都是用来做一些自定义逻辑的,我们重点看下这个 ActivityTaskManagerServiceInjector.isAllowedStartActivity() 方法的逻辑:

static boolean isAllowedStartActivity(…, Intent paramIntent, …) {

StringBuilder stringBuilder;

// 1

if (UserHandle.getAppId(paramInt) == 1000 || (paramIntent.getMiuiFlags() & 0x2) != 0 || PendingIntentRecordInjector.containsPendingIntent(paramString) || PendingIntentRecordInjector.containsPendingIntent(paramActivityInfo.applicationInfo.packageName) || paramInt == mLastStartActivityUid || paramActivityTaskManagerService.isUidForeground(paramInt)) {

return true;

}

// 2

if (paramActivityTaskManagerService.mWindowManager.isKeyguardLocked() && paramActivityTaskManagerService.getAppOpsService().noteOperation(10020, paramInt, paramString) != 0) {

stringBuilder = new StringBuilder();

stringBuilder.append("MIUILOG- Permission Denied Activity KeyguardLocked: ");

// …

Slog.d(“ActivityTaskManagerServiceInjector”, stringBuilder.toString());

return false;

}

// …

// 3

if (stringBuilder.getAppOpsService().checkOperation(10021, paramInt, paramString) != 0) {

SparseArray sparseArray = ((ActivityTaskManagerService)stringBuilder).mProcessMap.getPidMap();

for (int i = sparseArray.size() - 1; i >= 0; i–) {

int j = sparseArray.keyAt(i);

WindowProcessController windowProcessController = (WindowProcessController)sparseArray.get(j);

if (windowProcessController != null && windowProcessController.mUid == paramInt && (windowProcessController.hasForegroundActivities() || (ExtraActivityManagerService.isProcessRecordVisible(j, paramInt) && windowProcessController.hasActivities() && paramInt == activityRecord.launchedFromUid))) {

mLastStartActivityUid = paramActivityInfo.applicationInfo.uid;

return true;

}

}

stringBuilder.getAppOpsService().noteOperation(10021, paramInt, paramString);

stringBuilder = new StringBuilder();

stringBuilder.append("MIUILOG- Permission Denied Activity : ");

最后

那我们该怎么做才能做到年薪60万+呢,对于程序员来说,只有不断学习,不断提升自己的实力。我之前有篇文章提到过,感兴趣的可以看看,到底要学习哪些知识才能达到年薪60万+。

通过职友集数据可以查看,以北京 Android 相关岗位为例,其中 【20k-30k】 薪酬的 Android 工程师,占到了整体从业者的 30.8%!

北京 Android 工程师「工资收入水平 」

今天重点内容是怎么去学,怎么提高自己的技术。

1.合理安排时间

2.找对好的系统的学习资料

3.有老师带,可以随时解决问题

4.有明确的学习路线

当然图中有什么需要补充的或者是需要改善的,可以在评论区写下来,一起交流学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

gLc-1715897003492)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值