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 import android.util.proto.ProtoOutputStream;
21 
22 import com.android.modules.utils.TypedXmlPullParser;
23 import com.android.modules.utils.TypedXmlSerializer;
24 
25 import org.xmlpull.v1.XmlPullParser;
26 import org.xmlpull.v1.XmlPullParserException;
27 
28 import java.io.IOException;
29 import java.io.PrintWriter;
30 
31 /**
32  * Contains power consumption data across the entire device.
33  *
34  * {@hide}
35  */
36 public final class AggregateBatteryConsumer extends BatteryConsumer {
37     static final int CONSUMER_TYPE_AGGREGATE = 0;
38 
39     static final int COLUMN_INDEX_SCOPE = BatteryConsumer.COLUMN_COUNT;
40     static final int COLUMN_INDEX_CONSUMED_POWER = COLUMN_INDEX_SCOPE + 1;
41     static final int COLUMN_COUNT = BatteryConsumer.COLUMN_COUNT + 2;
42 
AggregateBatteryConsumer(BatteryConsumerData data)43     AggregateBatteryConsumer(BatteryConsumerData data) {
44         super(data);
45     }
46 
AggregateBatteryConsumer(@onNull Builder builder)47     private AggregateBatteryConsumer(@NonNull Builder builder) {
48         super(builder.mData, builder.mPowerComponentsBuilder.build());
49     }
50 
getScope()51     int getScope() {
52         return mData.getInt(COLUMN_INDEX_SCOPE);
53     }
54 
55     @Override
dump(PrintWriter pw, boolean skipEmptyComponents)56     public void dump(PrintWriter pw, boolean skipEmptyComponents) {
57         mPowerComponents.dump(pw, skipEmptyComponents);
58     }
59 
60     @Override
getConsumedPower()61     public double getConsumedPower() {
62         return mData.getDouble(COLUMN_INDEX_CONSUMED_POWER);
63     }
64 
65     /** Serializes this object to XML */
writeToXml(TypedXmlSerializer serializer, @BatteryUsageStats.AggregateBatteryConsumerScope int scope)66     void writeToXml(TypedXmlSerializer serializer,
67             @BatteryUsageStats.AggregateBatteryConsumerScope int scope) throws IOException {
68         serializer.startTag(null, BatteryUsageStats.XML_TAG_AGGREGATE);
69         serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_SCOPE, scope);
70         serializer.attributeDouble(null, BatteryUsageStats.XML_ATTR_POWER, getConsumedPower());
71         mPowerComponents.writeToXml(serializer);
72         serializer.endTag(null, BatteryUsageStats.XML_TAG_AGGREGATE);
73     }
74 
75     /** Parses an XML representation and populates the BatteryUsageStats builder */
parseXml(TypedXmlPullParser parser, BatteryUsageStats.Builder builder)76     static void parseXml(TypedXmlPullParser parser, BatteryUsageStats.Builder builder)
77             throws XmlPullParserException, IOException {
78         final int scope = parser.getAttributeInt(null, BatteryUsageStats.XML_ATTR_SCOPE);
79         final Builder consumerBuilder = builder.getAggregateBatteryConsumerBuilder(scope);
80 
81         int eventType = parser.getEventType();
82         if (eventType != XmlPullParser.START_TAG || !parser.getName().equals(
83                 BatteryUsageStats.XML_TAG_AGGREGATE)) {
84             throw new XmlPullParserException("Invalid XML parser state");
85         }
86 
87         consumerBuilder.setConsumedPower(
88                 parser.getAttributeDouble(null, BatteryUsageStats.XML_ATTR_POWER));
89 
90         while (!(eventType == XmlPullParser.END_TAG && parser.getName().equals(
91                 BatteryUsageStats.XML_TAG_AGGREGATE))
92                 && eventType != XmlPullParser.END_DOCUMENT) {
93             if (eventType == XmlPullParser.START_TAG) {
94                 if (parser.getName().equals(BatteryUsageStats.XML_TAG_POWER_COMPONENTS)) {
95                     PowerComponents.parseXml(parser, consumerBuilder.mPowerComponentsBuilder);
96                 }
97             }
98             eventType = parser.next();
99         }
100     }
101 
writePowerComponentModelProto(@onNull ProtoOutputStream proto)102     void writePowerComponentModelProto(@NonNull ProtoOutputStream proto) {
103         for (int i = 0; i < POWER_COMPONENT_COUNT; i++) {
104             final int powerModel = getPowerModel(i);
105             if (powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) continue;
106 
107             final long token = proto.start(BatteryUsageStatsAtomsProto.COMPONENT_MODELS);
108             proto.write(BatteryUsageStatsAtomsProto.PowerComponentModel.COMPONENT, i);
109             proto.write(BatteryUsageStatsAtomsProto.PowerComponentModel.POWER_MODEL,
110                     powerModelToProtoEnum(powerModel));
111             proto.end(token);
112         }
113     }
114 
115     /**
116      * Builder for DeviceBatteryConsumer.
117      */
118     public static final class Builder extends BaseBuilder<AggregateBatteryConsumer.Builder> {
Builder(BatteryConsumer.BatteryConsumerData data, int scope, double minConsumedPowerThreshold)119         public Builder(BatteryConsumer.BatteryConsumerData data, int scope,
120                 double minConsumedPowerThreshold) {
121             super(data, CONSUMER_TYPE_AGGREGATE, minConsumedPowerThreshold);
122             data.putInt(COLUMN_INDEX_SCOPE, scope);
123         }
124 
125         /**
126          * Sets the total power included in this aggregate.
127          */
setConsumedPower(double consumedPowerMah)128         public Builder setConsumedPower(double consumedPowerMah) {
129             mData.putDouble(COLUMN_INDEX_CONSUMED_POWER, consumedPowerMah);
130             return this;
131         }
132 
133         /**
134          * Adds power and usage duration from the supplied AggregateBatteryConsumer.
135          */
add(AggregateBatteryConsumer aggregateBatteryConsumer)136         public void add(AggregateBatteryConsumer aggregateBatteryConsumer) {
137             setConsumedPower(mData.getDouble(COLUMN_INDEX_CONSUMED_POWER)
138                     + aggregateBatteryConsumer.getConsumedPower());
139             mPowerComponentsBuilder.addPowerAndDuration(aggregateBatteryConsumer.mPowerComponents);
140         }
141 
142         /**
143          * Creates a read-only object out of the Builder values.
144          */
145         @NonNull
build()146         public AggregateBatteryConsumer build() {
147             return new AggregateBatteryConsumer(this);
148         }
149     }
150 }
151