1. 測試現象
1.1 EPRODUCING PROCEDURES:
1.進入高德 Map(data) wifi),起點爲自己所在位置,搜索一個位置進行導航;
2.等待30秒後開始記錄電流,持續5分鐘;
3.按Power鍵,滅屏待機;
4.手機滅屏15秒後開始記錄電流,持續3分鐘;
1.2 Test numberSummary
設備 | 高德地圖導航 |
---|---|
測試機 | 461.82 mA |
對比機 | 369.13 mA |
2.分析
2.1 拔屏以扣除LCD影響
設備 | 高德地圖導航 |
---|---|
測試機+450nit帶屏幕導航 | 405.18 mA |
對比機+450nit帶屏幕導航 | 380.11 |
測試機+拔屏 | 174.45 mA |
對比機+拔屏 | 131.76 mA |
從上述看扣掉 LCD 同樣有功耗差異,即LCD 關係不大
注意:導航場景:一般是帶導航語音,即需要考慮Audio的影響
2.2 設計實驗找出問題差異
以下是我自己設計的實驗方法
1).對比機與測試機的GPS搜星實驗
- GPS puls 搜星查看,我apk放到附件中
- 只開啓GPS+飛行模式
- 儘量2臺機器相同環境下同時測試
4.放置5分鐘後,apk主界面截圖
GPS plus+工具 | 搜星情況 |
---|---|
對比機無GPS信號增強器 | 觀察衛星數量和信號強度 |
對比機有GPS信號增強器 | 觀察衛星數量和信號強度 |
測試機無GPS信號增強器 | 觀察衛星數量和信號強度 |
測試機有GPS信號增強器 | 觀察衛星數量和信號強度 |
實驗發現:基本無差異,故 GPS 單體應該是沒問題
2).導航電流測試
- 最暗亮度測試,避免扣掉屏幕帶來的影響
- 靜音+插入耳機,去除導航語音帶來的影響
- 儘量2臺機器相同環境下同時測試
測試項目 | 測試機器(mA) | 對比機(mA) |
---|---|---|
case 1 靜態HOME界面固定牆紙_飛行模式 | 65.21 | 68.19 |
case 2網絡定位條件,高德導航測試:只保持WiFi連接,飛行模式 | 87.63 | 88.95 |
case 3 GPS定位條件,高德導航測試:開啓GPS+插卡+WiFi 連接 | 147.63 | 120.71 |
case 4 GPS定位條件,高德導航測試:GPS增強器+開啓GPS+插卡+WiFi 連接 | 169.64 | 153.48 |
- case 1 目的: 對比相同亮度下是否存在差異
- case 2 目的: 查看是否網絡定位有問題
- case 3 目的:查看是否GPS定位存問題
- case 3 目的: 查殺是否與GPS信號強度有關,因爲室內是GPS信號比較弱
上述:
- case 1 說明測試機和對比機亮屏下相同亮度的測試電流是基本一致,即基礎的系統功耗是相同的
- case 2 說明網絡定位是OK的,說明相同APK在不同機器測試,運行是後臺也基本保持一致,且說明如果GPS不開啓則是導航是好的;
- case 3、case 4 說明GPS開啓,會帶來導航功耗影響
3).GPS單體功耗
這塊數據沒有,故需要讓硬件提供:
測試步驟:
Wi-Fi Off, GPS ON, BT OFF, NFC OFF, Fly mode ON.
滅屏,等待1min,記錄平均電流,即是打開GPS時的電流。
在上述的條件時,記錄下可以穩定復現的最小電流值,即是 GPS floor current.
Average current when GPS navigation working:
Step1:通過下拉菜單,打開飛行模式,打開位置服務;
Step2:進入工程模式 adb shell am start -n com.mediatek.ygps/com.mediatek.ygps.YgpsActivity;
Step3:進入Location->YGPS->Enable in BG.(need restart),重啓後再次進入該界面;
Step4:關閉屏幕,待電流穩定,測試3分鐘,記錄電流A1;
Step5:通過下拉菜單,關閉位置服務;
Step6:進入工程模式,進入Location->YGPS,再回到YGPS界面;
Step7:關閉屏幕,待電流穩定,測試3分鐘,記錄電流A2;
GPS ON=A1-A2
由於不知道 ygps 源碼,通過測試步驟基本猜到,主要是測試GPS開啓電流和工作電流,相當於高德地圖的定位場景,非導航場景
測試數據:
設備 | 平均電流 |
---|---|
測試機 | 34mA |
對比機 | 34mA |
從上面數據看,GPS的工作電流是基本一致的,即GPS單體是OK的
這就奇怪了,GPS單體是好的,爲什麼導航一開GPS就存問題呢?還需要再排除干擾。例如以下干擾:
- WiFi 環境因素
- 4G 插卡因素
- 應用啓動後會進行頁面、地圖數據、配置文件下載
- 測試過程中,如果網絡發生變化,熱點不穩定
4).離線導航
- Wi-Fi Off, GPS ON, BT OFF, NFC OFF, Fly mode ON,排除WiFi帶來的干擾
- 最小亮度
- 使用 what_temp apk抓CPU數據
- 靜音插耳機
- 使用高德離線地圖導航
設備 | 測試機 | 對比機 |
---|---|---|
高德地圖定位界面 | 55.13mA | 50.13mA |
高德地圖導航界面 | 83.00mA | 60.49mA |
上述查看:
- 現象復現,即排除了Wi-Fi Off, GPS ON, BT OFF, NFC OFF, Fly mode影響,即wifi、4G都沒問題
- 定位場景差異不大,導航場景差異比較大。
- 需要查看高德地圖定位細節
2.3 高德地圖的dump信息
dumpsys location|grep -B 2 “com.autonavi.minimap”
Tokyo_Lite:/ $ dumpsys location|grep -B 2 "com.autonavi.minimap"
Battery Saver Location Mode: NO_CHANGE
Location Listeners:
Reciever[35eed63 listener UpdateRecord[passive com.autonavi.minimap(10167 foreground) Request[POWER_NONE passive fastest=0] null], isNeedBgGpsRestrict false monitoring location: true]
Reciever[fe54b41 listener UpdateRecord[passive android(1000 foreground) Request[POWER_NONE passive fastest=+30m0s0ms] null], isNeedBgGpsRestrict false monitoring location: true]
Reciever[a523146 listener UpdateRecord[passive com.autonavi.minimap(10167 foreground) Request[POWER_NONE passive fastest=+1s0ms] null], isNeedBgGpsRestrict false monitoring location: true]
Reciever[4698940 listener UpdateRecord[passive android(1000 foreground) Request[POWER_NONE passive fastest=0] null], isNeedBgGpsRestrict false monitoring location: false]
Reciever[3e939ea listener monitoring location: false]
Reciever[a629ca9 listener UpdateRecord[gps com.autonavi.minimap(10167 foreground) Request[ACCURACY_FINE gps requested=+1s0ms fastest=+1s0ms] null], isNeedBgGpsRestrict false monitoring location: true]
Active Records by Provider:
gps:
UpdateRecord[gps com.autonavi.minimap(10167 foreground) Request[ACCURACY_FINE gps requested=+1s0ms fastest=+1s0ms] null], isNeedBgGpsRestrict false
--
UpdateRecord[passive android(1000 foreground) Request[POWER_NONE passive fastest=0] null], isNeedBgGpsRestrict false
UpdateRecord[passive android(1000 foreground) Request[POWER_NONE passive fastest=+30m0s0ms] null], isNeedBgGpsRestrict false
UpdateRecord[passive com.autonavi.minimap(10167 foreground) Request[POWER_NONE passive fastest=0] null], isNeedBgGpsRestrict false
UpdateRecord[passive com.autonavi.minimap(10167 foreground) Request[POWER_NONE passive fastest=+1s0ms] null], isNeedBgGpsRestrict false
--
Active GnssNavigationMessage Listeners:
Active GnssStatus Listeners:
5600 10167 com.autonavi.minimap: false
5600 10167 com.autonavi.minimap: false
5600 10167 com.autonavi.minimap: false
5766 10167 com.autonavi.minimap: false
Historical Records by Provider:
android: passive: Min interval 0 seconds: Max interval 1800 seconds: Duration requested 99 total, 99 foreground, out of the last 99 minutes: Currently active
com.autonavi.minimap: passive: Min interval 0 seconds: Max interval 1 seconds: Duration requested 2 total, 2 foreground, out of the last 98 minutes: Currently active
com.autonavi.minimap: gps: Interval 1 seconds: Duration requested 2 total, 2 foreground, out of the last 98 minutes: Currently active
查看高德地圖的dump信息,我們基本知道高德地圖申請了哪些定位:
- GPS 定位,定位間隔1秒一個
Reciever[a629ca9 listener UpdateRecord[gps com.autonavi.minimap(10167 foreground) Request[ACCURACY_FINE gps requested=+1s0ms fastest=+1s0ms] null], isNeedBgGpsRestrict false monitoring location: true] - passive 定位
Reciever[a523146 listener UpdateRecord[passive com.autonavi.minimap(10167 foreground) Request[POWER_NONE passive fastest=+1s0ms] null], isNeedBgGpsRestrict false monitoring location: true] - 監聽了 GnssStatus 數據
Active GnssStatus Listeners:
5600 10167 com.autonavi.minimap: false
5600 10167 com.autonavi.minimap: false
5600 10167 com.autonavi.minimap: false
5766 10167 com.autonavi.minimap: false
2.4 分析高德地圖定位和導航調用的函數
我們在dump locaiton已經知道高德地圖會申請使用GPS,並且定位間隔爲1秒,故不需要在
1) LocationManager 埋點
public class LocationManager {
public boolean addNmeaListener(
@NonNull OnNmeaMessageListener listener, @Nullable Handler handler) {
boolean result;
// huazhi.su
if("true".equals(SystemProperties.get("persist.sys.tct.addNmeaListener.debug", "false"))) {
Log.e(TAG, "skip addNmeaListener");
return false;
}
// huazhi.su
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean registerGnssStatusCallback(
@NonNull GnssStatus.Callback callback, @Nullable Handler handler) {
boolean result;
synchronized (mGnssStatusListeners) {
// huazhi.su
if("true".equals(SystemProperties.get("persist.sys.tct.registerGnssStatusCallback.debug", "false"))) {
if("com.autonavi.minimap".equals(mContext.getPackageName())) {
Log.e(TAG, "skip registerGnssStatusCallback packageName:" + mContext.getPackageName());
}
return false;
}
// huazhi.su
2) 查看導航場景高德地圖使用的sdk情況
場景 | API接口 |
---|---|
定位場景 | requestLocationUpdates、registerGnssStatusCallback |
導航場景 | requestLocationUpdates、registerGnssStatusCallback、addNmeaListener |
即導航場景比定位場景多了 addNmeaListener
12-06 14:10:44.728 3716 3716 W System.err: at android.location.LocationManager.addNmeaListener(LocationManager.java:2046)
12-06 14:10:44.736 3716 4034 W System.err: at android.location.LocationManager.registerGnssStatusCallback(LocationManager.java:1944)
locationManager.registerGnssStatusCallback(new GnssStatus.Callback() {
@Override
public void onSatelliteStatusChanged(GnssStatus status) {
super.onSatelliteStatusChanged(status);
Log.d(TAG, "onSatelliteStatusChanged");
}
});
locationManager.addNmeaListener(new OnNmeaMessageListener() {
@Override
public void onNmeaMessage(String message, long timestamp) {
Log.d(TAG, "onNmeaMessage message :" + message + ", timestamp :" + timestamp);
sendRequestWithHttpClient();
}
});
locationManager.requestLocationUpdates(GPS_PROVIDER, 1000, 0, mMyLocationListener);
- 之前的測試GPS單體的功耗基本是 requestLocationUpdates 這個接口的功能,故 基本問題不大
- 且導航和定位場景中,導航場景存在和定位場景不同,故我們可以單獨屏蔽掉 registerGnssStatusCallback、addNmeaListener
3. 問題根源研究
3.1 禁止監聽 GnssStatus 和 Nmea
測試項 | 平均電流 | 備註 |
---|---|---|
離線導航 | 133 | 異常電流波形 |
離線導航+禁止監聽 GnssStatus | 120 | 異常電流波形 |
離線導航+禁止監聽 Nmea | 110 | 異常電流波形 |
離線導航+禁止監聽 Nmea + GnssStatus | 100 | 正常電流波形 |
首先我們看下異常電流:特徵是一秒鐘一個波峯,且單個異常波形平均電流就有166mA,基本功耗不被拉大才怪
上述說明:監聽 Nmea + GnssStatus 會帶來功耗,但是肯定要給第三方應用正常使用這個數據
3.1 攔截 GnssStatus 和 Nmea
攔截位置
package com.android.server.location;
public class GnssLocationProvider ...{
@NativeEntryPoint // libgnss.so上報
private void reportNmea(long timestamp) {
// 新增攔截
...
// 對應上層的:public void onNmeaMessage(String message, long timestamp) 方法
...
}
@NativeEntryPoint // libgnss.so上報
private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s,
// 新增攔截
...
// 對應上層的:public void onSatelliteStatusChanged(GnssStatus status) { 方法
...
}
}
測試項 | 平均電流 | 備註 |
---|---|---|
離線導航 | 133 | 異常電流波形 |
離線導航+攔截 GnssStatus 數據上報 | 123 | 異常電流波形 |
離線導航+攔截 Nmea 數據上報 | 110 | 異常電流波形 |
離線導航+攔截 Nmea + GnssStatus 數據上報 | 100 | 正常電流波形 |
攔截測試也說明 Nmea + GnssStatus 有影響,難道高德地圖會收到數據做一些耗電操作,還是對比機有優化呢?
由於高德地圖、對比機沒有源碼,所以我們無法知道,從源碼一個函數一個函數地分析。看是否源代碼有問題,即瞭解GPS的Nmea + GnssStatus上報給上層的源碼
4. 源碼分析並新增日誌
4.1 源碼數據通路新增日誌
例如 Nmea 數據如何上報給上層apk,在這個數據傳遞的通路新增日誌,每個函數調用的地方都加
1.數據源頭-------------------------------------------------
package com.android.server.location;
@NativeEntryPoint
private void reportNmea(long timestamp) {
if (!mItarSpeedLimitExceeded) {
int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
mGnssStatusListenerHelper.onNmeaReceived(timestamp, nmea);
}
}
2.-------------------------------------------------
public abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatusListener> {
public void onNmeaReceived(final long timestamp, final String nmea) {
// 遍歷 addNmeaListener 監聽數量,例如高德地圖使用了2個,一個定位註冊的,一個導航場景註冊的
foreach((IGnssStatusListener listener, CallerIdentity callerIdentity) -> {
// 檢查是否與定位權限
if (hasPermission(mContext, callerIdentity)) {
logPermissionDisabledEventNotReported(TAG, callerIdentity.mPackageName, "NMEA");
return;
}
// 消息傳遞到上層
listener.onNmeaReceived(timestamp, nmea);
});
}
}
3.-------------------------------------------------
public class LocationManager {
@Override
public void onNmeaReceived(long timestamp, String nmea) {
...
mGnssHandler.obtainMessage(NMEA_RECEIVED).sendToTarget();
...
}
for (Nmea nmea : mNmeaBuffer) {
// 數據給上層
mGnssNmeaListener.onNmeaMessage(nmea.mNmea, nmea.mTimestamp);
}
4.2 現象發現
1)日誌大量打印,這裏1秒鐘70組數據從底層上報出來,都需要經過上述的函數,簡直是太頻繁
01-01 00:04:54.516 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GNGGA,160454.011,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*5F
01-01 00:04:54.516 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GNGGA,160454.011,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*5F
01-01 00:04:54.518 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GNGGA,160454.011,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*5F
01-01 00:04:54.519 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
01-01 00:04:54.520 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
01-01 00:04:54.522 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
01-01 00:04:54.522 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
01-01 00:04:54.522 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GLGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2C
01-01 00:04:54.524 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GLGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2C
01-01 00:04:54.524 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GLGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2C
01-01 00:04:54.526 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GLGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2C
01-01 00:04:54.526 3740 4447 E LocationManager: skip onNmeaReceived: nmea$BDGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*21
01-01 00:04:54.527 3328 4051 E LocationManager: skip onNmeaReceived: nmea$BDGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*21
01-01 00:04:54.527 3328 4051 E LocationManager: skip onNmeaReceived: nmea$BDGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*21
01-01 00:04:54.527 3328 4561 E LocationManager: skip onNmeaReceived: nmea$BDGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*21
01-01 00:04:54.528 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GAGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*21
01-01 00:04:54.529 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GAGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*21
01-01 00:04:54.529 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GAGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*21
01-01 00:04:54.529 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GAGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*21
01-01 00:04:54.531 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GPGSV,1,1,0*49
01-01 00:04:54.531 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GPGSV,1,1,0*49
01-01 00:04:54.531 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GPGSV,1,1,0*49
01-01 00:04:54.533 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GLGSV,1,1,0*55
01-01 00:04:54.533 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GLGSV,1,1,0*55
01-01 00:04:54.534 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GPGSV,1,1,0*49
01-01 00:04:54.534 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GLGSV,1,1,0*55
01-01 00:04:54.535 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GLGSV,1,1,0*55
01-01 00:04:54.535 3740 4447 E LocationManager: skip onNmeaReceived: nmea$BDGSV,1,1,0*58
01-01 00:04:54.536 3328 4051 E LocationManager: skip onNmeaReceived: nmea$BDGSV,1,1,0*58
01-01 00:04:54.536 3328 4561 E LocationManager: skip onNmeaReceived: nmea$BDGSV,1,1,0*58
01-01 00:04:54.536 3328 4561 E LocationManager: skip onNmeaReceived: nmea$BDGSV,1,1,0*58
01-01 00:04:54.537 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GAGSV,1,1,0*58
01-01 00:04:54.537 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GAGSV,1,1,0*58
01-01 00:04:54.538 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GAGSV,1,1,0*58
01-01 00:04:54.538 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GAGSV,1,1,0*58
01-01 00:04:54.539 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GNRMC,160454.011,V,8960.0000,N,00000.0000,E,0.000,0.00,311218,,,N*55
01-01 00:04:54.539 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GNRMC,160454.011,V,8960.0000,N,00000.0000,E,0.000,0.00,311218,,,N*55
01-01 00:04:54.539 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GNRMC,160454.011,V,8960.0000,N,00000.0000,E,0.000,0.00,311218,,,N*55
01-01 00:04:54.540 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GNVTG,0.00,T,,M,0.000,N,0.000,K,N*2C
01-01 00:04:54.541 3328 4561 E LocationManager: skip onNmeaReceived: nmea$GNVTG,0.00,T,,M,0.000,N,0.000,K,N*2C
01-01 00:04:54.542 3328 3345 E LocationManager: skip onNmeaReceived: nmea$GNVTG,0.00,T,,M,0.000,N,0.000,K,N*2C
01-01 00:04:54.542 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GNRMC,160454.011,V,8960.0000,N,00000.0000,E,0.000,0.00,311218,,,N*55
01-01 00:04:54.542 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GNVTG,0.00,T,,M,0.000,N,0.000,K,N*2C
01-01 00:04:54.542 3740 4447 E LocationManager: skip onNmeaReceived: nmea$PMTKTSX1,5012,326233.306,43.336,38.845,59000000,32.622746,32.623331,0.000000,-0.225000,0.000000,32.623*7C
01-01 00:04:54.543 3328 4051 E LocationManager: skip onNmeaReceived: nmea$PMTKTSX1,5012,326233.306,43.336,38.845,59000000,32.622746,32.623331,0.000000,-0.225000,0.000000,32.623*7C
01-01 00:04:54.544 3328 4051 E LocationManager: skip onNmeaReceived: nmea$PMTKTSX1,5012,326233.306,43.336,38.845,59000000,32.622746,32.623331,0.000000,-0.225000,0.000000,32.623*7C
01-01 00:04:54.544 3328 3345 E LocationManager: skip onNmeaReceived: nmea$PMTKTSX1,5012,326233.306,43.336,38.845,59000000,32.622746,32.623331,0.000000,-0.225000,0.000000,32.623*7C
01-01 00:04:54.544 3740 4447 E LocationManager: skip onNmeaReceived: nmea$PMTKGEPH,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*04
01-01 00:04:54.545 3328 3345 E LocationManager: skip onNmeaReceived: nmea$PMTKGEPH,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*04
01-01 00:04:54.545 3328 4051 E LocationManager: skip onNmeaReceived: nmea$PMTKGEPH,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*04
01-01 00:04:54.546 3328 4051 E LocationManager: skip onNmeaReceived: nmea$PMTKGEPH,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*04
01-01 00:04:54.546 3740 4447 E LocationManager: skip onNmeaReceived: nmea$PMTKGALM,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*19
01-01 00:04:54.547 3328 4051 E LocationManager: skip onNmeaReceived: nmea$PMTKGALM,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*19
01-01 00:04:54.547 3328 3345 E LocationManager: skip onNmeaReceived: nmea$PMTKGALM,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*19
01-01 00:04:54.548 3328 4051 E LocationManager: skip onNmeaReceived: nmea$PMTKGALM,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*19
01-01 00:04:54.548 3740 4447 E LocationManager: skip onNmeaReceived: nmea$GNACCURACY,3162.1,180.0,3.5,500.0*29
01-01 00:04:54.548 3328 4051 E LocationManager: skip onNmeaReceived: nmea$GNACCURACY,3162.1,180.0,3.5,500.0*29
01-01 00:04:54.549 3328 3345 E LocationManager: skip onNmeaReceived: nmea$GNACCURACY,3162.1,180.0,3.5,500.0*29
01-01 00:04:54.549 3328 3345 E LocationManager: skip onNmeaReceived: nmea$GNACCURACY,3162.1,180.0,3.5,500.0*29
01-01 00:04:54.550 3740 4447 E LocationManager: skip onNmeaReceived: nmea$PMTKAGC,160454.011,6174,6241,7189,7273,0,0,0*68
01-01 00:04:54.550 3328 3345 E LocationManager: skip onNmeaReceived: nmea$PMTKAGC,160454.011,6174,6241,7189,7273,0,0,0*68
01-01 00:04:54.551 3328 3345 E LocationManager: skip onNmeaReceived: nmea$PMTKAGC,160454.011,6174,6241,7189,7273,0,0,0*68
01-01 00:04:54.551 3328 4051 E LocationManager: skip onNmeaReceived: nmea$PMTKAGC,160454.011,6174,6241,7189,7273,0,0,0*68
01-01 00:04:54.553 3740 4447 E LocationManager: skip onNmeaReceived: nmea$PMTKAG2,160454.011,6*1C
01-01 00:04:54.553 3328 4051 E LocationManager: skip onNmeaReceived: nmea$PMTKAG2,160454.011,6*1C
01-01 00:04:54.553 3328 3345 E LocationManager: skip onNmeaReceived: nmea$PMTKAG2,160454.011,6*1C
01-01 00:04:54.554 3328 3345 E LocationManager: skip onNmeaReceived: nmea$PMTKAG2,160454.011,6*1C
2)異常發現
發現只要去掉 hasPermission 的調用,功耗就能掉下來,沒想到是這個函數搞得鬼
public void onNmeaReceived(final long timestamp, final String nmea) {
foreach((IGnssStatusListener listener, CallerIdentity callerIdentity) -> {
// huazhi.su add start
if("true".equals(SystemProperties.get("persist.sys.Helper.hasPermission", "false"))) {
// 實測1秒中被調用了70次,去除後平均電流減少20mA
// 這個判斷作用:若用戶定位的時候突然關閉GPS權限,則也要相應停止數據上報到上層
// 出發點是好:但是1秒鐘判斷了70次就不厚道了,且不同應用註冊的數量不同,故這裏的次數也不一樣
if (!hasPermission(mContext, callerIdentity)) {
logPermissionDisabledEventNotReported(TAG, callerIdentity.mPackageName, "NMEA");
return;
}
}
// huazhi.su add end
listener.onNmeaReceived(timestamp, nmea);
});
protected boolean hasPermission(Context context, CallerIdentity callerIdentity) {
if (LocationPermissionUtil.doesCallerReportToAppOps(context, callerIdentity)) {
// The caller is identified as a location provider that will report location
// access to AppOps. Skip noteOp but do checkOp to check for location permission.
return mAppOps.checkOpNoThrow(AppOpsManager.OP_FINE_LOCATION, callerIdentity.mUid,
callerIdentity.mPackageName) == AppOpsManager.MODE_ALLOWED;
}
return mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, callerIdentity.mUid,
callerIdentity.mPackageName) == AppOpsManager.MODE_ALLOWED;
}
上述中 reportSvStatus 也使用到了 hasPermission 的判斷,但是實測回調的次數沒有 reportNmea多,故功耗電流小一些
public void onSvStatusChanged (
...
hasPermission(mContext, callerIdentity)
...
}
5. 問題發現與解決
5.1. 功耗問題原因
去掉了 hasPermission 就好,說明系統也經不起頻繁執行某個函數的方法
5.2. 分析
源碼也存在問題,爲什麼這麼頻繁調用的地方,每次都是執行一個函數,幹嘛不把這個變量的狀態保持下來。讀狀態比去執行函數的效率高多了。
估計 Google 寫這個函數的時候,沒考慮的這裏實際會被頻繁調用到
5.3. 解決方案
- 監聽權限變化事件,當權限改變的時候,更新下對應uid的權限,並保存起來
context.getPackageManager().addOnPermissionsChangeListener(mOnPermissionsChangedListener);
private OnPermissionsChangedListener mOnPermissionsChangedListener = new OnPermissionsChangedListener() {
public void onPermissionsChanged(int uid) {
updatePermissionsChanged(uid);
}
};
- 若當前保存了uid的權限狀態,則讀狀態,而不是每次執行函數獲取,提高效率
private boolean isHasPermission(Context context, CallerIdentity callerIdentity) {
if(mPermissionsList.containsKey(callerIdentity.mUid)) {
return mPermissionsList.get(callerIdentity.mUid);
} else {
boolean isHasPermission = hasPermission(mContext, callerIdentity);
mPermissionsList.put(callerIdentity.mUid, isHasPermission);
return isHasPermission;
}
}
5.4 高德地圖導航場景電流優化了 30mA
優化後電流由 133mA 下降到100mA, 1秒鐘一個的異常波形也消失了。
由於這裏數據是我自己測的