PowerManager的partial wake lock

Partial wake locks are a mechanism in the PowerManager API that lets developers keep the CPU running after a device's display turns off (whether due to system timeout or the user pressing the power button). 

翻译:partial wake locks 是 powerManager API 里面的一种机制,这种机制可以在息屏的时候保持cpu running

 

Your app acquires a partial wake lock by calling acquire() with the PARTIAL_WAKE_LOCK flag.

翻译:通过调用acquire 方法(with partial_wake_lock)可以获得 一个partial wake lock

 

A partial wake lock becomes stuck if it is held for a long time while your app is running in the background (no part of your app is visible to the user).

翻译:如果partial wake lock 长时间hold 并且app 在后台运行,则这个partial wake lock 变成 stuck

 

This condition drains the device's battery because it prevents the device from entering lower power states.

翻译:这个状况会消耗设备的电量,因为它阻止设备进入低电量模式。

 

Partial wake locks should be used only when necessary and released as soon as no longer needed.

翻译:partial wake lock 应该只有在必要的时候才用,并且用完要尽快释放

 

If your app has a stuck partial wake lock, you can use the guidance in this page to diagnose and fix the problem.

翻译:如果你的app有这个问题,你可以用下面的guidance 来诊断和解决。

 

Detect the problem

检测问题

You may not always know that your app's partial wake locks are stuck. If you have already published your app, Android vitals can help make you aware of the problem.

你可能不知道你的app 的 partial wake locks stuck了。如果你的app已经发布,android vital 可以帮助你意识到这些问题

 

Android vitals

Android vitals can help improve your app's performance by alerting you, via the Play Console, when your app is exhibiting stuck partial wake locks. Android vitals reports partial wake locks as stuck when at least one, hour-long, partial wake lock occurs in either:

or

  • At least either 0.70% of battery sessions as a whole.
  • At least 0.10% of battery sessions while running only in the background.

符合上面条件的会被当做 partial wake stuck

 

battery session refers to the interval between two full battery charges. The number of battery sessions displayed is an aggregate for all measured users of the app. For information on how Google Play collects Android vitals data, see thePlay Console documentation.

battery session 是指两次电池充满电的时间间隔 。

Once you're aware that your app has excessive stuck partial wake locks, your next step is to address the issue.

意识到问题后就要解决问题。

 

Fix the problem

Wake locks were introduced in early versions of the Android platform, but over time, many use cases that previously required wake locks are now better served by newer APIs like WorkManager.

Wake locks 是android 早期版本引入的,但是随着时间的推移,之前需要 wake locks 的条件现在用 新api  WorkManager更合适。

 

This section contains tips for fixing your wake locks, but in the long term, consider migrating your app to follow the recommendations in the best practices section.

下面的部分给你解决 wake locks问题的建议,但是长期来看,follow best practics 更好。

 

Identify and fix places in your code that acquire a wake lock, such as newWakeLock(int, String) or WakefulBroadcastReceiver. Here are some tips:

确定要用 wake lock 的位置 ,如(newWakeLock, WakefulBroadcastReceiver),下面是建议

 

We recommend including your package, class, or method name in the wake lock tag name so that you can easily identify the location in your source where the wake lock was created. Here are some additional tips:

命名要注意

  • Leave out any personally identifying information (PII) in the name, such as an email address. Otherwise, the device logs _UNKNOWN instead of the wake lock name.

命名中省略个人标识信息

  • Don't get the class or method name programmatically, for example by calling getName(), because it could get obfuscated by Proguard. Instead use a hard-coded string.

不要getName来获取类名,而是要用硬编码,因为会混淆

 

  • Don't add a counter or unique identifiers to wake lock tags. The system will not be able to aggregate wake locks created by the same method because they all have unique identifiers.

不要添加计数器或者唯一标识符

Make sure your code releases all the wake locks that it acquires. This is more complicated than making sure that every call to acquire() has a corresponding call to release(). Here's an example of a wake lock that is not released due to an uncaught exception:

确保释放锁。

 

错误示范:

 void doSomethingAndRelease() throws MyException {
        wakeLock.acquire();
        doSomethingThatThrows();
        wakeLock.release();  // does not run if an exception is thrown
    }

 

