Merge "Usage stats!"

This commit is contained in:
Dianne Hackborn
2014-05-08 21:58:44 +00:00
committed by Android (Google) Code Review
13 changed files with 756 additions and 280 deletions

View File

@@ -20,7 +20,6 @@ import android.os.BatteryStats;
import android.os.IBinder;
import com.android.internal.app.IUsageStats;
import com.android.internal.app.ProcessStats;
import com.android.internal.os.PkgUsageStats;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
@@ -2130,14 +2129,15 @@ public class ActivityManager {
return new HashMap<String, Integer>();
}
PkgUsageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats();
UsageStats.PackageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats(
ActivityThread.currentPackageName());
if (allPkgUsageStats == null) {
return new HashMap<String, Integer>();
}
Map<String, Integer> launchCounts = new HashMap<String, Integer>();
for (PkgUsageStats pkgUsageStats : allPkgUsageStats) {
launchCounts.put(pkgUsageStats.packageName, pkgUsageStats.launchCount);
for (UsageStats.PackageStats pkgUsageStats : allPkgUsageStats) {
launchCounts.put(pkgUsageStats.getPackageName(), pkgUsageStats.getLaunchCount());
}
return launchCounts;
@@ -2251,17 +2251,17 @@ public class ActivityManager {
*
* @hide
*/
public PkgUsageStats[] getAllPackageUsageStats() {
public UsageStats.PackageStats[] getAllPackageUsageStats() {
try {
IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
ServiceManager.getService("usagestats"));
if (usageStatsService != null) {
return usageStatsService.getAllPkgUsageStats();
return usageStatsService.getAllPkgUsageStats(ActivityThread.currentPackageName());
}
} catch (RemoteException e) {
Log.w(TAG, "Could not query usage stats", e);
}
return new PkgUsageStats[0];
return new UsageStats.PackageStats[0];
}
/**

View File

@@ -16,6 +16,7 @@
package android.app;
import android.Manifest;
import android.os.Binder;
import android.os.IBinder;
import android.util.ArrayMap;
@@ -184,8 +185,10 @@ public class AppOpsManager {
public static final int OP_MONITOR_LOCATION = 41;
/** @hide Continually monitoring location data with a relatively high power request. */
public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
/** @hide Retrieve current usage stats via {@link UsageStatsManager}. */
public static final int OP_GET_USAGE_STATS = 43;
/** @hide */
public static final int _NUM_OP = 43;
public static final int _NUM_OP = 44;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION =
@@ -252,6 +255,7 @@ public class AppOpsManager {
OP_WAKE_LOCK,
OP_COARSE_LOCATION,
OP_COARSE_LOCATION,
OP_GET_USAGE_STATS,
};
/**
@@ -302,6 +306,7 @@ public class AppOpsManager {
null,
OPSTR_MONITOR_LOCATION,
OPSTR_MONITOR_HIGH_POWER_LOCATION,
null,
};
/**
@@ -352,6 +357,7 @@ public class AppOpsManager {
"WAKE_LOCK",
"MONITOR_LOCATION",
"MONITOR_HIGH_POWER_LOCATION",
"GET_USAGE_STATS"
};
/**
@@ -402,6 +408,7 @@ public class AppOpsManager {
android.Manifest.permission.WAKE_LOCK,
null, // no permission for generic location monitoring
null, // no permission for high power location monitoring
android.Manifest.permission.PACKAGE_USAGE_STATS,
};
/**
@@ -451,6 +458,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS
};
/**
@@ -504,6 +512,7 @@ public class AppOpsManager {
false,
false,
false,
false,
};
private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();

View File

@@ -678,6 +678,11 @@ class ContextImpl extends Context {
return new NetworkScoreManager(ctx);
}
});
registerService(USAGE_STATS_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new UsageStatsManager(ctx.getOuterContext());
}});
}
static ContextImpl getImpl(Context context) {

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) 2014, 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 android.app;
parcelable UsageStats;
parcelable UsageStats.PackageStats;

View File

@@ -0,0 +1,406 @@
/*
* Copyright (C) 2014 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 android.app;
import android.content.res.Configuration;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.ArrayMap;
import java.util.Map;
/**
* Snapshot of current usage stats data.
* @hide
*/
public class UsageStats implements Parcelable {
/** @hide */
public final ArrayMap<String, PackageStats> mPackages = new ArrayMap<String, PackageStats>();
/** @hide */
public final ArrayMap<Configuration, ConfigurationStats> mConfigurations
= new ArrayMap<Configuration, ConfigurationStats>();
public static class PackageStats implements Parcelable {
private final String mPackageName;
private int mLaunchCount;
private long mUsageTime;
private long mResumedTime;
/** @hide */
public final ArrayMap<String, Long> componentResumeTimes;
public static final Parcelable.Creator<PackageStats> CREATOR
= new Parcelable.Creator<PackageStats>() {
public PackageStats createFromParcel(Parcel in) {
return new PackageStats(in);
}
public PackageStats[] newArray(int size) {
return new PackageStats[size];
}
};
public String toString() {
return "PackageStats{"
+ Integer.toHexString(System.identityHashCode(this))
+ " " + mPackageName + "}";
}
/** @hide */
public PackageStats(String pkgName) {
mPackageName = pkgName;
componentResumeTimes = new ArrayMap<String, Long>();
}
/** @hide */
public PackageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
mPackageName = pkgName;
mLaunchCount = count;
mUsageTime = time;
componentResumeTimes = new ArrayMap<String, Long>();
componentResumeTimes.putAll(lastResumeTimes);
}
/** @hide */
public PackageStats(Parcel source) {
mPackageName = source.readString();
mLaunchCount = source.readInt();
mUsageTime = source.readLong();
final int N = source.readInt();
componentResumeTimes = new ArrayMap<String, Long>(N);
for (int i = 0; i < N; i++) {
String component = source.readString();
long lastResumeTime = source.readLong();
componentResumeTimes.put(component, lastResumeTime);
}
}
/** @hide */
public PackageStats(PackageStats pStats) {
mPackageName = pStats.mPackageName;
mLaunchCount = pStats.mLaunchCount;
mUsageTime = pStats.mUsageTime;
componentResumeTimes = new ArrayMap<String, Long>(pStats.componentResumeTimes);
}
/** @hide */
public void resume(boolean launched) {
if (launched) {
mLaunchCount++;
}
mResumedTime = SystemClock.elapsedRealtime();
}
/** @hide */
public void pause() {
if (mResumedTime > 0) {
mUsageTime += SystemClock.elapsedRealtime() - mResumedTime;
}
mResumedTime = 0;
}
public final String getPackageName() {
return mPackageName;
}
public final long getUsageTime(long elapsedRealtime) {
return mUsageTime + (mResumedTime > 0 ? (elapsedRealtime- mResumedTime) : 0);
}
public final int getLaunchCount() {
return mLaunchCount;
}
/** @hide */
public boolean clearUsageTimes() {
mLaunchCount = 0;
mUsageTime = 0;
return mResumedTime <= 0 && componentResumeTimes.isEmpty();
}
public final int describeContents() {
return 0;
}
public final void writeToParcel(Parcel dest, int parcelableFlags) {
writeToParcel(dest, parcelableFlags, 0);
}
final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) {
dest.writeString(mPackageName);
dest.writeInt(mLaunchCount);
dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime);
dest.writeInt(componentResumeTimes.size());
for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
dest.writeString(ent.getKey());
dest.writeLong(ent.getValue());
}
}
/** @hide */
public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
}
}
public static class ConfigurationStats implements Parcelable {
private final Configuration mConfiguration;
private long mLastUsedTime;
private int mUsageCount;
private long mUsageTime;
private long mStartedTime;
public static final Parcelable.Creator<ConfigurationStats> CREATOR
= new Parcelable.Creator<ConfigurationStats>() {
public ConfigurationStats createFromParcel(Parcel in) {
return new ConfigurationStats(in);
}
public ConfigurationStats[] newArray(int size) {
return new ConfigurationStats[size];
}
};
public String toString() {
return "ConfigurationStats{"
+ Integer.toHexString(System.identityHashCode(this))
+ " " + mConfiguration + "}";
}
/** @hide */
public ConfigurationStats(Configuration config) {
mConfiguration = config;
}
/** @hide */
public ConfigurationStats(Parcel source) {
mConfiguration = Configuration.CREATOR.createFromParcel(source);
mLastUsedTime = source.readLong();
mUsageCount = source.readInt();
mUsageTime = source.readLong();
}
/** @hide */
public ConfigurationStats(ConfigurationStats pStats) {
mConfiguration = pStats.mConfiguration;
mLastUsedTime = pStats.mLastUsedTime;
mUsageCount = pStats.mUsageCount;
mUsageTime = pStats.mUsageTime;
}
public final Configuration getConfiguration() {
return mConfiguration;
}
public final long getLastUsedTime() {
return mLastUsedTime;
}
public final long getUsageTime(long elapsedRealtime) {
return mUsageTime + (mStartedTime > 0 ? (elapsedRealtime- mStartedTime) : 0);
}
public final int getUsageCount() {
return mUsageCount;
}
/** @hide */
public void start() {
mLastUsedTime = System.currentTimeMillis();
mUsageCount++;
mStartedTime = SystemClock.elapsedRealtime();
}
/** @hide */
public void stop() {
if (mStartedTime > 0) {
mUsageTime += SystemClock.elapsedRealtime() - mStartedTime;
}
mStartedTime = 0;
}
/** @hide */
public boolean clearUsageTimes() {
mUsageCount = 0;
mUsageTime = 0;
return mLastUsedTime == 0 && mStartedTime <= 0;
}
public final int describeContents() {
return 0;
}
public final void writeToParcel(Parcel dest, int parcelableFlags) {
writeToParcel(dest, parcelableFlags, 0);
}
final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) {
mConfiguration.writeToParcel(dest, parcelableFlags);
dest.writeLong(mLastUsedTime);
dest.writeInt(mUsageCount);
dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime);
}
/** @hide */
public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
}
}
/** @hide */
public UsageStats() {
}
/** @hide */
public UsageStats(Parcel source, boolean extended) {
int N = source.readInt();
for (int i=0; i<N; i++) {
PackageStats pkg = extended ? onNewPackageStats(source) : new PackageStats(source);
mPackages.put(pkg.getPackageName(), pkg);
}
N = source.readInt();
for (int i=0; i<N; i++) {
ConfigurationStats config = extended ? onNewConfigurationStats(source)
: new ConfigurationStats(source);
mConfigurations.put(config.getConfiguration(), config);
}
}
public int getPackageStatsCount() {
return mPackages.size();
}
public PackageStats getPackageStatsAt(int index) {
return mPackages.valueAt(index);
}
public PackageStats getPackageStats(String pkgName) {
return mPackages.get(pkgName);
}
/** @hide */
public PackageStats getOrCreatePackageStats(String pkgName) {
PackageStats ps = mPackages.get(pkgName);
if (ps == null) {
ps = onNewPackageStats(pkgName);
mPackages.put(pkgName, ps);
}
return ps;
}
public int getConfigurationStatsCount() {
return mConfigurations.size();
}
public ConfigurationStats getConfigurationStatsAt(int index) {
return mConfigurations.valueAt(index);
}
public ConfigurationStats getConfigurationStats(Configuration config) {
return mConfigurations.get(config);
}
/** @hide */
public ConfigurationStats getOrCreateConfigurationStats(Configuration config) {
ConfigurationStats cs = mConfigurations.get(config);
if (cs == null) {
cs = onNewConfigurationStats(config);
mConfigurations.put(config, cs);
}
return cs;
}
/** @hide */
public void clearUsageTimes() {
for (int i=mPackages.size()-1; i>=0; i--) {
if (mPackages.valueAt(i).clearUsageTimes()) {
mPackages.removeAt(i);
}
}
for (int i=mConfigurations.size()-1; i>=0; i--) {
if (mConfigurations.valueAt(i).clearUsageTimes()) {
mConfigurations.removeAt(i);
}
}
}
/** @hide */
public PackageStats onNewPackageStats(String pkgName) {
return new PackageStats(pkgName);
}
/** @hide */
public PackageStats onNewPackageStats(Parcel source) {
return new PackageStats(source);
}
/** @hide */
public ConfigurationStats onNewConfigurationStats(Configuration config) {
return new ConfigurationStats(config);
}
/** @hide */
public ConfigurationStats onNewConfigurationStats(Parcel source) {
return new ConfigurationStats(source);
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int parcelableFlags) {
writeToParcelInner(dest, parcelableFlags, false);
}
/** @hide */
public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
writeToParcelInner(dest, parcelableFlags, true);
}
private void writeToParcelInner(Parcel dest, int parcelableFlags, boolean extended) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
int N = mPackages.size();
dest.writeInt(N);
for (int i=0; i<N; i++) {
PackageStats ps = mPackages.valueAt(i);
ps.writeToParcel(dest, parcelableFlags, elapsedRealtime);
if (extended) {
ps.writeExtendedToParcel(dest, parcelableFlags);
}
}
N = mConfigurations.size();
dest.writeInt(N);
for (int i=0; i<N; i++) {
ConfigurationStats cs = mConfigurations.valueAt(i);
cs.writeToParcel(dest, parcelableFlags, elapsedRealtime);
if (extended) {
cs.writeExtendedToParcel(dest, parcelableFlags);
}
}
}
public static final Parcelable.Creator<UsageStats> CREATOR
= new Parcelable.Creator<UsageStats>() {
public UsageStats createFromParcel(Parcel in) {
return new UsageStats(in, false);
}
public UsageStats[] newArray(int size) {
return new UsageStats[size];
}
};
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2014 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 android.app;
import android.content.Context;
import android.os.ParcelableParcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import com.android.internal.app.IUsageStats;
/**
* Access to usage stats data.
* @hide
*/
public class UsageStatsManager {
final Context mContext;
final IUsageStats mService;
/** @hide */
public UsageStatsManager(Context context) {
mContext = context;
mService = IUsageStats.Stub.asInterface(ServiceManager.getService(
Context.USAGE_STATS_SERVICE));
}
public UsageStats getCurrentStats() {
try {
ParcelableParcel in = mService.getCurrentStats(mContext.getOpPackageName());
if (in != null) {
return new UsageStats(in.getParcel(), false);
}
} catch (RemoteException e) {
// About to die.
}
return new UsageStats();
}
}

View File

@@ -2682,6 +2682,16 @@ public abstract class Context {
*/
public static final String NETWORK_SCORE_SERVICE = "network_score";
/**
* Use with {@link #getSystemService} to retrieve a {@link
* android.app.UsageStatsManager} for interacting with the status bar.
*
* @see #getSystemService
* @see android.app.UsageStatsManager
* @hide
*/
public static final String USAGE_STATS_SERVICE = "usagestats";
/**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.

View File

@@ -0,0 +1,19 @@
/*
** Copyright 2014, 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 android.os;
parcelable ParcelableParcel;