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 
AppTimeTracker(PendingIntent receiver)46     public AppTimeTracker(PendingIntent receiver) {
47         mReceiver = receiver;
48     }
49 
start(String packageName)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 
stop()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 
deliverResult(Context context)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 
dumpWithHeader(PrintWriter pw, String prefix, boolean details)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 
dump(PrintWriter pw, String prefix, boolean details)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 
writeToProto(ProtoOutputStream proto, long fieldId, boolean details)125     public 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