正确示范

  void doSomethingAndRelease() throws MyException {
        try {
            wakeLock.acquire();
            doSomethingThatThrows();
        } finally {
            wakeLock.release();
        }
    }

 

Make sure that wake locks are released as soon as they are no longer needed. For example, if you are using a wake lock to allow a background task to finish, make sure that release happens when that task finishes. If a wake lock is held longer than expected without being released, this could mean that your background task is taking more time than expected.

干完活就释放锁。。

After fixing the problem in code, verify that your app correctly releases wake locks by using the following Android tools:

使用下面的工具来确认app 正确释放了锁

dumpsys - a tool that provides information about the status of system services on a device. To see the status of the power service, which includes a list of wake locks, run adb shell dumpsys power.

使用dumpsys工具

 

 

Battery Historian - a tool that parses the output of an Android bug report into a visual representation of power related events.

Battery Historian

 

Best practices

最佳实践

In general, your app should avoid partial wake locks because it is too easy to drain the user's battery. Android provides alternative APIs for almost every use-case that previously required a partial wake lock. One remaining use-case for partial wake locks is to ensure that a music app continues to play when the screen is off. If you are using wake locks to run tasks, consider the alternatives described in the background processing guide.

partial wake lock 能不用尽量不用。android有替代方案, 音乐播放是个例外。如果使用wake locks,考虑使用替代方案:

参考:background processing guide.

 

If you must use partial wake locks, follow these recommendations:

如果非用不可,考虑如下建议

  • Make sure some portion of your app remains in the foreground. For example, if you need to run a service, start a foreground service instead. This visually indicates to the user that your app is still running.

翻译:用户可感知

  • Make sure the logic for acquiring and releasing wake locks is as simple as possible. When your wake lock logic is tied to complex state machines, timeouts, executor pools, and/or callback events, any subtle bug in that logic can cause the wake lock to be held longer than expected. These bugs are difficult to diagnose and debug.

