UsageStatsService.java revision f47e51ec605fccf7fed9e50d1adc98fbd4e8b340
1/** 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 17package com.android.server.usage; 18 19import android.Manifest; 20import android.app.ActivityManagerNative; 21import android.app.AppGlobals; 22import android.app.AppOpsManager; 23import android.app.admin.DevicePolicyManager; 24import android.app.usage.ConfigurationStats; 25import android.app.usage.IUsageStatsManager; 26import android.app.usage.UsageEvents; 27import android.app.usage.UsageEvents.Event; 28import android.app.usage.UsageStats; 29import android.app.usage.UsageStatsManagerInternal; 30import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener; 31import android.appwidget.AppWidgetManager; 32import android.content.BroadcastReceiver; 33import android.content.ComponentName; 34import android.content.Context; 35import android.content.Intent; 36import android.content.IntentFilter; 37import android.content.pm.PackageInfo; 38import android.content.pm.PackageManager; 39import android.content.pm.ParceledListSlice; 40import android.content.pm.UserInfo; 41import android.content.res.Configuration; 42import android.database.ContentObserver; 43import android.net.Uri; 44import android.os.Binder; 45import android.os.Environment; 46import android.os.Handler; 47import android.os.Looper; 48import android.os.Message; 49import android.os.Process; 50import android.os.RemoteException; 51import android.os.SystemClock; 52import android.os.UserHandle; 53import android.os.UserManager; 54import android.provider.Settings; 55import android.util.ArraySet; 56import android.util.Slog; 57import android.util.SparseArray; 58 59import com.android.internal.os.BackgroundThread; 60import com.android.internal.util.IndentingPrintWriter; 61import com.android.server.SystemConfig; 62import com.android.server.SystemService; 63 64import java.io.File; 65import java.io.FileDescriptor; 66import java.io.PrintWriter; 67import java.util.ArrayList; 68import java.util.Arrays; 69import java.util.List; 70 71/** 72 * A service that collects, aggregates, and persists application usage data. 73 * This data can be queried by apps that have been granted permission by AppOps. 74 */ 75public class UsageStatsService extends SystemService implements 76 UserUsageStatsService.StatsUpdatedListener { 77 static final String TAG = "UsageStatsService"; 78 79 static final boolean DEBUG = false; 80 private static final long TEN_SECONDS = 10 * 1000; 81 private static final long TWENTY_MINUTES = 20 * 60 * 1000; 82 private static final long FLUSH_INTERVAL = DEBUG ? TEN_SECONDS : TWENTY_MINUTES; 83 private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds. 84 85 // Handler message types. 86 static final int MSG_REPORT_EVENT = 0; 87 static final int MSG_FLUSH_TO_DISK = 1; 88 static final int MSG_REMOVE_USER = 2; 89 static final int MSG_INFORM_LISTENERS = 3; 90 static final int MSG_RESET_LAST_TIMESTAMP = 4; 91 92 private final Object mLock = new Object(); 93 Handler mHandler; 94 AppOpsManager mAppOps; 95 UserManager mUserManager; 96 97 private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>(); 98 private File mUsageStatsDir; 99 long mRealTimeSnapshot; 100 long mSystemTimeSnapshot; 101 102 private static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = 1L * 24 * 60 * 60 * 1000; // 1 day 103 private long mAppIdleDurationMillis; 104 105 private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener> 106 mPackageAccessListeners = new ArrayList<>(); 107 108 public UsageStatsService(Context context) { 109 super(context); 110 } 111 112 @Override 113 public void onStart() { 114 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 115 mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); 116 mHandler = new H(BackgroundThread.get().getLooper()); 117 118 File systemDataDir = new File(Environment.getDataDirectory(), "system"); 119 mUsageStatsDir = new File(systemDataDir, "usagestats"); 120 mUsageStatsDir.mkdirs(); 121 if (!mUsageStatsDir.exists()) { 122 throw new IllegalStateException("Usage stats directory does not exist: " 123 + mUsageStatsDir.getAbsolutePath()); 124 } 125 126 getContext().registerReceiver(new UserRemovedReceiver(), 127 new IntentFilter(Intent.ACTION_USER_REMOVED)); 128 129 synchronized (mLock) { 130 cleanUpRemovedUsersLocked(); 131 } 132 133 mRealTimeSnapshot = SystemClock.elapsedRealtime(); 134 mSystemTimeSnapshot = System.currentTimeMillis(); 135 // Look at primary user's secure setting for this. TODO: Maybe apply different 136 // thresholds for different users. 137 mAppIdleDurationMillis = Settings.Secure.getLongForUser(getContext().getContentResolver(), 138 Settings.Secure.APP_IDLE_DURATION, DEFAULT_APP_IDLE_THRESHOLD_MILLIS, 139 UserHandle.USER_OWNER); 140 141 publishLocalService(UsageStatsManagerInternal.class, new LocalService()); 142 publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService()); 143 } 144 145 @Override 146 public void onBootPhase(int phase) { 147 if (phase == PHASE_SYSTEM_SERVICES_READY) { 148 // Observe changes to the threshold 149 new SettingsObserver(mHandler).registerObserver(); 150 } 151 } 152 153 private class UserRemovedReceiver extends BroadcastReceiver { 154 155 @Override 156 public void onReceive(Context context, Intent intent) { 157 if (intent != null && intent.getAction().equals(Intent.ACTION_USER_REMOVED)) { 158 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 159 if (userId >= 0) { 160 mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget(); 161 } 162 } 163 } 164 } 165 166 @Override 167 public void onStatsUpdated() { 168 mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL); 169 } 170 171 private void cleanUpRemovedUsersLocked() { 172 final List<UserInfo> users = mUserManager.getUsers(true); 173 if (users == null || users.size() == 0) { 174 throw new IllegalStateException("There can't be no users"); 175 } 176 177 ArraySet<String> toDelete = new ArraySet<>(); 178 String[] fileNames = mUsageStatsDir.list(); 179 if (fileNames == null) { 180 // No users to delete. 181 return; 182 } 183 184 toDelete.addAll(Arrays.asList(fileNames)); 185 186 final int userCount = users.size(); 187 for (int i = 0; i < userCount; i++) { 188 final UserInfo userInfo = users.get(i); 189 toDelete.remove(Integer.toString(userInfo.id)); 190 } 191 192 final int deleteCount = toDelete.size(); 193 for (int i = 0; i < deleteCount; i++) { 194 deleteRecursively(new File(mUsageStatsDir, toDelete.valueAt(i))); 195 } 196 } 197 198 private static void deleteRecursively(File f) { 199 File[] files = f.listFiles(); 200 if (files != null) { 201 for (File subFile : files) { 202 deleteRecursively(subFile); 203 } 204 } 205 206 if (!f.delete()) { 207 Slog.e(TAG, "Failed to delete " + f); 208 } 209 } 210 211 private UserUsageStatsService getUserDataAndInitializeIfNeededLocked(int userId, 212 long currentTimeMillis) { 213 UserUsageStatsService service = mUserState.get(userId); 214 if (service == null) { 215 service = new UserUsageStatsService(getContext(), userId, 216 new File(mUsageStatsDir, Integer.toString(userId)), this); 217 service.init(currentTimeMillis); 218 mUserState.put(userId, service); 219 } 220 return service; 221 } 222 223 /** 224 * This should be the only way to get the time from the system. 225 */ 226 private long checkAndGetTimeLocked() { 227 final long actualSystemTime = System.currentTimeMillis(); 228 final long actualRealtime = SystemClock.elapsedRealtime(); 229 final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot; 230 if (Math.abs(actualSystemTime - expectedSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) { 231 // The time has changed. 232 final int userCount = mUserState.size(); 233 for (int i = 0; i < userCount; i++) { 234 final UserUsageStatsService service = mUserState.valueAt(i); 235 service.onTimeChanged(expectedSystemTime, actualSystemTime); 236 } 237 mRealTimeSnapshot = actualRealtime; 238 mSystemTimeSnapshot = actualSystemTime; 239 } 240 return actualSystemTime; 241 } 242 243 /** 244 * Assuming the event's timestamp is measured in milliseconds since boot, 245 * convert it to a system wall time. 246 */ 247 private void convertToSystemTimeLocked(UsageEvents.Event event) { 248 event.mTimeStamp = Math.max(0, event.mTimeStamp - mRealTimeSnapshot) + mSystemTimeSnapshot; 249 } 250 251 /** 252 * Called by the Binder stub 253 */ 254 void shutdown() { 255 synchronized (mLock) { 256 mHandler.removeMessages(MSG_REPORT_EVENT); 257 flushToDiskLocked(); 258 } 259 } 260 261 /** 262 * Called by the Binder stub. 263 */ 264 void reportEvent(UsageEvents.Event event, int userId) { 265 synchronized (mLock) { 266 final long timeNow = checkAndGetTimeLocked(); 267 convertToSystemTimeLocked(event); 268 269 final UserUsageStatsService service = 270 getUserDataAndInitializeIfNeededLocked(userId, timeNow); 271 final long lastUsed = service.getLastPackageAccessTime(event.mPackage); 272 final boolean previouslyIdle = hasPassedIdleDuration(lastUsed); 273 service.reportEvent(event); 274 // Inform listeners if necessary 275 if ((event.mEventType == Event.MOVE_TO_FOREGROUND 276 || event.mEventType == Event.MOVE_TO_BACKGROUND 277 || event.mEventType == Event.INTERACTION)) { 278 if (previouslyIdle) { 279 // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage); 280 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId, 281 /* idle = */ 0, event.mPackage)); 282 } 283 } 284 } 285 } 286 287 /** 288 * Forces the app's timestamp to reflect idle or active. If idle, then it rolls back the 289 * last used timestamp to a point in time thats behind the threshold for idle. 290 */ 291 void resetLastTimestamp(String packageName, int userId, boolean idle) { 292 synchronized (mLock) { 293 final long timeNow = checkAndGetTimeLocked(); 294 final long lastTimestamp = timeNow - (idle ? mAppIdleDurationMillis : 0); 295 296 final UserUsageStatsService service = 297 getUserDataAndInitializeIfNeededLocked(userId, timeNow); 298 final long lastUsed = service.getLastPackageAccessTime(packageName); 299 final boolean previouslyIdle = hasPassedIdleDuration(lastUsed); 300 service.setLastTimestamp(packageName, lastTimestamp); 301 // Inform listeners if necessary 302 if (previouslyIdle != idle) { 303 // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage); 304 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId, 305 /* idle = */ idle ? 1 : 0, packageName)); 306 } 307 } 308 } 309 310 /** 311 * Called by the Binder stub. 312 */ 313 void flushToDisk() { 314 synchronized (mLock) { 315 flushToDiskLocked(); 316 } 317 } 318 319 /** 320 * Called by the Binder stub. 321 */ 322 void removeUser(int userId) { 323 synchronized (mLock) { 324 Slog.i(TAG, "Removing user " + userId + " and all data."); 325 mUserState.remove(userId); 326 cleanUpRemovedUsersLocked(); 327 } 328 } 329 330 /** 331 * Called by the Binder stub. 332 */ 333 List<UsageStats> queryUsageStats(int userId, int bucketType, long beginTime, long endTime) { 334 synchronized (mLock) { 335 final long timeNow = checkAndGetTimeLocked(); 336 if (!validRange(timeNow, beginTime, endTime)) { 337 return null; 338 } 339 340 final UserUsageStatsService service = 341 getUserDataAndInitializeIfNeededLocked(userId, timeNow); 342 return service.queryUsageStats(bucketType, beginTime, endTime); 343 } 344 } 345 346 /** 347 * Called by the Binder stub. 348 */ 349 List<ConfigurationStats> queryConfigurationStats(int userId, int bucketType, long beginTime, 350 long endTime) { 351 synchronized (mLock) { 352 final long timeNow = checkAndGetTimeLocked(); 353 if (!validRange(timeNow, beginTime, endTime)) { 354 return null; 355 } 356 357 final UserUsageStatsService service = 358 getUserDataAndInitializeIfNeededLocked(userId, timeNow); 359 return service.queryConfigurationStats(bucketType, beginTime, endTime); 360 } 361 } 362 363 /** 364 * Called by the Binder stub. 365 */ 366 UsageEvents queryEvents(int userId, long beginTime, long endTime) { 367 synchronized (mLock) { 368 final long timeNow = checkAndGetTimeLocked(); 369 if (!validRange(timeNow, beginTime, endTime)) { 370 return null; 371 } 372 373 final UserUsageStatsService service = 374 getUserDataAndInitializeIfNeededLocked(userId, timeNow); 375 return service.queryEvents(beginTime, endTime); 376 } 377 } 378 379 /** 380 * Called by LocalService stub. 381 */ 382 long getLastPackageAccessTime(String packageName, int userId) { 383 synchronized (mLock) { 384 final long timeNow = checkAndGetTimeLocked(); 385 // android package is always considered non-idle. 386 // TODO: Add a generic whitelisting mechanism 387 if (packageName.equals("android")) { 388 return timeNow; 389 } 390 final UserUsageStatsService service = 391 getUserDataAndInitializeIfNeededLocked(userId, timeNow); 392 return service.getLastPackageAccessTime(packageName); 393 } 394 } 395 396 void addListener(AppIdleStateChangeListener listener) { 397 synchronized (mLock) { 398 if (!mPackageAccessListeners.contains(listener)) { 399 mPackageAccessListeners.add(listener); 400 } 401 } 402 } 403 404 void removeListener(AppIdleStateChangeListener listener) { 405 synchronized (mLock) { 406 mPackageAccessListeners.remove(listener); 407 } 408 } 409 410 private boolean hasPassedIdleDuration(long lastUsed) { 411 final long now = System.currentTimeMillis(); 412 return lastUsed < now - mAppIdleDurationMillis; 413 } 414 415 boolean isAppIdle(String packageName, int userId) { 416 if (packageName == null) return false; 417 if (SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) { 418 return false; 419 } 420 if (isActiveDeviceAdmin(packageName, userId)) { 421 return false; 422 } 423 424 final long lastUsed = getLastPackageAccessTime(packageName, userId); 425 return hasPassedIdleDuration(lastUsed); 426 } 427 428 void setAppIdle(String packageName, boolean idle, int userId) { 429 if (packageName == null) return; 430 431 mHandler.obtainMessage(MSG_RESET_LAST_TIMESTAMP, userId, idle ? 1 : 0, packageName) 432 .sendToTarget(); 433 } 434 435 private boolean isActiveDeviceAdmin(String packageName, int userId) { 436 DevicePolicyManager dpm = getContext().getSystemService(DevicePolicyManager.class); 437 if (dpm == null) return false; 438 List<ComponentName> components = dpm.getActiveAdminsAsUser(userId); 439 if (components == null) return false; 440 final int size = components.size(); 441 for (int i = 0; i < size; i++) { 442 if (components.get(i).getPackageName().equals(packageName)) { 443 return true; 444 } 445 } 446 return false; 447 } 448 449 void informListeners(String packageName, int userId, boolean isIdle) { 450 for (AppIdleStateChangeListener listener : mPackageAccessListeners) { 451 listener.onAppIdleStateChanged(packageName, userId, isIdle); 452 } 453 } 454 455 private static boolean validRange(long currentTime, long beginTime, long endTime) { 456 return beginTime <= currentTime && beginTime < endTime; 457 } 458 459 private void flushToDiskLocked() { 460 final int userCount = mUserState.size(); 461 for (int i = 0; i < userCount; i++) { 462 UserUsageStatsService service = mUserState.valueAt(i); 463 service.persistActiveStats(); 464 } 465 466 mHandler.removeMessages(MSG_FLUSH_TO_DISK); 467 } 468 469 /** 470 * Called by the Binder stub. 471 */ 472 void dump(String[] args, PrintWriter pw) { 473 synchronized (mLock) { 474 IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " "); 475 ArraySet<String> argSet = new ArraySet<>(); 476 argSet.addAll(Arrays.asList(args)); 477 478 final int userCount = mUserState.size(); 479 for (int i = 0; i < userCount; i++) { 480 idpw.printPair("user", mUserState.keyAt(i)); 481 idpw.println(); 482 idpw.increaseIndent(); 483 if (argSet.contains("--checkin")) { 484 mUserState.valueAt(i).checkin(idpw); 485 } else { 486 mUserState.valueAt(i).dump(idpw); 487 } 488 idpw.decreaseIndent(); 489 } 490 } 491 } 492 493 class H extends Handler { 494 public H(Looper looper) { 495 super(looper); 496 } 497 498 @Override 499 public void handleMessage(Message msg) { 500 switch (msg.what) { 501 case MSG_REPORT_EVENT: 502 reportEvent((UsageEvents.Event) msg.obj, msg.arg1); 503 break; 504 505 case MSG_FLUSH_TO_DISK: 506 flushToDisk(); 507 break; 508 509 case MSG_REMOVE_USER: 510 removeUser(msg.arg1); 511 break; 512 513 case MSG_INFORM_LISTENERS: 514 informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1); 515 break; 516 517 case MSG_RESET_LAST_TIMESTAMP: 518 resetLastTimestamp((String) msg.obj, msg.arg1, msg.arg2 == 1); 519 break; 520 521 default: 522 super.handleMessage(msg); 523 break; 524 } 525 } 526 } 527 528 /** 529 * Observe settings changes for Settings.Secure.APP_IDLE_DURATION. 530 */ 531 private class SettingsObserver extends ContentObserver { 532 533 SettingsObserver(Handler handler) { 534 super(handler); 535 } 536 537 void registerObserver() { 538 getContext().getContentResolver().registerContentObserver(Settings.Secure.getUriFor( 539 Settings.Secure.APP_IDLE_DURATION), false, this, UserHandle.USER_OWNER); 540 } 541 542 @Override 543 public void onChange(boolean selfChange, Uri uri, int userId) { 544 mAppIdleDurationMillis = Settings.Secure.getLongForUser(getContext().getContentResolver(), 545 Settings.Secure.APP_IDLE_DURATION, DEFAULT_APP_IDLE_THRESHOLD_MILLIS, 546 UserHandle.USER_OWNER); 547 // TODO: Check if we need to update idle states of all the apps 548 } 549 } 550 551 private class BinderService extends IUsageStatsManager.Stub { 552 553 private boolean hasPermission(String callingPackage) { 554 final int callingUid = Binder.getCallingUid(); 555 if (callingUid == Process.SYSTEM_UID) { 556 return true; 557 } 558 final int mode = mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, 559 callingUid, callingPackage); 560 if (mode == AppOpsManager.MODE_DEFAULT) { 561 // The default behavior here is to check if PackageManager has given the app 562 // permission. 563 return getContext().checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS) 564 == PackageManager.PERMISSION_GRANTED; 565 } 566 return mode == AppOpsManager.MODE_ALLOWED; 567 } 568 569 @Override 570 public ParceledListSlice<UsageStats> queryUsageStats(int bucketType, long beginTime, 571 long endTime, String callingPackage) { 572 if (!hasPermission(callingPackage)) { 573 return null; 574 } 575 576 final int userId = UserHandle.getCallingUserId(); 577 final long token = Binder.clearCallingIdentity(); 578 try { 579 final List<UsageStats> results = UsageStatsService.this.queryUsageStats( 580 userId, bucketType, beginTime, endTime); 581 if (results != null) { 582 return new ParceledListSlice<>(results); 583 } 584 } finally { 585 Binder.restoreCallingIdentity(token); 586 } 587 return null; 588 } 589 590 @Override 591 public ParceledListSlice<ConfigurationStats> queryConfigurationStats(int bucketType, 592 long beginTime, long endTime, String callingPackage) throws RemoteException { 593 if (!hasPermission(callingPackage)) { 594 return null; 595 } 596 597 final int userId = UserHandle.getCallingUserId(); 598 final long token = Binder.clearCallingIdentity(); 599 try { 600 final List<ConfigurationStats> results = 601 UsageStatsService.this.queryConfigurationStats(userId, bucketType, 602 beginTime, endTime); 603 if (results != null) { 604 return new ParceledListSlice<>(results); 605 } 606 } finally { 607 Binder.restoreCallingIdentity(token); 608 } 609 return null; 610 } 611 612 @Override 613 public UsageEvents queryEvents(long beginTime, long endTime, String callingPackage) { 614 if (!hasPermission(callingPackage)) { 615 return null; 616 } 617 618 final int userId = UserHandle.getCallingUserId(); 619 final long token = Binder.clearCallingIdentity(); 620 try { 621 return UsageStatsService.this.queryEvents(userId, beginTime, endTime); 622 } finally { 623 Binder.restoreCallingIdentity(token); 624 } 625 } 626 627 @Override 628 public boolean isAppIdle(String packageName, int userId) { 629 try { 630 userId = ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(), 631 Binder.getCallingUid(), userId, false, true, "isAppIdle", null); 632 } catch (RemoteException re) { 633 return false; 634 } 635 final long token = Binder.clearCallingIdentity(); 636 try { 637 return UsageStatsService.this.isAppIdle(packageName, userId); 638 } finally { 639 Binder.restoreCallingIdentity(token); 640 } 641 } 642 643 @Override 644 public void setAppIdle(String packageName, boolean idle, int userId) { 645 final int callingUid = Binder.getCallingUid(); 646 try { 647 userId = ActivityManagerNative.getDefault().handleIncomingUser( 648 Binder.getCallingPid(), callingUid, userId, false, true, 649 "setAppIdle", null); 650 } catch (RemoteException re) { 651 return; 652 } 653 getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE, 654 "No permission to change app idle state"); 655 final long token = Binder.clearCallingIdentity(); 656 try { 657 PackageInfo pi = AppGlobals.getPackageManager() 658 .getPackageInfo(packageName, 0, userId); 659 if (pi == null) return; 660 UsageStatsService.this.setAppIdle(packageName, idle, userId); 661 } catch (RemoteException re) { 662 } finally { 663 Binder.restoreCallingIdentity(token); 664 } 665 } 666 667 @Override 668 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 669 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 670 != PackageManager.PERMISSION_GRANTED) { 671 pw.println("Permission Denial: can't dump UsageStats from pid=" 672 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 673 + " without permission " + android.Manifest.permission.DUMP); 674 return; 675 } 676 UsageStatsService.this.dump(args, pw); 677 } 678 } 679 680 /** 681 * This local service implementation is primarily used by ActivityManagerService. 682 * ActivityManagerService will call these methods holding the 'am' lock, which means we 683 * shouldn't be doing any IO work or other long running tasks in these methods. 684 */ 685 private class LocalService extends UsageStatsManagerInternal { 686 687 @Override 688 public void reportEvent(ComponentName component, int userId, int eventType) { 689 if (component == null) { 690 Slog.w(TAG, "Event reported without a component name"); 691 return; 692 } 693 694 UsageEvents.Event event = new UsageEvents.Event(); 695 event.mPackage = component.getPackageName(); 696 event.mClass = component.getClassName(); 697 698 // This will later be converted to system time. 699 event.mTimeStamp = SystemClock.elapsedRealtime(); 700 701 event.mEventType = eventType; 702 mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); 703 } 704 705 @Override 706 public void reportEvent(String packageName, int userId, int eventType) { 707 if (packageName == null) { 708 Slog.w(TAG, "Event reported without a package name"); 709 return; 710 } 711 712 UsageEvents.Event event = new UsageEvents.Event(); 713 event.mPackage = packageName; 714 715 // This will later be converted to system time. 716 event.mTimeStamp = SystemClock.elapsedRealtime(); 717 718 event.mEventType = eventType; 719 mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); 720 } 721 722 @Override 723 public void reportConfigurationChange(Configuration config, int userId) { 724 if (config == null) { 725 Slog.w(TAG, "Configuration event reported with a null config"); 726 return; 727 } 728 729 UsageEvents.Event event = new UsageEvents.Event(); 730 event.mPackage = "android"; 731 732 // This will later be converted to system time. 733 event.mTimeStamp = SystemClock.elapsedRealtime(); 734 735 event.mEventType = UsageEvents.Event.CONFIGURATION_CHANGE; 736 event.mConfiguration = new Configuration(config); 737 mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); 738 } 739 740 @Override 741 public boolean isAppIdle(String packageName, int userId) { 742 return UsageStatsService.this.isAppIdle(packageName, userId); 743 } 744 745 @Override 746 public long getLastPackageAccessTime(String packageName, int userId) { 747 return UsageStatsService.this.getLastPackageAccessTime(packageName, userId); 748 } 749 750 @Override 751 public void prepareShutdown() { 752 // This method *WILL* do IO work, but we must block until it is finished or else 753 // we might not shutdown cleanly. This is ok to do with the 'am' lock held, because 754 // we are shutting down. 755 shutdown(); 756 } 757 758 @Override 759 public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) { 760 UsageStatsService.this.addListener(listener); 761 } 762 763 @Override 764 public void removeAppIdleStateChangeListener( 765 AppIdleStateChangeListener listener) { 766 UsageStatsService.this.removeListener(listener); 767 } 768 } 769} 770