1. 目的
基于《软件绿色联盟应用体验标准》中autostart资源的定义,进autostart频繁次数的测试apk。旨在触发手机中异常功耗管控机制。
本方案需要2个APP协同工作,具体工作原理:
- APP1 作用:负责自杀和被冷启动
- APP2 作用:负责定时复活APP1,触发冷启动检测
红线标准:半小时内的频繁冷启动次数检测,阈值20次以上。
2. 测试步骤
H手机和T手机、其他手机进行安装该apk.
所有手机都需要设置应用为白名单。
2.1 手机白名单设置方法:
手机管家->应用启动设置:允许自启动、允许关联启动、允许后台启动
T手机:手机管家->自启动管理:允许自启动
2.2 运行本apk
只需运行APP2,作用:负责定时复活APP1,触发冷启动检测
保持APP2前台显示。至少等待400秒以上。观察通知栏是否有高耗电提醒
红线标准:半小时内的频繁冷启动次数检测,阈值20次以上。
2.3 日志查看
使用命令模拟拔掉USB的技巧,先发如下命令,再插拔一下USB数据线即可
adb shell dumpsys battery unplug
日志关键字:APwTrigger|APwLevelAnalysis|APwActAnalysis|startDeaderApp startForegroundService count=|AutoStartDeaderService onDestroy|AutoStartDeaderService onCreate|AutoStartDeaderService killCount
2022-05-18 17:29:51.633 2614-2978/com.huawei.iaware D/APwTrigger: start bg process:com.sufadi.blockautostart_deader reason:service pid:14604 uid:10160 count:19
2022-05-18 17:29:51.633 2614-2978/com.huawei.iaware I/APwLevelAnalysis: frequently auto start app: com.sufadi.blockautostart_deader count:20 duration:366667 level:2 // 检测到冷启动20次
2022-05-18 17:29:51.634 2614-2978/com.huawei.iaware I/APwActAnalysis: auto start high power app : com.sufadi.blockautostart_deader count:20 totalTime:366667// 高耗电提醒
3. apk 源码
3.1 APP1 负责启动后自杀
3.2.1 UI
3.1.2 核心逻辑
主要都需要设置为前台进程属性,服务的逻辑是收到 APP2 的kill Action 后,延迟5秒执行自杀
package com.sufadi.blockautostart_deader
import android.app.*
import android.content.Context
import android.content.Intent
import android.os.*
import android.util.Log
import com.sufadi.commlib.R
/**
* adb shell am force-stop com.sufadi.blockautostart
* adb shell am start-foreground-service -n com.sufadi.blockautostart_deader/com.sufadi.blockautostart_deader.AutoStartDeaderService
*
*while true;am force-stop com.sufadi.blockautostart_deader;do sleep 5;am start-foreground-service -n com.sufadi.blockautostart_deader/com.sufadi.blockautostart_deader.AutoStartDeaderService;done;
*/
class AutoStartDeaderService: Service() {
val TAG = "AutoStartDeaderService"
val FORGROUND_ID = 0x99
private var killCount = 0
var workHandler: WorkHandler?= null
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onCreate() {
Log.d("AutoStart", "AutoStartDeaderService onCreate")
val workThread = HandlerThread("work thread")
workThread.start()
workHandler = WorkHandler(workThread.looper)
startMyForeground()
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if ("kill_app" == intent?.action) {
killCount = intent.getIntExtra("kill_count", 0)
Log.d("AutoStart", "AutoStartDeaderService killCount:$killCount")
if (killCount < 20) {
workHandler?.removeMessages(1)
workHandler?.sendEmptyMessageDelayed(1, 5000)
}
}
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
Log.d("AutoStart", "AutoStartDeaderService onDestroy")
stopForeground(true)
super.onDestroy()
}
fun killAppProcess() {
Log.d("AutoStart", "AutoStartDeaderService Kill killAppProcess")
//注意:不能先杀掉主进程,否则逻辑代码无法继续执行,需先杀掉相关进程最后杀掉主进程
val mActivityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val mList = mActivityManager.runningAppProcesses
for (runningAppProcessInfo in mList) {
if (runningAppProcessInfo.pid != android.os.Process.myPid()) {
android.os.Process.killProcess(runningAppProcessInfo.pid)
Log.d("AutoStart", "Kill killAppProcess pid ${runningAppProcessInfo.pid}")
}
}
android.os.Process.killProcess(android.os.Process.myPid())
System.exit(0)
}
inner class WorkHandler(looper: Looper): Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
stopForeground(true)
killAppProcess()
}
}
private fun startMyForeground() {
Log.d(TAG, "startMyForeground show notification")
Log.d(TAG, "PhoneDataService startMyForeground sdk :" + android.os.Build.VERSION.SDK_INT)
val nb = Notification.Builder(this)
if (android.os.Build.VERSION.SDK_INT >= 26) {
val CHANNEL_ONE_ID = "channel_id_foreground"
val CHANNEL_ONE_NAME = "Channel One"
var notificationChannel: NotificationChannel? = null
notificationChannel = NotificationChannel(
CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_LOW
)
nb.setChannelId(CHANNEL_ONE_ID)
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(notificationChannel)
}
nb.setSmallIcon(R.mipmap.ic_launcher)
nb.setContentTitle(getString(R.string.notification_title))
nb.setContentText(getString(R.string.notification_Content))
try {
startForeground(FORGROUND_ID, nb.build())
} catch (e: Exception) {
e.printStackTrace()
}
}
}
3.2 APP2 负责定时复活APP1,触发冷启动检测
3.2.1 UI
package com.sufadi.blockautostart_doctor
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.sufadi.commlib.services.ForegroundService
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startService(Intent(this, AutoStartDoctorService::class.java))
}
}
3.2.2 核心逻辑
主要都需要设置为前台进程属性,服务的逻辑:每个20秒定时通过startService的方式启动 APP1
package com.sufadi.blockautostart_doctor
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.*
import android.util.Log
import com.sufadi.commlib.R
class AutoStartDoctorService : Service(){
val TAG = "AutoStartDoctorService"
val FORGROUND_ID = 0x77
var workHandler: WorkHandler?= null
var count = 0
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
val workThread = HandlerThread("work thread")
workThread.start()
workHandler = WorkHandler(workThread.looper)
workHandler?.removeMessages(1)
workHandler?.sendEmptyMessageDelayed(1, 20000)
startMyForeground()
}
override fun onDestroy() {
super.onDestroy()
stopForeground(true)
}
inner class WorkHandler(looper: Looper): Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
startDeaderApp()
workHandler?.removeMessages(1)
workHandler?.sendEmptyMessageDelayed(1, 20000)
}
}
/**
* adb shell am force-stop com.sufadi.blockautostart
* adb shell am start-foreground-service -n com.sufadi.blockautostart_deader/com.sufadi.blockautostart_deader.AutoStartDeaderService
* while true;am force-stop com.sufadi.blockautostart_deader;do sleep 5;am start-foreground-service -n com.sufadi.blockautostart_deader/com.sufadi.blockautostart_deader.AutoStartDeaderService;done;
* adb shell am start -n com.sufadi.blockautostart_deader/com.sufadi.blockautostart_deader.MainActivity
*/
fun startDeaderApp() {
count++
Log.d("AutoStart", "startDeaderApp startForegroundService count=$count")
val intent = Intent()
intent.setClassName("com.sufadi.blockautostart_deader", "com.sufadi.blockautostart_deader.AutoStartDeaderService")
if (count > 400) {
count = 0
} else if(count > 20) {
intent.action = "startDeaderApp"
} else {
intent.action = "kill_app"
intent.putExtra("kill_count", count)
}
startForegroundService(intent)
}
private fun startMyForeground() {
Log.d(TAG, "startMyForeground show notification")
Log.d(TAG, "PhoneDataService startMyForeground sdk :" + android.os.Build.VERSION.SDK_INT)
val nb = Notification.Builder(this)
if (android.os.Build.VERSION.SDK_INT >= 26) {
val CHANNEL_ONE_ID = "channel_id_foreground"
val CHANNEL_ONE_NAME = "Channel One"
var notificationChannel: NotificationChannel? = null
notificationChannel = NotificationChannel(
CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_LOW
)
nb.setChannelId(CHANNEL_ONE_ID)
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(notificationChannel)
}
nb.setSmallIcon(R.mipmap.ic_launcher)
nb.setContentTitle(getString(R.string.notification_title))
nb.setContentText(getString(R.string.notification_Content))
try {
startForeground(FORGROUND_ID, nb.build())
} catch (e: Exception) {
e.printStackTrace()
}
}
}