翻译:使获取锁和释放锁越简单越好

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
author:杨兴达; 邮箱:yangxingda1988@163.com 电话:180 1018 0585 Android 电源管理 -- wakelock机制,通过控制wakelock 实现保持pad 禁止休眠状态; Wake Lock是一种锁的机制, 只要有人拿着这个锁,系统就无法进入休眠, 可以被用户态程序和内核获得. 这个锁可以是有超时的 或者 是没有超时的, 超时的锁会在时间过去以后自动解锁。如果没有锁了或者超时了, 内核就会启动休眠的那套机制来进入休眠. PowerManager.WakeLock 有加锁和解锁两种状态,加锁的方式有两种: 第一种是永久的锁住,这样的锁除非显式的放开,否则是不会解锁的,所以这种锁用起来要非常的小心。 第二种锁是超时锁,这种锁会在锁住后一段时间解锁。 在创建了 PowerManager.WakeLock 后,有两种机制,第一种是不计数锁机制,另一种是计数锁机制。可以通过 setReferenceCounted(boolean value) 来指定,一般默认为计数机制。这两种机制的区别在于,前者无论 acquire() 了多少次,只要通过一次 release()即可解锁。而后者正真解锁是在( --count == 0 )的时候,同样当 (count == 0) 的时候才会去申请加锁。所以 PowerManager.WakeLock 的计数机制并不是正真意义上的对每次请求进行申请/释放每一把锁,它只是对同一把锁被申请/释放的次数进行了统计,然后再去操作。 源码 位置:frameworks/base/core/java/android/os/PowerManager.java ++++++++++++++++++++++++ 讲述 应用层 申请的锁 怎么传到kernel下面的,来理解 整个wakelock的框架。 比如android跑起来之后 在 /sys/power/wake_lock 下面的PowerManagerService 的生成过程。 1).应用程序申请锁 Android 提供了现成 android.os.PowerManager 类 , 类中 提供newWakeLock(int flags, String tag)方法 来取得 应用层的锁, 此函数的定义 frameworks/base/core/java/android/os/PowerManager.java 应用程序 在申请wake_lock时 都会有调用以下 部分。 实例: PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, “MyTag”); wl.acquire();//申请锁,这里会调用PowerManagerService里面acquireWakeLock() *********************** wl.release(); //释放锁,显示的释放锁,如果申请的锁不在此释放,系统就不会进入休眠。 ====================================== 2). frameworks层 /frameworks/base/services/java/com/android/server/PowerManagerService.java这个类是来管理 所有的应用程序 申请的wakelock。比如音视、频播放器、camera等申请的wakelock 都是通过这个类来 管理的。 static final String PARTIAL_NAME ="PowerManagerService" nativeAcquireWakeLock(PARTIAL_WAKE_LOCK_ID, PARTIAL_NAME); 上面 这个函数调用Power类 里面的 acquireWakeLock(),此时的PARTIAL_NAME作为参数传递到底层去。 public static native void nativeAcquireWakeLock(int lock, String id); 注:在PowerManagerService 类中没有实现nativeAcquireWakeLock,其实现体在 frameworks/base/core/jni/android_os_Power.cpp中,所以nativeAcquireWakeLock()方法时会调用JNI下的实现方法。 3).JNI层的实现 路径:frameworks/base/core/jni/android_os_Power.cpp // static void acquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj) { ************** const char *id = env->GetStringUTFChars(idObj, NULL); acquire_wake_lock(lock, id); env->ReleaseStringUTFChars(idObj, id); } 注:在acquireWakeLock()中调用了 路径下hardware/libhardware_legacy/power/power.c下面的acquire_wake_lock(lock, id) 4).与kernel层的交互 在power.c下的acquire_wake_lock(lock, id)函数如下: int acquire_wake_lock(int lock, const char* id) { ************** return write(fd, id, strlen(id)); } 注: fd就是文件描述符,在此 表示”/sys/power/wake_lock” id就是从PowerManagerService类中传下来的参数即:PARTIAL_NAME = "PowerManagerService" 到此 就是通过 文件系统 来与kernel层 交互的地方。 +++++++++++++++++++++++++++++++++++++++++++++++++++++ PowerManager类被应用程序调用,控制电源设备状态切换: PowerManager类对外有三个接口函数: 1、void goToSleep(long time); //强制设备进入Sleep状态 Note:在应用层调用该函数, 应用需要 在 源码下编译,用系统签名,否则 调用 此函数 出错; 2、newWakeLock(int flags, String tag);//取得相应层次的锁 flags参数说明: PARTIAL_WAKE_LOCK :保持CPU 运转,屏幕和键盘灯是关闭的。 SCREEN_DIM_WAKE_LOCK :保持CPU 运转,允许保持屏幕显示但有可能是灰的,关闭键盘灯 SCREEN_BRIGHT_WAKE_LOCK :保持CPU 运转,保持屏幕高亮显示,关闭键盘灯 FULL_WAKE_LOCK :保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度 ACQUIRE_CAUSES_WAKEUP: 一旦有请求锁时,强制打开Screen和keyboard light ON_AFTER_RELEASE: 在释放锁时reset activity timer Note: 如果申请了partial wakelock,那么即使按Power键,系统也不会进Sleep,如Music播放时 如果申请了其它的wakelocks,按Power键,系统还是会进Sleep 3、void userActivity(long when, boolean noChangeLights);//User activity事件发生,设备会被切换到Full on的状态,同时Reset Screen off timer. PowerManagerWakeLock的操作步骤 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);通过 Context.getSystemService().方法获取PowerManager实例。 然后通过PowerManager的newWakeLock ((int flags, String tag)来生成WakeLock实例。int Flags指示要获取哪种WakeLock,不同的Lock对cpu 、屏幕、键盘灯有不同影响。 获取WakeLock实例后通过acquire()获取相应的锁,然后进行其他操作,最后使用release()释放(释放是必须的)。 Note: 1. 在使用以上函数的应用程序中,必须在其Manifest.xml文件中加入下面的权限: <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> 2. 所有的锁必须成对的使用, 如果申请了而没有及时释放,会造成系统故障。如申请了partial wakelock,而没有及时释放, 那系统就永远进不了Sleep模式.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值