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"}, true, false, 0) 163 .setBatteryCapacity(4000) 164 .setDischargePercentage(20) 165 .setDischargedPowerRange(1000, 2000) 166 .setStatsStartTimestamp(1000) 167 .setStatsEndTimestamp(3000); 168 169 builder.getAggregateBatteryConsumerBuilder( 170 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) 171 .setConsumedPower(123) 172 .setConsumedPower( 173 BatteryConsumer.POWER_COMPONENT_CPU, 10100) 174 .setConsumedPowerForCustomComponent( 175 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200) 176 .setUsageDurationMillis( 177 BatteryConsumer.POWER_COMPONENT_CPU, 10300) 178 .setUsageDurationForCustomComponentMillis( 179 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10400); 180 181 for (int i = 0; i < 1000; i++) { 182 final UidBatteryConsumer.Builder consumerBuilder = 183 builder.getOrCreateUidBatteryConsumerBuilder(i) 184 .setPackageWithHighestDrain("example.packagename" + i) 185 .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, i * 2000) 186 .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, i * 1000); 187 for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT; 188 componentId++) { 189 consumerBuilder.setConsumedPower(componentId, componentId * 123.0, 190 BatteryConsumer.POWER_MODEL_POWER_PROFILE); 191 consumerBuilder.setUsageDurationMillis(componentId, componentId * 1000); 192 } 193 194 consumerBuilder.setConsumedPowerForCustomComponent( 195 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 1234) 196 .setUsageDurationForCustomComponentMillis( 197 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 4321); 198 } 199 return builder.build(); 200 } 201 } 202