• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 com.android.internal.os;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import android.app.Service;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.ServiceConnection;
26 import android.os.BatteryConsumer;
27 import android.os.BatteryStatsManager;
28 import android.os.BatteryUsageStats;
29 import android.os.BatteryUsageStatsQuery;
30 import android.os.Binder;
31 import android.os.ConditionVariable;
32 import android.os.IBinder;
33 import android.os.Parcel;
34 import android.os.UidBatteryConsumer;
35 import android.perftests.utils.BenchmarkState;
36 import android.perftests.utils.PerfStatusReporter;
37 
38 import androidx.annotation.NonNull;
39 import androidx.annotation.Nullable;
40 import androidx.test.InstrumentationRegistry;
41 import androidx.test.filters.LargeTest;
42 import androidx.test.runner.AndroidJUnit4;
43 
44 import org.junit.Rule;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 
48 import java.util.List;
49 
50 @RunWith(AndroidJUnit4.class)
51 @LargeTest
52 public class BatteryUsageStatsPerfTest {
53 
54     @Rule
55     public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
56 
57     /**
58      * Measures the performance of {@link BatteryStatsManager#getBatteryUsageStats()},
59      * which triggers a battery stats sync on every iteration.
60      */
61     @Test
testGetBatteryUsageStats()62     public void testGetBatteryUsageStats() {
63         final Context context = InstrumentationRegistry.getContext();
64         final BatteryStatsManager batteryStatsManager =
65                 context.getSystemService(BatteryStatsManager.class);
66 
67         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
68         while (state.keepRunning()) {
69             BatteryUsageStats batteryUsageStats = batteryStatsManager.getBatteryUsageStats(
70                     new BatteryUsageStatsQuery.Builder().setMaxStatsAgeMs(0).build());
71 
72             state.pauseTiming();
73 
74             List<UidBatteryConsumer> uidBatteryConsumers =
75                     batteryUsageStats.getUidBatteryConsumers();
76             double power = 0;
77             for (int i = 0; i < uidBatteryConsumers.size(); i++) {
78                 UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(i);
79                 power += uidBatteryConsumer.getConsumedPower();
80             }
81 
82             assertThat(power).isGreaterThan(0.0);
83 
84             state.resumeTiming();
85         }
86     }
87 
88     private final ConditionVariable mServiceConnected = new ConditionVariable();
89     private IBinder mService;
90 
91     private final ServiceConnection mConnection = new ServiceConnection() {
92         public void onServiceConnected(ComponentName name, IBinder service) {
93             mService = service;
94             mServiceConnected.open();
95         }
96 
97         public void onServiceDisconnected(ComponentName name) {
98             mService = null;
99         }
100     };
101 
102     /**
103      * Measures the performance of transferring BatteryUsageStats over a Binder.
104      */
105     @Test
testBatteryUsageStatsTransferOverBinder()106     public void testBatteryUsageStatsTransferOverBinder() throws Exception {
107         final Context context = InstrumentationRegistry.getContext();
108         context.bindService(
109                 new Intent(context, BatteryUsageStatsService.class),
110                 mConnection, Context.BIND_AUTO_CREATE);
111         mServiceConnected.block(30000);
112         assertThat(mService).isNotNull();
113 
114         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
115         while (state.keepRunning()) {
116             final Parcel data = Parcel.obtain();
117             final Parcel reply = Parcel.obtain();
118             mService.transact(42, data, reply, 0);
119             final BatteryUsageStats batteryUsageStats =
120                     BatteryUsageStats.CREATOR.createFromParcel(reply);
121             reply.recycle();
122             data.recycle();
123 
124             state.pauseTiming();
125 
126             assertThat(batteryUsageStats.getBatteryCapacity()).isEqualTo(4000);
127             assertThat(batteryUsageStats.getUidBatteryConsumers()).hasSize(1000);
128             final UidBatteryConsumer uidBatteryConsumer =
129                     batteryUsageStats.getUidBatteryConsumers().get(0);
130             assertThat(uidBatteryConsumer.getConsumedPower(1)).isEqualTo(123);
131 
132             state.resumeTiming();
133         }
134 
135         context.unbindService(mConnection);
136     }
137 
138     /* This service runs in a separate process */
139     public static class BatteryUsageStatsService extends Service {
140         private final BatteryUsageStats mBatteryUsageStats;
141 
BatteryUsageStatsService()142         public BatteryUsageStatsService() {
143             mBatteryUsageStats = buildBatteryUsageStats();
144         }
145 
146         @Nullable
147         @Override
onBind(Intent intent)148         public IBinder onBind(Intent intent) {
149             return new Binder() {
150                 @Override
151                 protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
152                         int flags) {
153                     mBatteryUsageStats.writeToParcel(reply, 0);
154                     return true;
155                 }
156             };
157         }
158     }
159 
160     private static BatteryUsageStats buildBatteryUsageStats() {
161         final BatteryUsageStats.Builder builder =
162                 new BatteryUsageStats.Builder(new String[]{"FOO"}, false, false, false, 0)
163                         .setBatteryCapacity(4000)
164                         .addDischargePercentage(20)
165                         .addDischargedPowerRange(1000, 2000)
166                         .setStatsStartTimestamp(1000)
167                         .setStatsEndTimestamp(3000);
168 
169         builder.getAggregateBatteryConsumerBuilder(
170                 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
171                 .addConsumedPower(123)
172                 .addConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 10100)
173                 .addConsumedPower(BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200)
174                 .addUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU, 10300)
175                 .addUsageDurationMillis(BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10400);
176 
177         for (int i = 0; i < 1000; i++) {
178             final UidBatteryConsumer.Builder consumerBuilder =
179                     builder.getOrCreateUidBatteryConsumerBuilder(i)
180                             .setPackageWithHighestDrain("example.packagename" + i)
181                             .setTimeInProcessStateMs(UidBatteryConsumer.STATE_FOREGROUND, i * 2000)
182                             .setTimeInProcessStateMs(UidBatteryConsumer.STATE_BACKGROUND, i * 1000);
183             for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
184                     componentId++) {
185                 consumerBuilder.addConsumedPower(componentId, componentId * 123.0);
186                 consumerBuilder.addUsageDurationMillis(componentId, componentId * 1000);
187             }
188 
189             consumerBuilder
190                     .addConsumedPower(BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 1234)
191                     .addUsageDurationMillis(BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 4321);
192         }
193         return builder.build();
194     }
195 }
196