应用宝的NotificationManagerService_post_com.tencent.android.qqdownloader持锁现象

摘要:

现象:

应用宝的NotificationManagerService_post_com.tencent.android.qqdownloader在Doze下也可以频繁持锁,很猛啊。

解决方案:

直接拦截持锁就行,也可以冻结,限制服务或主动释放锁,反正解决起来很容易。就是没想明白,为了保活目的这么拼干啥。因为在AOSP代码也就是一个if else就屏蔽掉了哈,甚至都不需要查杀或冻结操作。

分析

相关逻辑系统内部调用链

1.应用调用 notify() 后,系统服务的执行流程如下:

2.应用进程 → Binder 调用 → NotificationManagerService.notify()

3.NotificationManagerService 内部处理通知:

4.最终释放 WakeLock 的逻辑由 PostNotificationTracker 在通知处理完成后触发。

其实消息通知触发也没关系,但是太频繁就过分了,会带来频繁的持锁,导致功耗变大哈。

应用宝的NotificationManagerService_post_com.tencent.android.qqdownloader持锁现象_第1张图片

日志

从日志看:感觉是定时周期1分钟,就行不断地持锁。这样做的目的是啥,我只知道对手机待机功耗是不友好的哈。

Line 2118: 05-26 17:34:43.610025  1623  1663 D PowerManagerService: acquireWakeLockInternal: lock=110346082, flags=0x1, tag="NotificationManagerService:post:com.tencent.android.qqdownloader", ws=WorkSource{10225 com.tencent.android.qqdownloader}, uid=1000, pid=1623Line 2773: 05-26 17:35:45.094949  1623  3364 D PowerManagerService: acquireWakeLockInternal: lock=206925355, flags=0x1, tag="NotificationManagerService:post:com.tencent.android.qqdownloader", ws=WorkSource{10225 com.tencent.android.qqdownloader}, uid=1000, pid=1623Line 3403: 05-26 17:36:46.593976  1623  3364 D PowerManagerService: acquireWakeLockInternal: lock=200498714, flags=0x1, tag="NotificationManagerService:post:com.tencent.android.qqdownloader", ws=WorkSource{10225 com.tencent.android.qqdownloader}, uid=1000, pid=1623Line 4148: 05-26 17:37:48.095304  1623  3450 D PowerManagerService: acquireWakeLockInternal: lock=91113790, flags=0x1, tag="NotificationManagerService:post:com.tencent.android.qqdownloader", ws=WorkSource{10225 com.tencent.android.qqdownloader}, uid=1000, pid=1623Line 4949: 05-26 17:38:49.596294  1623  3364 D PowerManagerService: acquireWakeLockInternal: lock=101527642, flags=0x1, tag="NotificationManagerService:post:com.tencent.android.qqdownloader", ws=WorkSource{10225 com.tencent.android.qqdownloader}, uid=1000, pid=1623Line 5400: 05-26 17:39:49.768274  1623  3451 D PowerManagerService: acquireWakeLockInternal: lock=190337700, flags=0x1, tag="NotificationManagerService:post:com.tencent.android.qqdownloader", ws=WorkSource{10225 com.tencent.android.qqdownloader}, uid=1000, pid=1623

源码

日志对应的源码:​​​​​​​

private PostNotificationTracker acquireWakeLockForPost(String pkg, int uid) {    // The package probably doesn't have WAKE_LOCK permission and should not require it.    return Binder.withCleanCallingIdentity(() -> {        WakeLock wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,                "NotificationManagerService:post:" + pkg); // 日志打印位置        wakeLock.setWorkSource(new WorkSource(uid, pkg));        wakeLock.acquire(POST_WAKE_LOCK_TIMEOUT.toMillis());        return mPostNotificationTrackerFactory.newTracker(wakeLock);    });}

相关逻辑系统内部调用链

1.应用调用 notify() 后,系统服务的执行流程如下:

2.应用进程 → Binder 调用 → NotificationManagerService.notify()

3.NotificationManagerService 内部处理通知:

4.最终释放 WakeLock 的逻辑由 PostNotificationTracker 在通知处理完成后触发。​​​​​​​

// 应用发送通知的典型代码NotificationManager nm = getSystemService(NotificationManager.class);Notification notification = new Notification.Builder(this, "channel_id")        .setContentTitle("Test")        .setContentText("Trigger WakeLock")        .setSmallIcon(R.drawable.ic_notification)        .build();nm.notify(1, notification);  // 触发内部 WakeLock 逻辑void enqueueNotificationInternal(...) {    // 检查权限、频道状态等    ...    // 获取 WakeLock(关键步骤)    PostNotificationTracker tracker = acquireWakeLockForPost(pkg, uid);    // 投递通知到系统UI    mHandler.post(new EnqueueNotificationRunnable(tracker));}最终释放 WakeLock 的逻辑由 PostNotificationTracker 在通知处理完成后触发。

解决方案:

直接拦截持锁就行,也可以冻结,限制服务或主动释放锁,反正解决起来很容易。就是没想明白,为了保活目的这么拼干啥。因为在AOSP代码也就是一个if else就屏蔽掉了哈,甚至都不需要查杀或冻结操作。

你可能感兴趣的:(android,gitee)