Android 14 彻底终结大厂流氓应用?

hi 大家好,我是 DHL。大厂程序员,就职于美团、快手、小米。公众号:ByteCode,分享技术干货和编程知识点

在某些大厂内部通常都会有一个神秘的团队,他们的工作内容就是专门研究系统,而的事情就是如何让自家应用在后台存活的更久,达到永生的目的。

其中有个别公司,甚者利用公开漏洞,达到远程操控用户手机的目的,做更多他们想做的事,可以随意获取用户的隐私,而且一旦安装,普通用户很难删除,之前写了一些揭露他们的文章,但是现在已经被全部删除了,就连评论区抨击他们的内容也全都被删除了。

而 Android 14 的出现,可以说是暂时性的彻底终结了这些流氓软件,想在后台通过保活的方式,让应用在后台达到永生的目的基本不可能了。

为什么这是暂时性的呢,因为没有完美的系统,新的系统虽然修复了公开漏洞,终结了现有的保活的方式,但是新系统可能存在新的漏洞,还是会给某些大厂可乘之机。

我们一起来看一下 Android 工程副总裁 Dave Burke 都介绍 Andorid 14 在性能、隐私、安全性方面做了那些改进,这篇文章是对之前的文章 适配 Android 14,你的应用受影响了吗Android 14 新增权限 的补充。

  • 冻结缓存应用,增强杀进程能力
  • 应用启动更快
  • 减少内存占用
  • 屏幕截图检查
  • 显示全屏系统通知
  • 精确闹钟权限
  • 提供了对照片和视频的部分访问权限
  • 最小 targetSdkVersion 限制
  • 返回手势

本文只会介绍我认为 Android 14 上最大的变化,关于 Android 14 的所有变更,可以前往查看变更developer.android.com/about/versi...

冻结缓存应用,增强杀进程能力

在 Android 11 以上支持冻结已缓存的应用,当应用切换到后台并且没有其他活动时,系统会在一定时间内通过状态判断,是否冻结该应用,如果一个应用被冻结住了,将完全被 "暂停",不再消耗任何 CPU 资源,可以减少应用在后台消耗的 CPU 资源,从而达到节电的目的。

被冻结已缓存的应用并不会执行终止该应用,冻结的作用只是暂时挂起进程,消耗 CPU 的资源为 0,它有助于提高系统性能和稳定性,同时最大限度地节省设备的资源和电量的消耗,一旦应用再次切换到前台时,系统会将该应用的进程解冻,实现快速启动。

如果你的手机支持冻结已缓存的应用,在开发者选项里会显示 「暂停执行已缓存的应用」设置项。

冻结已缓存应用,在内核层面使用的是 cgroup v2 freezer,相对于使用信号 SIGSTOP 与 SIGCONT 实现的挂起与恢复,cgroup v2 freezer 无法被拦截,也就无法被开发者 Hook,从而彻底终结大厂想在这个基础上做一些事情。

当然 Google 也对 cgroup 进行了封装,提供了 Java API,在上层我们也可以调用对应的方法实现 CPU、内存资源的控制。

kotlin 复制代码
public static final native void setProcessFrozen(int pid, int uid, boolean frozen);
public static final native void enableFreezer(boolean enable);

经过测试 Android 14 相比于 Android 13,缓存进程的 CPU 使用量降低了高达 50%,因此,除了传统的 Android 应用生命周期 API,如前台服务、JobScheduler 或 WorkManager,后台工作将受到限制。

另外在 Android 14 上系统在杀进程之前,首先会将应用所有的进程进行 cgroup v2 freezer,被冻结的应用 cpu 资源占用为 0,然后在挨个杀掉进程,想通过进程互相拉取进程的方式,不断的想通过 fork 出子进程,达到应用永生的目的,在 Android 14 以上已经不可能了,这些黑科技都要告别历史的舞台了。

应用启动更快

在 Android 14 上对缓存应用进行优化,增加了缓存应用的最大数量的限制,从而减少了冷启动应用的次数。

而应用的最大缓存数量不是固定的,可以根据设备的内存容量进行调整,Android 测试团队在 8GB 设备上,发现冷启动应用的数量减少了 20%,而在 12GB 设备上减少了超过 30%,冷启动相对于热启动来说速度较慢,而且在电量消耗方面成本较高,这一工作有效地改善了电量使用和整体应用启动时间。

减少内存占用

代码大小是我们关注的关键指标之一,代码量越大虚拟内存占用越高,减少生成的代码大小,对内存(包括 RAM 和存储空间)的影响就越小。

在 Android 14 中,改进 Android 运行时(ART)对 Android 用户体验,ART 包含了优化措施,将代码大小平均减少了 9.3%,而不会影响性能。

屏幕截图检查

在 Android 14 中新增了一个特殊的 API,截取屏幕截图后会有个 ScreenCaptureCallback 的回调,当用户正在使用截取屏幕截图时,将会调用这些回调函数。

