Merge "Add BatteryStatsManager.getWakeLockStats() API"
This commit is contained in:
committed by
Android (Google) Code Review
commit
19196aff5c
@@ -3373,6 +3373,11 @@ public abstract class BatteryStats implements Parcelable {
|
||||
|
||||
public abstract Map<String, ? extends Timer> getKernelWakelockStats();
|
||||
|
||||
/**
|
||||
* Returns aggregated wake lock stats.
|
||||
*/
|
||||
public abstract WakeLockStats getWakeLockStats();
|
||||
|
||||
/**
|
||||
* Returns Timers tracking the total time of each Resource Power Manager state and voter.
|
||||
*/
|
||||
|
||||
@@ -157,6 +157,7 @@ public final class BatteryStatsManager {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface WifiSupplState {}
|
||||
|
||||
|
||||
private final IBatteryStats mBatteryStats;
|
||||
|
||||
/** @hide */
|
||||
@@ -351,6 +352,21 @@ public final class BatteryStatsManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves accumulate wake lock stats.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.BATTERY_STATS)
|
||||
@NonNull
|
||||
public WakeLockStats getWakeLockStats() {
|
||||
try {
|
||||
return mBatteryStats.getWakeLockStats();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates an app acquiring full wifi lock.
|
||||
*
|
||||
|
||||
20
core/java/android/os/WakeLockStats.aidl
Normal file
20
core/java/android/os/WakeLockStats.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.os;
|
||||
|
||||
/** {@hide} */
|
||||
parcelable WakeLockStats;
|
||||
131
core/java/android/os/WakeLockStats.java
Normal file
131
core/java/android/os/WakeLockStats.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Snapshot of wake lock stats.
|
||||
* @hide
|
||||
*/
|
||||
public final class WakeLockStats implements Parcelable {
|
||||
|
||||
/** @hide */
|
||||
public static class WakeLock {
|
||||
public final int uid;
|
||||
@NonNull
|
||||
public final String name;
|
||||
public final int timesAcquired;
|
||||
public final long totalTimeHeldMs;
|
||||
|
||||
/**
|
||||
* Time in milliseconds that the lock has been held or 0 if not currently holding the lock
|
||||
*/
|
||||
public final long timeHeldMs;
|
||||
|
||||
public WakeLock(int uid, @NonNull String name, int timesAcquired, long totalTimeHeldMs,
|
||||
long timeHeldMs) {
|
||||
this.uid = uid;
|
||||
this.name = name;
|
||||
this.timesAcquired = timesAcquired;
|
||||
this.totalTimeHeldMs = totalTimeHeldMs;
|
||||
this.timeHeldMs = timeHeldMs;
|
||||
}
|
||||
|
||||
private WakeLock(Parcel in) {
|
||||
uid = in.readInt();
|
||||
name = in.readString();
|
||||
timesAcquired = in.readInt();
|
||||
totalTimeHeldMs = in.readLong();
|
||||
timeHeldMs = in.readLong();
|
||||
}
|
||||
|
||||
private void writeToParcel(Parcel out) {
|
||||
out.writeInt(uid);
|
||||
out.writeString(name);
|
||||
out.writeInt(timesAcquired);
|
||||
out.writeLong(totalTimeHeldMs);
|
||||
out.writeLong(timeHeldMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WakeLock{"
|
||||
+ "uid=" + uid
|
||||
+ ", name='" + name + '\''
|
||||
+ ", timesAcquired=" + timesAcquired
|
||||
+ ", totalTimeHeldMs=" + totalTimeHeldMs
|
||||
+ ", timeHeldMs=" + timeHeldMs
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
||||
private final List<WakeLock> mWakeLocks;
|
||||
|
||||
/** @hide **/
|
||||
public WakeLockStats(@NonNull List<WakeLock> wakeLocks) {
|
||||
mWakeLocks = wakeLocks;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<WakeLock> getWakeLocks() {
|
||||
return mWakeLocks;
|
||||
}
|
||||
|
||||
private WakeLockStats(Parcel in) {
|
||||
final int size = in.readInt();
|
||||
mWakeLocks = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
mWakeLocks.add(new WakeLock(in));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel out, int flags) {
|
||||
final int size = mWakeLocks.size();
|
||||
out.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
WakeLock stats = mWakeLocks.get(i);
|
||||
stats.writeToParcel(out);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<WakeLockStats> CREATOR =
|
||||
new Creator<WakeLockStats>() {
|
||||
public WakeLockStats createFromParcel(Parcel in) {
|
||||
return new WakeLockStats(in);
|
||||
}
|
||||
|
||||
public WakeLockStats[] newArray(int size) {
|
||||
return new WakeLockStats[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WakeLockStats " + mWakeLocks;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import android.bluetooth.BluetoothActivityEnergyInfo;
|
||||
import android.os.BatteryUsageStats;
|
||||
import android.os.BatteryUsageStatsQuery;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.WakeLockStats;
|
||||
import android.os.WorkSource;
|
||||
import android.os.connectivity.CellularBatteryStats;
|
||||
import android.os.connectivity.WifiActivityEnergyInfo;
|
||||
@@ -157,6 +158,10 @@ interface IBatteryStats {
|
||||
/** {@hide} */
|
||||
GpsBatteryStats getGpsBatteryStats();
|
||||
|
||||
/** {@hide} */
|
||||
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BATTERY_STATS)")
|
||||
WakeLockStats getWakeLockStats();
|
||||
|
||||
HealthStatsParceler takeUidSnapshot(int uid);
|
||||
HealthStatsParceler[] takeUidSnapshots(in int[] uid);
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.os.WakeLockStats;
|
||||
import android.os.WorkSource;
|
||||
import android.os.WorkSource.WorkChain;
|
||||
import android.os.connectivity.CellularBatteryStats;
|
||||
@@ -1143,6 +1144,37 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return mKernelWakelockStats;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WakeLockStats getWakeLockStats() {
|
||||
final long realtimeMs = mClock.elapsedRealtime();
|
||||
final long realtimeUs = realtimeMs * 1000;
|
||||
List<WakeLockStats.WakeLock> uidWakeLockStats = new ArrayList<>();
|
||||
for (int i = mUidStats.size() - 1; i >= 0; i--) {
|
||||
final Uid uid = mUidStats.valueAt(i);
|
||||
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
|
||||
uid.mWakelockStats.getMap();
|
||||
for (int j = wakelockStats.size() - 1; j >= 0; j--) {
|
||||
final String name = wakelockStats.keyAt(j);
|
||||
final Uid.Wakelock wakelock = (Uid.Wakelock) wakelockStats.valueAt(j);
|
||||
final DualTimer timer = wakelock.mTimerPartial;
|
||||
if (timer != null) {
|
||||
final long totalTimeLockHeldMs =
|
||||
timer.getTotalTimeLocked(realtimeUs, STATS_SINCE_CHARGED) / 1000;
|
||||
if (totalTimeLockHeldMs != 0) {
|
||||
uidWakeLockStats.add(
|
||||
new WakeLockStats.WakeLock(uid.getUid(), name,
|
||||
timer.getCountLocked(STATS_SINCE_CHARGED),
|
||||
totalTimeLockHeldMs,
|
||||
timer.isRunningLocked()
|
||||
? timer.getCurrentDurationMsLocked(realtimeMs)
|
||||
: 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new WakeLockStats(uidWakeLockStats);
|
||||
}
|
||||
|
||||
String mLastWakeupReason = null;
|
||||
long mLastWakeupUptimeMs = 0;
|
||||
private final HashMap<String, SamplingTimer> mWakeupReasonStats = new HashMap<>();
|
||||
|
||||
@@ -22,6 +22,8 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_CACHED;
|
||||
import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
|
||||
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -36,6 +38,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.WakeLockStats;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Display;
|
||||
|
||||
@@ -50,6 +53,8 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SuppressWarnings("GuardedBy")
|
||||
@@ -507,4 +512,51 @@ public class BatteryStatsImplTest {
|
||||
final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(parentUid);
|
||||
u.addIsolatedUid(childUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetWakeLockStats() {
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
|
||||
// First wakelock, acquired once, not currently held
|
||||
mMockClock.realtime = 1000;
|
||||
mBatteryStatsImpl.noteStartWakeLocked(10100, 100, null, "wakeLock1", null,
|
||||
BatteryStats.WAKE_TYPE_PARTIAL, false);
|
||||
|
||||
mMockClock.realtime = 3000;
|
||||
mBatteryStatsImpl.noteStopWakeLocked(10100, 100, null, "wakeLock1", null,
|
||||
BatteryStats.WAKE_TYPE_PARTIAL);
|
||||
|
||||
// Second wakelock, acquired twice, still held
|
||||
mMockClock.realtime = 4000;
|
||||
mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null,
|
||||
BatteryStats.WAKE_TYPE_PARTIAL, false);
|
||||
|
||||
mMockClock.realtime = 5000;
|
||||
mBatteryStatsImpl.noteStopWakeLocked(10200, 101, null, "wakeLock2", null,
|
||||
BatteryStats.WAKE_TYPE_PARTIAL);
|
||||
|
||||
mMockClock.realtime = 6000;
|
||||
mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null,
|
||||
BatteryStats.WAKE_TYPE_PARTIAL, false);
|
||||
|
||||
mMockClock.realtime = 9000;
|
||||
|
||||
List<WakeLockStats.WakeLock> wakeLockStats =
|
||||
mBatteryStatsImpl.getWakeLockStats().getWakeLocks();
|
||||
assertThat(wakeLockStats).hasSize(2);
|
||||
|
||||
WakeLockStats.WakeLock wakeLock1 = wakeLockStats.stream()
|
||||
.filter(wl -> wl.uid == 10100 && wl.name.equals("wakeLock1")).findFirst().get();
|
||||
|
||||
assertThat(wakeLock1.timesAcquired).isEqualTo(1);
|
||||
assertThat(wakeLock1.timeHeldMs).isEqualTo(0); // Not currently held
|
||||
assertThat(wakeLock1.totalTimeHeldMs).isEqualTo(2000); // 3000-1000
|
||||
|
||||
WakeLockStats.WakeLock wakeLock2 = wakeLockStats.stream()
|
||||
.filter(wl -> wl.uid == 10200 && wl.name.equals("wakeLock2")).findFirst().get();
|
||||
|
||||
assertThat(wakeLock2.timesAcquired).isEqualTo(2);
|
||||
assertThat(wakeLock2.timeHeldMs).isEqualTo(3000); // 9000-6000
|
||||
assertThat(wakeLock2.totalTimeHeldMs).isEqualTo(4000); // (5000-4000) + (9000-6000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.os.WakeLockStats;
|
||||
import android.os.WorkSource;
|
||||
import android.os.connectivity.CellularBatteryStats;
|
||||
import android.os.connectivity.GpsBatteryStats;
|
||||
@@ -2595,6 +2596,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a snapshot of wake lock stats
|
||||
* @hide
|
||||
*/
|
||||
public WakeLockStats getWakeLockStats() {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BATTERY_STATS, null);
|
||||
|
||||
// Wait for the completion of pending works if there is any
|
||||
awaitCompletion();
|
||||
synchronized (mStats) {
|
||||
return mStats.getWakeLockStats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a snapshot of the system health for a particular uid.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user