1 /* 2 * Copyright (C) 2006-2007 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.server.am; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.bluetooth.BluetoothHeadset; 21 import android.bluetooth.BluetoothProfile; 22 import android.content.Context; 23 import android.content.pm.ApplicationInfo; 24 import android.content.pm.PackageManager; 25 import android.os.BatteryStats; 26 import android.os.Binder; 27 import android.os.IBinder; 28 import android.os.Parcel; 29 import android.os.Process; 30 import android.os.ServiceManager; 31 import android.os.UserHandle; 32 import android.os.WorkSource; 33 import android.telephony.SignalStrength; 34 import android.telephony.TelephonyManager; 35 import android.util.Slog; 36 37 import com.android.internal.app.IBatteryStats; 38 import com.android.internal.os.BatteryStatsImpl; 39 import com.android.internal.os.PowerProfile; 40 41 import java.io.FileDescriptor; 42 import java.io.PrintWriter; 43 import java.util.List; 44 45 /** 46 * All information we are collecting about things that can happen that impact 47 * battery life. 48 */ 49 public final class BatteryStatsService extends IBatteryStats.Stub { 50 static IBatteryStats sService; 51 52 final BatteryStatsImpl mStats; 53 Context mContext; 54 private boolean mBluetoothPendingStats; 55 private BluetoothHeadset mBluetoothHeadset; 56 57 BatteryStatsService(String filename) { 58 mStats = new BatteryStatsImpl(filename); 59 } 60 61 public void publish(Context context) { 62 mContext = context; 63 ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder()); 64 mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps()); 65 mStats.setRadioScanningTimeout(mContext.getResources().getInteger( 66 com.android.internal.R.integer.config_radioScanningTimeout) 67 * 1000L); 68 } 69 70 public void shutdown() { 71 Slog.w("BatteryStats", "Writing battery stats before shutdown..."); 72 synchronized (mStats) { 73 mStats.shutdownLocked(); 74 } 75 } 76 77 public static IBatteryStats getService() { 78 if (sService != null) { 79 return sService; 80 } 81 IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME); 82 sService = asInterface(b); 83 return sService; 84 } 85 86 /** 87 * @return the current statistics object, which may be modified 88 * to reflect events that affect battery usage. You must lock the 89 * stats object before doing anything with it. 90 */ 91 public BatteryStatsImpl getActiveStatistics() { 92 return mStats; 93 } 94 95 public byte[] getStatistics() { 96 mContext.enforceCallingPermission( 97 android.Manifest.permission.BATTERY_STATS, null); 98 //Slog.i("foo", "SENDING BATTERY INFO:"); 99 //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); 100 Parcel out = Parcel.obtain(); 101 mStats.writeToParcel(out, 0); 102 byte[] data = out.marshall(); 103 out.recycle(); 104 return data; 105 } 106 107 public void noteStartWakelock(int uid, int pid, String name, int type) { 108 enforceCallingPermission(); 109 synchronized (mStats) { 110 mStats.noteStartWakeLocked(uid, pid, name, type); 111 } 112 } 113 114 public void noteStopWakelock(int uid, int pid, String name, int type) { 115 enforceCallingPermission(); 116 synchronized (mStats) { 117 mStats.noteStopWakeLocked(uid, pid, name, type); 118 } 119 } 120 121 public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type) { 122 enforceCallingPermission(); 123 synchronized (mStats) { 124 mStats.noteStartWakeFromSourceLocked(ws, pid, name, type); 125 } 126 } 127 128 public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, int type) { 129 enforceCallingPermission(); 130 synchronized (mStats) { 131 mStats.noteStopWakeFromSourceLocked(ws, pid, name, type); 132 } 133 } 134 135 public void noteStartSensor(int uid, int sensor) { 136 enforceCallingPermission(); 137 synchronized (mStats) { 138 mStats.noteStartSensorLocked(uid, sensor); 139 } 140 } 141 142 public void noteStopSensor(int uid, int sensor) { 143 enforceCallingPermission(); 144 synchronized (mStats) { 145 mStats.noteStopSensorLocked(uid, sensor); 146 } 147 } 148 149 public void noteVibratorOn(int uid, long durationMillis) { 150 enforceCallingPermission(); 151 synchronized (mStats) { 152 mStats.noteVibratorOnLocked(uid, durationMillis); 153 } 154 } 155 156 public void noteVibratorOff(int uid) { 157 enforceCallingPermission(); 158 synchronized (mStats) { 159 mStats.noteVibratorOffLocked(uid); 160 } 161 } 162 163 public void noteStartGps(int uid) { 164 enforceCallingPermission(); 165 synchronized (mStats) { 166 mStats.noteStartGpsLocked(uid); 167 } 168 } 169 170 public void noteStopGps(int uid) { 171 enforceCallingPermission(); 172 synchronized (mStats) { 173 mStats.noteStopGpsLocked(uid); 174 } 175 } 176 177 public void noteScreenOn() { 178 enforceCallingPermission(); 179 synchronized (mStats) { 180 mStats.noteScreenOnLocked(); 181 } 182 } 183 184 public void noteScreenBrightness(int brightness) { 185 enforceCallingPermission(); 186 synchronized (mStats) { 187 mStats.noteScreenBrightnessLocked(brightness); 188 } 189 } 190 191 public void noteScreenOff() { 192 enforceCallingPermission(); 193 synchronized (mStats) { 194 mStats.noteScreenOffLocked(); 195 } 196 } 197 198 public void noteInputEvent() { 199 enforceCallingPermission(); 200 mStats.noteInputEventAtomic(); 201 } 202 203 public void noteUserActivity(int uid, int event) { 204 enforceCallingPermission(); 205 synchronized (mStats) { 206 mStats.noteUserActivityLocked(uid, event); 207 } 208 } 209 210 public void notePhoneOn() { 211 enforceCallingPermission(); 212 synchronized (mStats) { 213 mStats.notePhoneOnLocked(); 214 } 215 } 216 217 public void notePhoneOff() { 218 enforceCallingPermission(); 219 synchronized (mStats) { 220 mStats.notePhoneOffLocked(); 221 } 222 } 223 224 public void notePhoneSignalStrength(SignalStrength signalStrength) { 225 enforceCallingPermission(); 226 synchronized (mStats) { 227 mStats.notePhoneSignalStrengthLocked(signalStrength); 228 } 229 } 230 231 public void notePhoneDataConnectionState(int dataType, boolean hasData) { 232 enforceCallingPermission(); 233 synchronized (mStats) { 234 mStats.notePhoneDataConnectionStateLocked(dataType, hasData); 235 } 236 } 237 238 public void notePhoneState(int state) { 239 enforceCallingPermission(); 240 int simState = TelephonyManager.getDefault().getSimState(); 241 synchronized (mStats) { 242 mStats.notePhoneStateLocked(state, simState); 243 } 244 } 245 246 public void noteWifiOn() { 247 enforceCallingPermission(); 248 synchronized (mStats) { 249 mStats.noteWifiOnLocked(); 250 } 251 } 252 253 public void noteWifiOff() { 254 enforceCallingPermission(); 255 synchronized (mStats) { 256 mStats.noteWifiOffLocked(); 257 } 258 } 259 260 public void noteStartAudio(int uid) { 261 enforceCallingPermission(); 262 synchronized (mStats) { 263 mStats.noteAudioOnLocked(uid); 264 } 265 } 266 267 public void noteStopAudio(int uid) { 268 enforceCallingPermission(); 269 synchronized (mStats) { 270 mStats.noteAudioOffLocked(uid); 271 } 272 } 273 274 public void noteStartVideo(int uid) { 275 enforceCallingPermission(); 276 synchronized (mStats) { 277 mStats.noteVideoOnLocked(uid); 278 } 279 } 280 281 public void noteStopVideo(int uid) { 282 enforceCallingPermission(); 283 synchronized (mStats) { 284 mStats.noteVideoOffLocked(uid); 285 } 286 } 287 288 public void noteWifiRunning(WorkSource ws) { 289 enforceCallingPermission(); 290 synchronized (mStats) { 291 mStats.noteWifiRunningLocked(ws); 292 } 293 } 294 295 public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) { 296 enforceCallingPermission(); 297 synchronized (mStats) { 298 mStats.noteWifiRunningChangedLocked(oldWs, newWs); 299 } 300 } 301 302 public void noteWifiStopped(WorkSource ws) { 303 enforceCallingPermission(); 304 synchronized (mStats) { 305 mStats.noteWifiStoppedLocked(ws); 306 } 307 } 308 309 public void noteBluetoothOn() { 310 enforceCallingPermission(); 311 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 312 if (adapter != null) { 313 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 314 BluetoothProfile.HEADSET); 315 } 316 synchronized (mStats) { 317 if (mBluetoothHeadset != null) { 318 mStats.noteBluetoothOnLocked(); 319 mStats.setBtHeadset(mBluetoothHeadset); 320 } else { 321 mBluetoothPendingStats = true; 322 } 323 } 324 } 325 326 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 327 new BluetoothProfile.ServiceListener() { 328 public void onServiceConnected(int profile, BluetoothProfile proxy) { 329 mBluetoothHeadset = (BluetoothHeadset) proxy; 330 synchronized (mStats) { 331 if (mBluetoothPendingStats) { 332 mStats.noteBluetoothOnLocked(); 333 mStats.setBtHeadset(mBluetoothHeadset); 334 mBluetoothPendingStats = false; 335 } 336 } 337 } 338 339 public void onServiceDisconnected(int profile) { 340 mBluetoothHeadset = null; 341 } 342 }; 343 344 public void noteBluetoothOff() { 345 enforceCallingPermission(); 346 synchronized (mStats) { 347 mBluetoothPendingStats = false; 348 mStats.noteBluetoothOffLocked(); 349 } 350 } 351 352 public void noteFullWifiLockAcquired(int uid) { 353 enforceCallingPermission(); 354 synchronized (mStats) { 355 mStats.noteFullWifiLockAcquiredLocked(uid); 356 } 357 } 358 359 public void noteFullWifiLockReleased(int uid) { 360 enforceCallingPermission(); 361 synchronized (mStats) { 362 mStats.noteFullWifiLockReleasedLocked(uid); 363 } 364 } 365 366 public void noteWifiScanStarted(int uid) { 367 enforceCallingPermission(); 368 synchronized (mStats) { 369 mStats.noteWifiScanStartedLocked(uid); 370 } 371 } 372 373 public void noteWifiScanStopped(int uid) { 374 enforceCallingPermission(); 375 synchronized (mStats) { 376 mStats.noteWifiScanStoppedLocked(uid); 377 } 378 } 379 380 public void noteWifiMulticastEnabled(int uid) { 381 enforceCallingPermission(); 382 synchronized (mStats) { 383 mStats.noteWifiMulticastEnabledLocked(uid); 384 } 385 } 386 387 public void noteWifiMulticastDisabled(int uid) { 388 enforceCallingPermission(); 389 synchronized (mStats) { 390 mStats.noteWifiMulticastDisabledLocked(uid); 391 } 392 } 393 394 public void noteFullWifiLockAcquiredFromSource(WorkSource ws) { 395 enforceCallingPermission(); 396 synchronized (mStats) { 397 mStats.noteFullWifiLockAcquiredFromSourceLocked(ws); 398 } 399 } 400 401 public void noteFullWifiLockReleasedFromSource(WorkSource ws) { 402 enforceCallingPermission(); 403 synchronized (mStats) { 404 mStats.noteFullWifiLockReleasedFromSourceLocked(ws); 405 } 406 } 407 408 public void noteWifiScanStartedFromSource(WorkSource ws) { 409 enforceCallingPermission(); 410 synchronized (mStats) { 411 mStats.noteWifiScanStartedFromSourceLocked(ws); 412 } 413 } 414 415 public void noteWifiScanStoppedFromSource(WorkSource ws) { 416 enforceCallingPermission(); 417 synchronized (mStats) { 418 mStats.noteWifiScanStoppedFromSourceLocked(ws); 419 } 420 } 421 422 public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) { 423 enforceCallingPermission(); 424 synchronized (mStats) { 425 mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph); 426 } 427 } 428 429 public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) { 430 enforceCallingPermission(); 431 synchronized (mStats) { 432 mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws); 433 } 434 } 435 436 public void noteWifiMulticastEnabledFromSource(WorkSource ws) { 437 enforceCallingPermission(); 438 synchronized (mStats) { 439 mStats.noteWifiMulticastEnabledFromSourceLocked(ws); 440 } 441 } 442 443 public void noteWifiMulticastDisabledFromSource(WorkSource ws) { 444 enforceCallingPermission(); 445 synchronized (mStats) { 446 mStats.noteWifiMulticastDisabledFromSourceLocked(ws); 447 } 448 } 449 450 @Override 451 public void noteNetworkInterfaceType(String iface, int type) { 452 enforceCallingPermission(); 453 synchronized (mStats) { 454 mStats.noteNetworkInterfaceTypeLocked(iface, type); 455 } 456 } 457 458 @Override 459 public void noteNetworkStatsEnabled() { 460 enforceCallingPermission(); 461 synchronized (mStats) { 462 mStats.noteNetworkStatsEnabledLocked(); 463 } 464 } 465 466 public boolean isOnBattery() { 467 return mStats.isOnBattery(); 468 } 469 470 public void setBatteryState(int status, int health, int plugType, int level, 471 int temp, int volt) { 472 enforceCallingPermission(); 473 mStats.setBatteryState(status, health, plugType, level, temp, volt); 474 } 475 476 public long getAwakeTimeBattery() { 477 mContext.enforceCallingOrSelfPermission( 478 android.Manifest.permission.BATTERY_STATS, null); 479 return mStats.getAwakeTimeBattery(); 480 } 481 482 public long getAwakeTimePlugged() { 483 mContext.enforceCallingOrSelfPermission( 484 android.Manifest.permission.BATTERY_STATS, null); 485 return mStats.getAwakeTimePlugged(); 486 } 487 488 public void enforceCallingPermission() { 489 if (Binder.getCallingPid() == Process.myPid()) { 490 return; 491 } 492 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 493 Binder.getCallingPid(), Binder.getCallingUid(), null); 494 } 495 496 private void dumpHelp(PrintWriter pw) { 497 pw.println("Battery stats (batterystats) dump options:"); 498 pw.println(" [--checkin] [-c] [--unplugged] [--reset] [--write] [-h] [<package.name>]"); 499 pw.println(" --checkin: format output for a checkin report."); 500 pw.println(" --unplugged: only output data since last unplugged."); 501 pw.println(" --reset: reset the stats, clearing all current data."); 502 pw.println(" --write: force write current collected stats to disk."); 503 pw.println(" -h: print this help text."); 504 pw.println(" <package.name>: optional name of package to filter output by."); 505 } 506 507 @Override 508 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 509 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 510 != PackageManager.PERMISSION_GRANTED) { 511 pw.println("Permission Denial: can't dump BatteryStats from from pid=" 512 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 513 + " without permission " + android.Manifest.permission.DUMP); 514 return; 515 } 516 517 boolean isCheckin = false; 518 boolean includeHistory = false; 519 boolean isUnpluggedOnly = false; 520 boolean noOutput = false; 521 int reqUid = -1; 522 if (args != null) { 523 for (String arg : args) { 524 if ("--checkin".equals(arg)) { 525 isCheckin = true; 526 } else if ("-c".equals(arg)) { 527 isCheckin = true; 528 includeHistory = true; 529 } else if ("--unplugged".equals(arg)) { 530 isUnpluggedOnly = true; 531 } else if ("--reset".equals(arg)) { 532 synchronized (mStats) { 533 mStats.resetAllStatsLocked(); 534 pw.println("Battery stats reset."); 535 noOutput = true; 536 } 537 } else if ("--write".equals(arg)) { 538 synchronized (mStats) { 539 mStats.writeSyncLocked(); 540 pw.println("Battery stats written."); 541 noOutput = true; 542 } 543 } else if ("-h".equals(arg)) { 544 dumpHelp(pw); 545 return; 546 } else if ("-a".equals(arg)) { 547 // fall through 548 } else if (arg.length() > 0 && arg.charAt(0) == '-'){ 549 pw.println("Unknown option: " + arg); 550 dumpHelp(pw); 551 return; 552 } else { 553 // Not an option, last argument must be a package name. 554 try { 555 reqUid = mContext.getPackageManager().getPackageUid(arg, 556 UserHandle.getCallingUserId()); 557 } catch (PackageManager.NameNotFoundException e) { 558 pw.println("Unknown package: " + arg); 559 dumpHelp(pw); 560 return; 561 } 562 } 563 } 564 } 565 if (noOutput) { 566 return; 567 } 568 if (isCheckin) { 569 List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0); 570 synchronized (mStats) { 571 mStats.dumpCheckinLocked(pw, apps, isUnpluggedOnly, includeHistory); 572 } 573 } else { 574 synchronized (mStats) { 575 mStats.dumpLocked(pw, isUnpluggedOnly, reqUid); 576 } 577 } 578 } 579 } 580