要使 API 正常工作,需要在 AndroidManifest 中添加 DETECT_SCREEN_CAPTURE 权限,然后在 onStart() 方法中注册回调,需要在 onStop() 中取消注册。

kotlin 复制代码
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
</manifest>


class MainActivity : Activity() {

    private val mainExecutor = MainEcxector()
    
    private val screenshotCallback = ScreenCaptureCallback {
        // A screenshot was taken
    }

    override fun onStart() {
        super.onStart()
        registerScreenCaptureCallback(mainExecutor, screenshotCallback)
    }

    override fun onStop() {
        super.onStop()
        unregisterScreenCaptureCallback(screenshotCallback)
    }
}

显示全屏系统通知

Android 11 引入了全屏通知,当全屏应用程序运行时,这些通知将在锁屏屏幕上显示,任何应用都可以在手机处于锁定状态时使用 Notification. Builder. setFullScreenIntent 发送全屏 Intent,不过需要在 AndroidManifest 中声明 USE_FULL_SCREEN_INTENT 权限,在应用安装时自动授予此权限。

从 Android 14 开始,使用此权限的应用仅限于提供通话和闹钟的应用。对于不适合此情况的任何应用,Google Play 商店会撤消其默认的 USE_FULL_SCREEN_INTENT 权限。

在用户更新到 Android 14 之前,在手机上已经安装的应用仍拥有此权限,但是用户可以开启和关闭此权限,所以您可以使用新 API NotificationManager.canUseFullScreenIntent 检查应用是否具有该权限。

如果想在 Android 14 上使用这个权限,我们可以提示用户手动打开授权,通过 Intent(ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT) 来跳转到设置界面。

kotlin 复制代码
if(NotificationManager.canUseFullScreenIntent()){
    startActivity(Intent(ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT))
}

精确闹钟权限

在 Andorid 12 之前我们可以直接调用 setAlarmClock()setExact() setExactAndAllowWhileIdle() 等等方法设置精确闹钟时间,

但是在 Android 12 上 Google 引入了一个新的权限 SCHEDULE_EXACT_ALARM,如果想调用 setAlarmClock()setExact() setExactAndAllowWhileIdle() 等等方法设置精确闹钟时间, 需要在 manifest 中申明 android.permission.SCHEDULE_EXACT_ALARM 权限。

所以运行在 Android 12 ~ Android 13 系统上,我们只需要声明一下权限就可以使用了,但是从 Android 14 开始 SCHEDULE_EXACT_ALARM 权限默认被禁止使用了。

如果你还想在 Andorid 14 以上使用精准闹钟的 API,我们可以提示用户手动打开授权,通过 Intent (ACTION_REQUEST_SCHEDULE_EXACT_ALARM) 来跳转到设置界面,代码如下。

kotlin 复制代码
val alarmManager: AlarmManager = context.getSystemService<AlarmManager>()!!
when {
   // If permission is granted, proceed with scheduling exact alarms.
   alarmManager.canScheduleExactAlarms() -> {
       alarmManager.setExact(...)
   }
   else -> {
       // Ask users to go to exact alarm page in system settings.
       startActivity(Intent(ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
   }
}

提供了对照片和视频的部分访问权限

这个限制和 iOS 相似,Android 14 提供了对照片和视频的部分访问权限。当您访问媒体数据时,用户将看到一个对话框,提示用户授予对所有媒体的访问、或者授予单个照片/视频的访问权限,该新功能将适用于 Android 14 上所有应用程序,无论其 targetSdkVersion 是多少。

在 Android 13 上已经引入了单独的照片访问和视频访问权限,但是在 Android 14 上新增了新的权限 READ_MEDIA_VISUAL_USER_SELECTED

xml 复制代码
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />

    <!-- Devices running Android 13 (API level 33) or higher -->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

    <!-- To handle the reselection within the app on Android 14 -->
    <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

</manifest>

如果没有声明新的权限,当应用程序进入后台或用户终止应用程序时,单独的照片访问和视频访问权限将立即撤销,不会保存 READ_MEDIA_IMAGESREAD_MEDIA_VIDEO 权限的状态,每次都需要检查。

最小 targetSdkVersion 限制

Android 14 当中有一个比较大的变化就是,无法安装 targetSdk <= 23 的应用程序 (Android 6.0),不要将它与 minSdk 混淆。

在 Android 开发中有两个比较重要的版本号:

  • compileSdkVersion :用于编译当前项目的 Android 系统版本
  • targetSdkVersion :App 已经适配好的系统版本,系统会根据这个版本号,来决定是否可以使用新的特性

这个最小 targetSdkVersion 限制,主要是出于安全考虑,在 Android 6.0 中引入了运行时权限机制,App 想要使用一些敏感权限时,必须先弹窗询问用户,用户点击允许之后才能使用相应的权限。

但是一些 App 为了利用权限方便获取到用户的信息,通过不去升级 targetSdk 的版本号的方式,在安装过程中获得所有权限,以最低成本的方式,绕过运行时权限机制。

如果之前已经安装了的 App,就算升级到 Android 14 也会去保留,系统不能代表用户去删除某个应用,其实我在想,为什么不针对这些已经安装好的低版本的 App,Google 给出一些警告提示,让用户可以感知到呢

返回手势

在 Android 13 的时候,Google 已经预示我们在下一个版本中,返回手势将会有一些更新,并以预览屏幕的形式呈现动画,效果如下图所示。

我们来演示一下使用后退导航的动画。

在 Android 14 增加了在 App 中创建过渡动画的功能,比如在 OnBackPressedCallback 接口中添加了一个方法 handleonbackprogress() ,这个方法在返回手势执行过程中被调用,我们可以在这个方法中增加一些过渡动画。

OnBackPressedCallback 接口中还提供了两个方法 handleOnBackPressed()handleOnBackCancelled() 分别在动画完成和取消动画时调用,我们来看看在代码中如何使用。

kotlin 复制代码
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        val box = findViewById<View>(R.id.box)
        val screenWidth = 
            Resources.getSystem().displayMetrics.widthPixels
        val maxXShift = (screenWidth / 20)

        val callback = object : OnBackPressedCallback(
            enabled = true
        ) {

            override fun handleOnBackProgressed(
                backEvent: BackEvent
            ) {
                when (backEvent.swipeEdge) {
                    BackEvent.EDGE_LEFT ->
                        box.translationX = backEvent.progress *     
                            maxXShift
                    BackEvent.EDGE_RIGHT ->
                        box.translationX = -(backEvent.progress * 
                            maxXShift)
                }
                box.scaleX = 1F - (0.1F * backEvent.progress)
                box.scaleY = 1F - (0.1F * backEvent.progress)
            }

            override fun handleOnBackPressed() {
                // Back Gesture competed
            }

            
            override fun handleOnBackCancelled() {
                // Back Gesture cancelled 
                // Reset animation objects to initial state
            }
        }
        this.onBackPressedDispatcher.addCallback(callback)
    }
}

