blob: 001987fd0ff342db52cc0b96cc8bcebaff542522 [file] [log] [blame]
/*
* Copyright (C) 2006-2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.am;
import com.android.internal.app.IUsageStats;
import android.content.ComponentName;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import com.android.internal.os.PkgUsageStats;
import android.os.Process;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* This service collects the statistics associated with usage
* of various components, like when a particular package is launched or
* paused and aggregates events like number of time a component is launched
* total duration of a component launch.
*/
public final class UsageStatsService extends IUsageStats.Stub {
public static final String SERVICE_NAME = "usagestats";
private static final boolean localLOGV = false;
private static final String TAG = "UsageStats";
static IUsageStats sService;
private Context mContext;
private String mFileName;
final private Map<String, PkgUsageStatsExtended> mStats;
private String mResumedPkg;
private class PkgUsageStatsExtended {
int mLaunchCount;
long mUsageTime;
long mChgTime;
PkgUsageStatsExtended() {
mLaunchCount = 0;
mUsageTime = 0;
mChgTime = SystemClock.elapsedRealtime();
}
void updateResume() {
mLaunchCount ++;
mChgTime = SystemClock.elapsedRealtime();
}
void updatePause() {
long currTime = SystemClock.elapsedRealtime();
mUsageTime += (currTime - mChgTime);
mChgTime = currTime;
}
}
UsageStatsService(String filename) {
mFileName = filename;
mStats = new HashMap<String, PkgUsageStatsExtended>();
}
public void publish(Context context) {
mContext = context;
ServiceManager.addService(SERVICE_NAME, asBinder());
}
public static IUsageStats getService() {
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService(SERVICE_NAME);
sService = asInterface(b);
return sService;
}
public void noteResumeComponent(ComponentName componentName) {
enforceCallingPermission();
String pkgName;
if ((componentName == null) ||
((pkgName = componentName.getPackageName()) == null)) {
return;
}
if ((mResumedPkg != null) && (mResumedPkg.equalsIgnoreCase(pkgName))) {
// Moving across activities in same package. just return
return;
}
if (localLOGV) Log.i(TAG, "started component:"+pkgName);
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
pus = new PkgUsageStatsExtended();
mStats.put(pkgName, pus);
}
pus.updateResume();
mResumedPkg = pkgName;
}
public void notePauseComponent(ComponentName componentName) {
enforceCallingPermission();
String pkgName;
if ((componentName == null) ||
((pkgName = componentName.getPackageName()) == null)) {
return;
}
if ((mResumedPkg == null) || (!pkgName.equalsIgnoreCase(mResumedPkg))) {
Log.w(TAG, "Something wrong here, Didn't expect "+pkgName+" to be paused");
return;
}
if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
// Weird some error here
Log.w(TAG, "No package stats for pkg:"+pkgName);
return;
}
pus.updatePause();
}
public void enforceCallingPermission() {
if (Binder.getCallingPid() == Process.myPid()) {
return;
}
mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
}
public PkgUsageStats getPkgUsageStats(ComponentName componentName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
String pkgName;
if ((componentName == null) ||
((pkgName = componentName.getPackageName()) == null)) {
return null;
}
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
return null;
}
return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime);
}
public PkgUsageStats[] getAllPkgUsageStats() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
synchronized (mStats) {
Set<String> keys = mStats.keySet();
int size = keys.size();
if (size <= 0) {
return null;
}
PkgUsageStats retArr[] = new PkgUsageStats[size];
int i = 0;
for (String key: keys) {
PkgUsageStatsExtended pus = mStats.get(key);
retArr[i] = new PkgUsageStats(key, pus.mLaunchCount, pus.mUsageTime);
i++;
}
return retArr;
}
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder sb = new StringBuilder();
synchronized (mStats) {
Set<String> keys = mStats.keySet();
for (String key: keys) {
PkgUsageStatsExtended ps = mStats.get(key);
sb.append("pkg=");
sb.append(key);
sb.append(", launchCount=");
sb.append(ps.mLaunchCount);
sb.append(", usageTime=");
sb.append(ps.mUsageTime+" ms\n");
}
}
pw.write(sb.toString());
}
}