1 /*
2  * Copyright (C) 2021 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 
17 package android.os;
18 
19 import android.annotation.NonNull;
20 
21 import com.android.modules.utils.TypedXmlPullParser;
22 import com.android.modules.utils.TypedXmlSerializer;
23 
24 import org.xmlpull.v1.XmlPullParser;
25 import org.xmlpull.v1.XmlPullParserException;
26 
27 import java.io.IOException;
28 import java.io.PrintWriter;
29 import java.util.ArrayList;
30 import java.util.List;
31 
32 /**
33  * Contains power consumption data attributed to a {@link UserHandle}.
34  *
35  * {@hide}
36  */
37 @android.ravenwood.annotation.RavenwoodKeepWholeClass
38 public class UserBatteryConsumer extends BatteryConsumer {
39     static final int CONSUMER_TYPE_USER = 2;
40 
41     private static final int COLUMN_INDEX_USER_ID = BatteryConsumer.COLUMN_COUNT;
42 
43     static final int COLUMN_COUNT = BatteryConsumer.COLUMN_COUNT + 1;
44 
UserBatteryConsumer(BatteryConsumerData data)45     UserBatteryConsumer(BatteryConsumerData data) {
46         super(data);
47     }
48 
UserBatteryConsumer(@onNull UserBatteryConsumer.Builder builder)49     private UserBatteryConsumer(@NonNull UserBatteryConsumer.Builder builder) {
50         super(builder.mData, builder.mPowerComponentsBuilder.build());
51     }
52 
getUserId()53     public int getUserId() {
54         return mData.getInt(COLUMN_INDEX_USER_ID);
55     }
56 
57     @Override
dump(PrintWriter pw, boolean skipEmptyComponents)58     public void dump(PrintWriter pw, boolean skipEmptyComponents) {
59         final double consumedPower = getConsumedPower();
60         pw.print("User ");
61         pw.print(getUserId());
62         pw.print(": ");
63         pw.print(BatteryStats.formatCharge(consumedPower));
64         pw.print(" ( ");
65         mPowerComponents.dump(pw, skipEmptyComponents  /* skipTotalPowerComponent */);
66         pw.print(" ) ");
67     }
68 
69     /** Serializes this object to XML */
writeToXml(TypedXmlSerializer serializer)70     void writeToXml(TypedXmlSerializer serializer) throws IOException {
71         if (getConsumedPower() == 0) {
72             return;
73         }
74 
75         serializer.startTag(null, BatteryUsageStats.XML_TAG_USER);
76         serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_USER_ID, getUserId());
77         mPowerComponents.writeToXml(serializer);
78         serializer.endTag(null, BatteryUsageStats.XML_TAG_USER);
79     }
80 
81     /** Parses an XML representation and populates the BatteryUsageStats builder */
createFromXml(TypedXmlPullParser parser, BatteryUsageStats.Builder builder)82     static void createFromXml(TypedXmlPullParser parser, BatteryUsageStats.Builder builder)
83             throws XmlPullParserException, IOException {
84         final int userId = parser.getAttributeInt(null, BatteryUsageStats.XML_ATTR_USER_ID);
85         final UserBatteryConsumer.Builder consumerBuilder =
86                 builder.getOrCreateUserBatteryConsumerBuilder(userId);
87 
88         int eventType = parser.getEventType();
89         if (eventType != XmlPullParser.START_TAG
90                 || !parser.getName().equals(BatteryUsageStats.XML_TAG_USER)) {
91             throw new XmlPullParserException("Invalid XML parser state");
92         }
93         while (!(eventType == XmlPullParser.END_TAG
94                 && parser.getName().equals(BatteryUsageStats.XML_TAG_USER))
95                 && eventType != XmlPullParser.END_DOCUMENT) {
96             if (eventType == XmlPullParser.START_TAG) {
97                 if (parser.getName().equals(BatteryUsageStats.XML_TAG_POWER_COMPONENTS)) {
98                     PowerComponents.parseXml(parser, consumerBuilder.mPowerComponentsBuilder);
99                 }
100             }
101             eventType = parser.next();
102         }
103     }
104 
105     /**
106      * Builder for UserBatteryConsumer.
107      */
108     public static final class Builder extends BaseBuilder<Builder> {
109         private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
110 
Builder(BatteryConsumerData data, int userId, double minConsumedPowerThreshold)111         Builder(BatteryConsumerData data, int userId, double minConsumedPowerThreshold) {
112             super(data, CONSUMER_TYPE_USER, minConsumedPowerThreshold);
113             data.putLong(COLUMN_INDEX_USER_ID, userId);
114         }
115 
116         /**
117          * Add a UidBatteryConsumer to this UserBatteryConsumer.
118          * <p>
119          * Calculated power and duration components of the added UID battery consumers
120          * are aggregated at the time the UserBatteryConsumer is built by the {@link #build()}
121          * method.
122          * </p>
123          */
addUidBatteryConsumer(UidBatteryConsumer.Builder uidBatteryConsumerBuilder)124         public void addUidBatteryConsumer(UidBatteryConsumer.Builder uidBatteryConsumerBuilder) {
125             if (mUidBatteryConsumers == null) {
126                 mUidBatteryConsumers = new ArrayList<>();
127             }
128             mUidBatteryConsumers.add(uidBatteryConsumerBuilder);
129         }
130 
131         /**
132          * Creates a read-only object out of the Builder values.
133          */
134         @NonNull
build()135         public UserBatteryConsumer build() {
136             if (mUidBatteryConsumers != null) {
137                 for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) {
138                     UidBatteryConsumer.Builder uidBatteryConsumer = mUidBatteryConsumers.get(i);
139                     mPowerComponentsBuilder.addPowerAndDuration(
140                             uidBatteryConsumer.mPowerComponentsBuilder);
141                 }
142             }
143             return new UserBatteryConsumer(this);
144         }
145     }
146 }
147