Android 进程保活系列:(一)利用 Activity 提升权限

最近公司有进程保活方面的业务需求,所以就趁着闲暇时间研究了相关的技术方案,并且亲身验证它们的可行性,接下来我会用几篇文章详细介绍。

之前就有人爆出手机 QQ 长久存活的秘诀,那就是 监听用户的解锁屏操作,在锁屏的时候启动一个像素的透明窗口的 Activity,在解锁的时候把 Activity 销毁。 不得不佩服鹅厂的程序猿,竟然能想出这么棒的方案!管你 Android 怎么升级,该方案真的是屡试不爽!用户无感知,目的达到了,两全其美的事情。

首先验证一下:在锁屏状态下 cmd 输入

adb shell dumpsys activity activities

我们来看一下 dump 的输出:最顶层的 Task 的信息,包名:com.tencent.reading,我看了一下应用列表,它是「天天快报」,果然是腾讯家的。

dump 输出

我们看到 OffActicity 就是顶层的 Activity,怀着好奇心找到了源码所在的目录,参考相关代码,自己写了一个 demo。

具体实现分两步:

  1. 创建一个透明的 Activity
  2. 监听用户解锁屏操作
第一步:创建一个透明的 Activity

1. 在 onCreate 方法中设置 window 的属性

Window window = getWindow();
window.setGravity(Gravity.TOP | Gravity.LEFT);
LayoutParams attributes = window.getAttributes();
attributes.x = 0;
attributes.y = 0;
attributes.height = 1;
attributes.width = 1;
window.setAttributes(attributes);

2. 在 Manifest 中设置一些属性,包括排除在最近任务列表外、透明主题、启动模式等

<activity
    android:name="com.silence.keeplive.onepx.OnePxActivity"    
    android:excludeFromRecents="true"
    android:exported="false"
    android:finishOnTaskLaunch="false"
    android:launchMode="singleInstance"
    android:process=":main"
    android:theme="@android:style/Theme.Translucent"    
    android:configChanges="keyboardHidden|orientation|screenSize" />

3. 处理触摸和销毁事件
因为 Activity 是在锁屏的时候启动的,所以在用户点亮屏幕后,它是绝对不能存在的。我们要在 Activity 的生命周期里做些处理。为了稳妥起见,对 Activity 的触摸事件我们也要处理,直接销毁 Activity 就可以了。

@Override
protected void onResume() {    
  super.onResume();    
  if (isScreenOn()) {       
      finishSelf();    
  }
}

@Override
protected void onDestroy() {    
  super.onDestroy();    
  if (instance != null && instance.get() == this) {        
    instance = null;   
  }
}

public void finishSelf() {    
  if (!isFinishing()) {        
    finish();    
  }  
}

private boolean isScreenOn() {    
    PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);        
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {            
        return powerManager.isInteractive();        
    } else {            
        return powerManager.isScreenOn();        
     }    
 }
第二步:监听用户解锁屏操作

实现该功能要注册三个广播:

<action android:name="android.intent.action.USER_PRESENT"/>
<action android:name="android.intent.action.SCREEN_ON"/>
<action android:name="android.intent.action.SCREEN_OFF"/>

但是这里有一个问题,USER_PRESENT 可以静态注册,其余两个只能通过动态注册才能收到广播。我们索性把这三个广播都动态和静态注册一次,反正不会有什么坏处。然后接收到开关屏广播事件,对 Activity 做处理。

if ("android.intent.action.SCREEN_OFF".equals(action)) {    
    Log.i(TAG, "锁屏开启一像素");
    CheckTopTask.setForeground(context);    
    mHandler.postDelayed(mCheckTopTask, 3000);
} else if ("android.intent.action.USER_PRESENT".equals(action) || "android.intent.action.SCREEN_ON".equals(action)) {   
    Log.i(TAG, "开屏关闭一像素");    
    OnePxActivity onePxActivity = OnePxActivity.instance != null ? OnePxActivity.instance.get() : null;   
    if (onePxActivity != null) {        
        onePxActivity.finishSelf();   
    }    
    mHandler.removeCallbacks(mCheckTopTask);
}

这里有一个很鸡贼的地方,既然锁屏时已经启动了透明 Activity,为什么还要再三秒后还要执行一个任务?因为担心其他应用也采用同样的方案,把它的 Activity 盖在我们的上面。这个任务就是在三秒后检测当前 Activity 是否在前台,如果不在就再次启动,获得前台的焦点。我看腾讯就是这么搞的,大写的「服」!

最后实现的功能是 Activity 为我们占据前台,保证进程不被杀死,后台的 Service 在辛勤工作,目的达到了,so happy ~~

项目地址:AndroidKeepPractive

参考链接:

【腾讯Bugly干货分享】Android 进程保活招式大全

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,861评论 25 708
  • 本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-androi...
    eddy_wiki阅读 3,297评论 0 20
  • 如何进行进程保活,首先我们应该先分析一下进程被杀死的原因开始 Android进程被杀死的场景分析: 从 Andro...
    如颖随行日记阅读 4,943评论 2 4
  • 为了面试,为了高工资,废话不多说,不定期更新。 1. Activity正常和异常情况下的生命周期分析。 Activ...
    24K男阅读 845评论 0 0
  • 小品里的大娘说:没了就真的没了……泪水夺眶而出,我想我的外婆,想到外公走了以后的这一年多时间,外婆一个人在那...
    flying毛毛阅读 374评论 1 3