Home | History | Annotate | Download | only in am
      1 /*
      2  * Copyright (C) 2015 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.app.ActivityOptions;
     20 import android.app.PendingIntent;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.os.Bundle;
     24 import android.os.SystemClock;
     25 import android.util.ArrayMap;
     26 import android.util.MutableLong;
     27 import android.util.TimeUtils;
     28 import android.util.proto.ProtoOutputStream;
     29 import android.util.proto.ProtoUtils;
     30 
     31 import java.io.PrintWriter;
     32 
     33 /**
     34  * Tracks the time a user spent in an app.
     35  */
     36 public class AppTimeTracker {
     37     private final PendingIntent mReceiver;
     38 
     39     private long mTotalTime;
     40     private final ArrayMap<String, MutableLong> mPackageTimes = new ArrayMap<>();
     41 
     42     private long mStartedTime;
     43     private String mStartedPackage;
     44     private MutableLong mStartedPackageTime;
     45 
     46     public AppTimeTracker(PendingIntent receiver) {
     47         mReceiver = receiver;
     48     }
     49 
     50     public void start(String packageName) {
     51         long now = SystemClock.elapsedRealtime();
     52         if (mStartedTime == 0) {
     53             mStartedTime = now;
     54         }
     55         if (!packageName.equals(mStartedPackage)) {
     56             if (mStartedPackageTime != null) {
     57                 long elapsedTime = now - mStartedTime;
     58                 mStartedPackageTime.value += elapsedTime;
     59                 mTotalTime += elapsedTime;
     60             }
     61             mStartedPackage = packageName;
     62             mStartedPackageTime = mPackageTimes.get(packageName);
     63             if (mStartedPackageTime == null) {
     64                 mStartedPackageTime = new MutableLong(0);
     65                 mPackageTimes.put(packageName, mStartedPackageTime);
     66             }
     67         }
     68     }
     69 
     70     public void stop() {
     71         if (mStartedTime != 0) {
     72             long elapsedTime = SystemClock.elapsedRealtime() - mStartedTime;
     73             mTotalTime += elapsedTime;
     74             if (mStartedPackageTime != null) {
     75                 mStartedPackageTime.value += elapsedTime;
     76             }
     77             mStartedPackage = null;
     78             mStartedPackageTime = null;
     79         }
     80     }
     81 
     82     public void deliverResult(Context context) {
     83         stop();
     84         Bundle extras = new Bundle();
     85         extras.putLong(ActivityOptions.EXTRA_USAGE_TIME_REPORT, mTotalTime);
     86         Bundle pkgs = new Bundle();
     87         for (int i=mPackageTimes.size()-1; i>=0; i--) {
     88             pkgs.putLong(mPackageTimes.keyAt(i), mPackageTimes.valueAt(i).value);
     89         }
     90         extras.putBundle(ActivityOptions.EXTRA_USAGE_TIME_REPORT_PACKAGES, pkgs);
     91         Intent fillinIntent = new Intent();
     92         fillinIntent.putExtras(extras);
     93         try {
     94             mReceiver.send(context, 0, fillinIntent);
     95         } catch (PendingIntent.CanceledException e) {
     96         }
     97     }
     98 
     99     public void dumpWithHeader(PrintWriter pw, String prefix, boolean details) {
    100         pw.print(prefix); pw.print("AppTimeTracker #");
    101         pw.print(Integer.toHexString(System.identityHashCode(this)));
    102         pw.println(":");
    103         dump(pw, prefix + "  ", details);
    104     }
    105 
    106     public void dump(PrintWriter pw, String prefix, boolean details) {
    107         pw.print(prefix); pw.print("mReceiver="); pw.println(mReceiver);
    108         pw.print(prefix); pw.print("mTotalTime=");
    109         TimeUtils.formatDuration(mTotalTime, pw);
    110         pw.println();
    111         for (int i = 0; i < mPackageTimes.size(); i++) {
    112             pw.print(prefix); pw.print("mPackageTime:"); pw.print(mPackageTimes.keyAt(i));
    113             pw.print("=");
    114             TimeUtils.formatDuration(mPackageTimes.valueAt(i).value, pw);
    115             pw.println();
    116         }
    117         if (details && mStartedTime != 0) {
    118             pw.print(prefix); pw.print("mStartedTime=");
    119             TimeUtils.formatDuration(SystemClock.elapsedRealtime(), mStartedTime, pw);
    120             pw.println();
    121             pw.print(prefix); pw.print("mStartedPackage="); pw.println(mStartedPackage);
    122         }
    123     }
    124 
    125     void writeToProto(ProtoOutputStream proto, long fieldId, boolean details) {
    126         final long token = proto.start(fieldId);
    127         proto.write(AppTimeTrackerProto.RECEIVER, mReceiver.toString());
    128         proto.write(AppTimeTrackerProto.TOTAL_DURATION_MS, mTotalTime);
    129         for (int i=0; i<mPackageTimes.size(); i++) {
    130             final long ptoken = proto.start(AppTimeTrackerProto.PACKAGE_TIMES);
    131             proto.write(AppTimeTrackerProto.PackageTime.PACKAGE, mPackageTimes.keyAt(i));
    132             proto.write(AppTimeTrackerProto.PackageTime.DURATION_MS, mPackageTimes.valueAt(i).value);
    133             proto.end(ptoken);
    134         }
    135         if (details && mStartedTime != 0) {
    136             ProtoUtils.toDuration(proto, AppTimeTrackerProto.STARTED_TIME,
    137                     mStartedTime, SystemClock.elapsedRealtime());
    138             proto.write(AppTimeTrackerProto.STARTED_PACKAGE, mStartedPackage);
    139         }
    140         proto.end(token);
    141     }
    142 }
    143