API 被废弃

在 Android 中使用 overidePendingTransition () 方法实现进入和退出动画,但是在 Android 14 上提供了新的 overrideActivityTransition () 方法,而 overidePendingTransition () 方法已被标记为弃用。

kotlin 复制代码
// New API
overrideActivityTransition(
    enterAnim = R.anim.open_trans,
    exitAnim = R.anim.exit_trans,
    backgroundColor = R.color.bgr_color
)

// deprecated
overridePendingTransition(R.anim.open_trans, R.anim.exit_trans)

全文到这里就结束了,感谢你的阅读,坚持原创不易,欢迎在看、点赞、分享给身边的小伙伴,我会持续分享原创干货!!!


我开了一个云同步编译工具(SyncKit),主要用于本地写代码,同步到远程设备,在远程设备上进行编译,最后将编译的结果同步到本地,代码已经上传到 Github,欢迎前往仓库 hi-dhl/SyncKit 查看。


Hi 大家好,我是 DHL,就职于美团、快手、小米。公众号:ByteCode ,分享有用、有趣的硬核原创内容,Kotlin、Jetpack、性能优化、系统源码、算法及数据结构、动画、大厂面经,真诚推荐你关注我。


最新文章

开源新项目

  • 云同步编译工具(SyncKit),本地写代码,远程编译,欢迎前去查看 SyncKit

  • KtKit 小巧而实用,用 Kotlin 语言编写的工具库,欢迎前去查看 KtKit

  • 最全、最新的 AndroidX Jetpack 相关组件的实战项目以及相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,欢迎前去查看 AndroidX-Jetpack-Practice

  • LeetCode / 剑指 offer,包含多种解题思路、时间复杂度、空间复杂度分析,在线阅读

相关推荐
Yawesh_best7 分钟前
MySQL(5)【数据类型 —— 字符串类型】
android·mysql·adb
王二端茶倒水1 小时前
大龄程序员兼职跑外卖第五周之亲身感悟
前端·后端·程序员
曾经的三心草3 小时前
Mysql之约束与事件
android·数据库·mysql·事件·约束
Goboy4 小时前
工欲善其事,必先利其器;小白入门Hadoop必备过程
后端·程序员
zxg_神说要有光5 小时前
自由职业第二年,我忘记了为什么出发
前端·javascript·程序员
陈随易6 小时前
农村程序员-关于小孩教育的思考
前端·后端·程序员
guoruijun_2012_46 小时前
fastadmin多个表crud连表操作步骤
android·java·开发语言
Winston Wood6 小时前
一文了解Android中的AudioFlinger
android·音频
B.-8 小时前
Flutter 应用在真机上调试的流程
android·flutter·ios·xcode·android-studio
有趣的杰克8 小时前
Flutter【04】高性能表单架构设计
android·flutter·dart