• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.power.stats;
17 
18 import android.annotation.Nullable;
19 import android.os.BatteryConsumer;
20 import android.os.Handler;
21 import android.os.PersistableBundle;
22 import android.util.SparseLongArray;
23 
24 import com.android.internal.os.Clock;
25 import com.android.internal.os.PowerStats;
26 import com.android.server.power.stats.format.WakelockPowerStatsLayout;
27 
28 import java.util.Arrays;
29 
30 class WakelockPowerStatsCollector extends PowerStatsCollector {
31 
32     public interface WakelockDurationRetriever {
33         interface Callback {
onUidWakelockDuration(int uid, long wakelockDurationMs)34             void onUidWakelockDuration(int uid, long wakelockDurationMs);
35         }
36 
getWakelockDurationMillis()37         long getWakelockDurationMillis();
retrieveUidWakelockDuration(Callback callback)38         void retrieveUidWakelockDuration(Callback callback);
39     }
40 
41     public interface Injector {
getHandler()42         Handler getHandler();
getClock()43         Clock getClock();
getUidResolver()44         PowerStatsUidResolver getUidResolver();
getPowerStatsCollectionThrottlePeriod(String powerComponentName)45         long getPowerStatsCollectionThrottlePeriod(String powerComponentName);
getWakelockDurationRetriever()46         WakelockDurationRetriever getWakelockDurationRetriever();
47     }
48 
49     private final WakelockDurationRetriever mWakelockDurationRetriever;
50     private WakelockPowerStatsLayout mStatsLayout;
51     private PowerStats.Descriptor mDescriptor;
52     private PowerStats mPowerStats;
53     private boolean mIsInitialized;
54     private boolean mFirstCollection = true;
55     private long mLastCollectionTime;
56     private long mLastWakelockDurationMs;
57     private final SparseLongArray mLastUidWakelockDurations = new SparseLongArray();
58 
WakelockPowerStatsCollector(Injector injector)59     WakelockPowerStatsCollector(Injector injector) {
60         super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod(
61                         BatteryConsumer.powerComponentIdToString(
62                                 BatteryConsumer.POWER_COMPONENT_WAKELOCK)),
63                 injector.getUidResolver(), injector.getClock());
64         mWakelockDurationRetriever = injector.getWakelockDurationRetriever();
65     }
66 
ensureInitialized()67     private boolean ensureInitialized() {
68         if (mIsInitialized) {
69             return true;
70         }
71 
72         if (!isEnabled()) {
73             return false;
74         }
75 
76         mStatsLayout = new WakelockPowerStatsLayout();
77         PersistableBundle extras = new PersistableBundle();
78         mStatsLayout.toExtras(extras);
79         mDescriptor = new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_WAKELOCK,
80                 mStatsLayout.getDeviceStatsArrayLength(), null, 0,
81                 mStatsLayout.getUidStatsArrayLength(), extras);
82         mPowerStats = new PowerStats(mDescriptor);
83         mIsInitialized = true;
84         return true;
85     }
86 
87     @Nullable
88     @Override
collectStats()89     protected PowerStats collectStats() {
90         if (!ensureInitialized()) {
91             return null;
92         }
93 
94         Arrays.fill(mPowerStats.stats, 0);
95         mPowerStats.uidStats.clear();
96 
97         long elapsedRealtime = mClock.elapsedRealtime();
98         mPowerStats.durationMs = elapsedRealtime - mLastCollectionTime;
99 
100         long wakelockDurationMillis = mWakelockDurationRetriever.getWakelockDurationMillis();
101 
102         if (!mFirstCollection) {
103             mStatsLayout.setUsageDuration(mPowerStats.stats,
104                     Math.max(0, wakelockDurationMillis - mLastWakelockDurationMs));
105         }
106 
107         mLastWakelockDurationMs = wakelockDurationMillis;
108 
109         mWakelockDurationRetriever.retrieveUidWakelockDuration((uid, durationMs) -> {
110             if (!mFirstCollection) {
111                 long diffMs = Math.max(0, durationMs - mLastUidWakelockDurations.get(uid));
112                 if (diffMs != 0) {
113                     long[] uidStats = mPowerStats.uidStats.get(uid);
114                     if (uidStats == null) {
115                         uidStats = new long[mDescriptor.uidStatsArrayLength];
116                         mPowerStats.uidStats.put(uid, uidStats);
117                     }
118 
119                     mStatsLayout.setUidUsageDuration(uidStats, diffMs);
120                 }
121             }
122             mLastUidWakelockDurations.put(uid, durationMs);
123         });
124 
125         mLastCollectionTime = elapsedRealtime;
126         mFirstCollection = false;
127 
128         return mPowerStats;
129     }
130 }
131