IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 保活之实现终极目标,应用永生 滴血重生术 -> 正文阅读

[移动开发]Android 保活之实现终极目标,应用永生 滴血重生术

先给大家看看保活效果,这是我新买的最新小米11手机 ,2022年2月刚更新了小米13系统 Android 12

小米miui13应用保活效果

取消所有权限+清除存储数据保活

安装后自启动并保活

目前可以实现Android 4-12:

  1. 拒绝应用强杀
  2. 安装静默自启动
  3. 不依赖任何Android权限

除此之外,经过测试 OPPO VIVO 华为 原生Android 手机都可以达到一样的效果

本App的安装包放在了最后,大家有兴趣可以下载研究

实现大体原理:

Android 保活之实现终极目标,应用永生滴血重生术

都2022年了,Android还有保活技术可以使用吗?

随着Android系统的持续升级和类似小米华为等厂商的持续迭代,不少开发者也是在保活技术上与厂商不停的斗智斗勇,也因此出现了很多保活技术和手段。

目前从网上可以找到的Android保活这块的技术主要有:

  1. 开启一个前台Service
  2. 引导用户设置白名单
  3. 引导用户使app成为某个系统服务,如:无障碍服务,动态壁纸服务,等。
  4. 一像素页面
  5. 无声音乐
  6. 接收系统广播唤醒
  7. JobService定时任务启动自己
  8. 双service守护,启动两个service相互 bind 启动,监听对方死亡拉起
  9. 在service的onstart方法里返回 STATR_STICK

但随着系统厂商的持续更新,在高版本Android这些方法已经不同程度的不管用了,特别是用户从任务栏划掉应用,或者点击强制停止杀死应用,可以说以上方法最终都逃不过被杀的命运。

但真的就没有扛得住点击强制杀死的保活方法了吗?答案是否定的

Android杀app最终执行的代码:

https://cs.android.com/android/platform/superproject/+/master:system/core/libprocessgroup/processgroup.cpp;l=345?q=KillProcessGroup

static int KillProcessGroup(uid_t uid, int initialPid, int signal, int retries,
                            int* max_processes) {
    //省略

    int retry = 40;
    int processes;
    while ((processes = DoKillProcessGroupOnce(cgroup, uid, initialPid, signal)) > 0) {
        if (max_processes != nullptr && processes > *max_processes) {
            *max_processes = processes;
        }
        LOG(VERBOSE) << "Killed " << processes << " processes for processgroup " << initialPid;
        if (retry > 0) {
            std::this_thread::sleep_for(5ms);
            --retry;
        } else {
            break;
        }
    }

    if (processes < 0) {
        PLOG(ERROR) << "Error encountered killing process cgroup uid " << uid << " pid "
                    << initialPid;
        return -1;
    }

    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

    // We only calculate the number of 'processes' when killing the processes.
    // In the retries == 0 case, we only kill the processes once and therefore
    // will not have waited then recalculated how many processes are remaining
    // after the first signals have been sent.
    // Logging anything regarding the number of 'processes' here does not make sense.

    if (processes == 0) {
        if (retries > 0) {
            LOG(INFO) << "Successfully killed process cgroup uid " << uid << " pid " << initialPid
                      << " in " << static_cast<int>(ms) << "ms";
        }

        int err = RemoveProcessGroup(cgroup, uid, initialPid, retries);

        if (isMemoryCgroupSupported() && UsePerAppMemcg()) {
            std::string memory_path;
            CgroupGetControllerPath("memory", &memory_path);
            memory_path += "/apps";
            if (RemoveProcessGroup(memory_path.c_str(), uid, initialPid, retries)) return -1;
        }

        return err;
    } else {
        if (retries > 0) {
            LOG(ERROR) << "Failed to kill process cgroup uid " << uid << " pid " << initialPid
                       << " in " << static_cast<int>(ms) << "ms, " << processes
                       << " processes remain";
        }
        return -1;
    }
}

int killProcessGroup(uid_t uid, int initialPid, int signal, int* max_processes) {
    return KillProcessGroup(uid, initialPid, signal, 40 /*retries*/, max_processes);
}

这里就是循环调用 DoKillProcessGroupOnce 循环杀进程,每次循环等待5毫秒,总共杀40次,也就是说 5*40 = 200 毫秒,而这200毫秒执行完之后,不管应用死没死就不管了,所以我们的app只要在这5毫秒成功启动一个新的进程,抗过去致命200毫秒之后,只要有一个进程存活,就能滴血重生。

梳理一下这个逻辑:

  1. app启动N多进程,我试了启动10个(最少需要两个)
  2. 发现被杀,开始快速启动进程
  3. 扛过200毫秒,剩余的进程负责重生任务
  4. 保活完成

发现被杀这一步我是借鉴别人的方案使用的文件锁感知,逻辑是:

  1. 进程A给文件F1加文件锁,进程B给文件F2加锁
  2. 进程A,B各创建一个文件,表示已经加锁完毕
  3. 进程A,B分别去判断对方这个文件存不存在,如果存在就证明对方加锁完毕了
  4. 进程 A尝试获取F2锁,进程B尝试获取F1锁,这样必形成死锁进入阻塞状态
  5. 由于文件锁在进程死亡时会释放,因此AB其中一个死亡,另一个死锁解开就可以进行感知了

快速启动进程大家可能首先想到的是启动一个Service,我试了下启动Service比较慢,网上使用binder缓存的方式我试了下其实效果也不太好,因此放弃了启动service的方式,而是使用外部调用ContentProvider的方式启动进程。

当然达到以上的效果绝不是上面说的那么简单,厂商之间还是有不少细节需要处理,后面继续写文分享。

下载资源:https://download.csdn.net/download/qq_27512671/82742972

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_27512671/article/details/123183052
联系作者:miqtdev@163.com

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 16:26:11  更:2022-03-03 16:29:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 17:10:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码