1 /* 2 * Copyright (C) 2016 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.wifi; 17 18 import android.os.BatteryStats; 19 import android.os.RemoteException; 20 import android.os.ServiceManager; 21 import android.os.connectivity.WifiBatteryStats; 22 import android.text.format.DateUtils; 23 import android.util.Log; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 import com.android.internal.app.IBatteryStats; 27 import com.android.server.wifi.nano.WifiMetricsProto.WifiPowerStats; 28 import com.android.server.wifi.nano.WifiMetricsProto.WifiRadioUsage; 29 30 import java.io.PrintWriter; 31 import java.text.DecimalFormat; 32 33 /** 34 * WifiPowerMetrics holds the wifi power metrics and converts them to WifiPowerStats proto buf. 35 * This proto buf is included in the Wifi proto buf. 36 */ 37 public class WifiPowerMetrics { 38 39 private static final String TAG = "WifiPowerMetrics"; 40 41 /* BatteryStats API */ 42 private final IBatteryStats mBatteryStats; 43 WifiPowerMetrics()44 public WifiPowerMetrics() { 45 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 46 BatteryStats.SERVICE_NAME)); 47 } 48 49 // This constructor injects IBatteryStats and should be used for testing only. 50 @VisibleForTesting WifiPowerMetrics(IBatteryStats batteryStats)51 public WifiPowerMetrics(IBatteryStats batteryStats) { 52 mBatteryStats = batteryStats; 53 } 54 55 /** 56 * Build WifiPowerStats proto 57 * A snapshot of Wifi statistics in Batterystats is obtained. Due to reboots multiple correlated 58 * logs may be uploaded in a day. Resolution is on the server side. The log with longest 59 * duration is picked. 60 * @return WifiPowerStats 61 */ buildProto()62 public WifiPowerStats buildProto() { 63 WifiPowerStats m = new WifiPowerStats(); 64 WifiBatteryStats stats = getStats(); 65 if (stats != null) { 66 m.loggingDurationMs = stats.getLoggingDurationMs(); 67 m.energyConsumedMah = stats.getEnergyConsumedMaMs() 68 / ((double) DateUtils.HOUR_IN_MILLIS); 69 m.idleTimeMs = stats.getIdleTimeMs(); 70 m.rxTimeMs = stats.getRxTimeMs(); 71 m.txTimeMs = stats.getTxTimeMs(); 72 m.wifiKernelActiveTimeMs = stats.getKernelActiveTimeMs(); 73 m.numPacketsTx = stats.getNumPacketsTx(); 74 m.numBytesTx = stats.getNumBytesTx(); 75 m.numPacketsRx = stats.getNumPacketsRx(); 76 m.numBytesRx = stats.getNumPacketsRx(); 77 m.sleepTimeMs = stats.getSleepTimeMs(); 78 m.scanTimeMs = stats.getScanTimeMs(); 79 m.monitoredRailEnergyConsumedMah = stats.getMonitoredRailChargeConsumedMaMs() 80 / ((double) DateUtils.HOUR_IN_MILLIS); 81 } 82 return m; 83 } 84 85 /** 86 * Build WifiRadioUsage proto 87 * A snapshot of Wifi statistics in Batterystats is obtained. Due to reboots multiple correlated 88 * logs may be uploaded in a day. Server side should analyze based the ratio of collected 89 * properties over the total logging duration (ie. |scanTimeMs| / |loggingDurationMs|) 90 * 91 * This proto contains additional wifi usage data that are not directly related to power 92 * calculations. 93 * @return WifiRadioUsage 94 */ buildWifiRadioUsageProto()95 public WifiRadioUsage buildWifiRadioUsageProto() { 96 WifiRadioUsage m = new WifiRadioUsage(); 97 WifiBatteryStats stats = getStats(); 98 if (stats != null) { 99 m.loggingDurationMs = stats.getLoggingDurationMs(); 100 m.scanTimeMs = stats.getScanTimeMs(); 101 } 102 return m; 103 } 104 105 /** 106 * Dump all WifiPowerStats to console (pw) 107 * @param pw 108 */ dump(PrintWriter pw)109 public void dump(PrintWriter pw) { 110 WifiPowerStats s = buildProto(); 111 if (s!=null) { 112 pw.println("Wifi power metrics:"); 113 pw.println("Logging duration (time on battery): " + s.loggingDurationMs); 114 pw.println("Energy consumed by wifi (mAh): " + s.energyConsumedMah); 115 pw.println("Amount of time wifi is in idle (ms): " + s.idleTimeMs); 116 pw.println("Amount of time wifi is in rx (ms): " + s.rxTimeMs); 117 pw.println("Amount of time wifi is in tx (ms): " + s.txTimeMs); 118 pw.println("Amount of time kernel is active because of wifi data (ms): " 119 + s.wifiKernelActiveTimeMs); 120 pw.println("Amount of time wifi is in sleep (ms): " + s.sleepTimeMs); 121 pw.println("Amount of time wifi is scanning (ms): " + s.scanTimeMs); 122 pw.println("Number of packets sent (tx): " + s.numPacketsTx); 123 pw.println("Number of bytes sent (tx): " + s.numBytesTx); 124 pw.println("Number of packets received (rx): " + s.numPacketsRx); 125 pw.println("Number of bytes sent (rx): " + s.numBytesRx); 126 pw.println("Energy consumed across measured wifi rails (mAh): " 127 + new DecimalFormat("#.##").format(s.monitoredRailEnergyConsumedMah)); 128 } 129 WifiRadioUsage wifiRadioUsage = buildWifiRadioUsageProto(); 130 pw.println("Wifi radio usage metrics:"); 131 pw.println("Logging duration (time on battery): " + wifiRadioUsage.loggingDurationMs); 132 pw.println("Amount of time wifi is in scan mode while on battery (ms): " 133 + wifiRadioUsage.scanTimeMs); 134 } 135 136 /** 137 * Get wifi stats from batterystats 138 * @return WifiBatteryStats 139 */ getStats()140 private WifiBatteryStats getStats() { 141 try { 142 return mBatteryStats.getWifiBatteryStats(); 143 } catch (RemoteException e) { 144 Log.e(TAG, "Unable to obtain Wifi power stats from BatteryStats"); 145 } 146 return null; 147 } 148 } 149