summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk4
-rw-r--r--core/java/android/app/ActivityManager.java14
-rw-r--r--core/java/android/app/AppOpsManager.java11
-rw-r--r--core/java/android/app/ContextImpl.java5
-rw-r--r--core/java/android/app/UsageStats.aidl20
-rw-r--r--core/java/android/app/UsageStats.java406
-rw-r--r--core/java/android/app/UsageStatsManager.java51
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/os/ParcelableParcel.aidl (renamed from core/java/com/android/internal/os/PkgUsageStats.aidl)25
-rw-r--r--core/java/com/android/internal/app/IUsageStats.aidl10
-rw-r--r--core/java/com/android/internal/os/PkgUsageStats.java94
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/UsageStatsService.java384
13 files changed, 756 insertions, 280 deletions
diff --git a/Android.mk b/Android.mk
index 3f1daf3..5970901 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,8 +76,8 @@ LOCAL_SRC_FILES += \
core/java/android/app/ISearchManagerCallback.aidl \
core/java/android/app/IServiceConnection.aidl \
core/java/android/app/IStopUserCallback.aidl \
- core/java/android/app/task/ITaskCallback.aidl \
- core/java/android/app/task/ITaskService.aidl \
+ core/java/android/app/task/ITaskCallback.aidl \
+ core/java/android/app/task/ITaskService.aidl \
core/java/android/app/IThumbnailRetriever.aidl \
core/java/android/app/ITransientNotification.aidl \
core/java/android/app/IUiAutomationConnection.aidl \
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5d809d8..044727d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -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];
}
/**
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b616c1e..d813dab 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -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>();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5ed5030..801182d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -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) {
diff --git a/core/java/android/app/UsageStats.aidl b/core/java/android/app/UsageStats.aidl
new file mode 100644
index 0000000..7dee70a
--- /dev/null
+++ b/core/java/android/app/UsageStats.aidl
@@ -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;
diff --git a/core/java/android/app/UsageStats.java b/core/java/android/app/UsageStats.java
new file mode 100644
index 0000000..0aeba59
--- /dev/null
+++ b/core/java/android/app/UsageStats.java
@@ -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];
+ }
+ };
+}
diff --git a/core/java/android/app/UsageStatsManager.java b/core/java/android/app/UsageStatsManager.java
new file mode 100644
index 0000000..fbf9c3b
--- /dev/null
+++ b/core/java/android/app/UsageStatsManager.java
@@ -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();
+ }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 042ee28..a059e48 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2683,6 +2683,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.
*
diff --git a/core/java/com/android/internal/os/PkgUsageStats.aidl b/core/java/android/os/ParcelableParcel.aidl
index 8305271..61f730c 100644
--- a/core/java/com/android/internal/os/PkgUsageStats.aidl
+++ b/core/java/android/os/ParcelableParcel.aidl
@@ -1,20 +1,19 @@
-/* //device/java/android/android/content/Intent.aidl
+/*
+** Copyright 2014, The Android Open Source Project
**
-** Copyright 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
**
-** 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
**
-** 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
+** 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.internal.os;
+package android.os;
-parcelable PkgUsageStats;
+parcelable ParcelableParcel;
diff --git a/core/java/com/android/internal/app/IUsageStats.aidl b/core/java/com/android/internal/app/IUsageStats.aidl
index 1ea7409..7e7f0e1 100644
--- a/core/java/com/android/internal/app/IUsageStats.aidl
+++ b/core/java/com/android/internal/app/IUsageStats.aidl
@@ -16,13 +16,17 @@
package com.android.internal.app;
+import android.app.UsageStats;
import android.content.ComponentName;
-import com.android.internal.os.PkgUsageStats;
+import android.content.res.Configuration;
+import android.os.ParcelableParcel;
interface IUsageStats {
void noteResumeComponent(in ComponentName componentName);
void notePauseComponent(in ComponentName componentName);
void noteLaunchTime(in ComponentName componentName, int millis);
- PkgUsageStats getPkgUsageStats(in ComponentName componentName);
- PkgUsageStats[] getAllPkgUsageStats();
+ void noteStartConfig(in Configuration config);
+ UsageStats.PackageStats getPkgUsageStats(String callingPkg, in ComponentName componentName);
+ UsageStats.PackageStats[] getAllPkgUsageStats(String callingPkg);
+ ParcelableParcel getCurrentStats(String callingPkg);
}
diff --git a/core/java/com/android/internal/os/PkgUsageStats.java b/core/java/com/android/internal/os/PkgUsageStats.java
deleted file mode 100644
index 8c2c405..0000000
--- a/core/java/com/android/internal/os/PkgUsageStats.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2009 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.internal.os;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * implementation of PkgUsageStats associated with an
- * application package.
- * @hide
- */
-public class PkgUsageStats implements Parcelable {
- public String packageName;
- public int launchCount;
- public long usageTime;
- public Map<String, Long> componentResumeTimes;
-
- public static final Parcelable.Creator<PkgUsageStats> CREATOR
- = new Parcelable.Creator<PkgUsageStats>() {
- public PkgUsageStats createFromParcel(Parcel in) {
- return new PkgUsageStats(in);
- }
-
- public PkgUsageStats[] newArray(int size) {
- return new PkgUsageStats[size];
- }
- };
-
- public String toString() {
- return "PkgUsageStats{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + packageName + "}";
- }
-
- public PkgUsageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
- packageName = pkgName;
- launchCount = count;
- usageTime = time;
- componentResumeTimes = new HashMap<String, Long>(lastResumeTimes);
- }
-
- public PkgUsageStats(Parcel source) {
- packageName = source.readString();
- launchCount = source.readInt();
- usageTime = source.readLong();
- final int N = source.readInt();
- componentResumeTimes = new HashMap<String, Long>(N);
- for (int i = 0; i < N; i++) {
- String component = source.readString();
- long lastResumeTime = source.readLong();
- componentResumeTimes.put(component, lastResumeTime);
- }
- }
-
- public PkgUsageStats(PkgUsageStats pStats) {
- packageName = pStats.packageName;
- launchCount = pStats.launchCount;
- usageTime = pStats.usageTime;
- componentResumeTimes = new HashMap<String, Long>(pStats.componentResumeTimes);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int parcelableFlags) {
- dest.writeString(packageName);
- dest.writeInt(launchCount);
- dest.writeLong(usageTime);
- dest.writeInt(componentResumeTimes.size());
- for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
- dest.writeString(ent.getKey());
- dest.writeLong(ent.getValue());
- }
- }
-}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index efc5606..09e7e12 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9570,6 +9570,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
mAppOpsService.systemReady();
+ mUsageStatsService.systemReady();
mSystemReady = true;
}
@@ -14391,6 +14392,7 @@ public final class ActivityManagerService extends ActivityManagerNative
newConfig.seq = mConfigurationSeq;
mConfiguration = newConfig;
Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
+ mUsageStatsService.noteStartConfig(newConfig);
final Configuration configCopy = new Configuration(mConfiguration);
diff --git a/services/core/java/com/android/server/am/UsageStatsService.java b/services/core/java/com/android/server/am/UsageStatsService.java
index 42cf900..4a5a554 100644
--- a/services/core/java/com/android/server/am/UsageStatsService.java
+++ b/services/core/java/com/android/server/am/UsageStatsService.java
@@ -17,26 +17,31 @@
package com.android.server.am;
import android.app.AppGlobals;
+import android.app.AppOpsManager;
+import android.app.UsageStats;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.os.Binder;
import android.os.IBinder;
import android.os.FileUtils;
import android.os.Parcel;
+import android.os.ParcelableParcel;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.TimeUtils;
import android.util.Xml;
import com.android.internal.app.IUsageStats;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.PkgUsageStats;
import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
@@ -46,7 +51,6 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -55,8 +59,6 @@ import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -75,7 +77,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
private static final String TAG = "UsageStats";
// Current on-disk Parcel version
- private static final int VERSION = 1008;
+ private static final int VERSION = 1010;
private static final int CHECKIN_VERSION = 4;
@@ -94,13 +96,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
static IUsageStats sService;
private Context mContext;
- // structure used to maintain statistics since the last checkin.
- final private ArrayMap<String, PkgUsageStatsExtended> mStats
- = new ArrayMap<String, PkgUsageStatsExtended>();
+ private AppOpsManager mAppOps;
- // Maintains the last time any component was resumed, for all time.
- final private ArrayMap<String, ArrayMap<String, Long>> mLastResumeTimes
- = new ArrayMap<String, ArrayMap<String, Long>>();
+ // structure used to maintain statistics since the last checkin.
+ private LocalUsageStats mStats = new LocalUsageStats();
// To remove last-resume time stats when a pacakge is removed.
private PackageMonitor mPackageMonitor;
@@ -115,6 +114,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
private String mLastResumedPkg;
private String mLastResumedComp;
private boolean mIsResumed;
+ private ConfigUsageStatsExtended mCurrentConfigStats;
private File mFile;
private AtomicFile mHistoryFile;
private String mFileLeaf;
@@ -127,6 +127,30 @@ public final class UsageStatsService extends IUsageStats.Stub {
private final AtomicLong mLastWriteElapsedTime = new AtomicLong(0);
private final AtomicBoolean mUnforcedDiskWriteRunning = new AtomicBoolean(false);
+ static class LocalUsageStats extends UsageStats {
+ public LocalUsageStats() {
+ }
+ public LocalUsageStats(Parcel in, boolean extended) {
+ super(in, extended);
+ }
+ @Override
+ public PackageStats onNewPackageStats(String pkgName) {
+ return new PkgUsageStatsExtended(pkgName);
+ }
+ @Override
+ public PackageStats onNewPackageStats(Parcel in) {
+ return new PkgUsageStatsExtended(in);
+ }
+ @Override
+ public ConfigurationStats onNewConfigurationStats(Configuration config) {
+ return new ConfigUsageStatsExtended(config);
+ }
+ @Override
+ public ConfigurationStats onNewConfigurationStats(Parcel source) {
+ return new ConfigUsageStatsExtended(source);
+ }
+ }
+
static class TimeStats {
int mCount;
final int[] mTimes = new int[NUM_LAUNCH_TIME_BINS];
@@ -166,27 +190,18 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- static class PkgUsageStatsExtended {
+ static class PkgUsageStatsExtended extends UsageStats.PackageStats {
final ArrayMap<String, TimeStats> mLaunchTimes
= new ArrayMap<String, TimeStats>();
final ArrayMap<String, TimeStats> mFullyDrawnTimes
= new ArrayMap<String, TimeStats>();
- int mLaunchCount;
- long mUsageTime;
- long mPausedTime;
- long mResumedTime;
- PkgUsageStatsExtended() {
- mLaunchCount = 0;
- mUsageTime = 0;
+ PkgUsageStatsExtended(String pkgName) {
+ super(pkgName);
}
PkgUsageStatsExtended(Parcel in) {
- mLaunchCount = in.readInt();
- mUsageTime = in.readLong();
- if (localLOGV) Slog.v(TAG, "Launch count: " + mLaunchCount
- + ", Usage time:" + mUsageTime);
-
+ super(in);
final int numLaunchTimeStats = in.readInt();
if (localLOGV) Slog.v(TAG, "Reading launch times: " + numLaunchTimeStats);
mLaunchTimes.ensureCapacity(numLaunchTimeStats);
@@ -208,18 +223,6 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- void updateResume(String comp, boolean launched) {
- if (launched) {
- mLaunchCount++;
- }
- mResumedTime = SystemClock.elapsedRealtime();
- }
-
- void updatePause() {
- mPausedTime = SystemClock.elapsedRealtime();
- mUsageTime += (mPausedTime - mResumedTime);
- }
-
void addLaunchCount(String comp) {
TimeStats times = mLaunchTimes.get(comp);
if (times == null) {
@@ -247,9 +250,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
times.add(millis);
}
- void writeToParcel(Parcel out) {
- out.writeInt(mLaunchCount);
- out.writeLong(mUsageTime);
+ public void writeExtendedToParcel(Parcel out, int parcelableFlags) {
final int numLaunchTimeStats = mLaunchTimes.size();
out.writeInt(numLaunchTimeStats);
for (int i=0; i<numLaunchTimeStats; i++) {
@@ -264,11 +265,21 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- void clear() {
+ @Override
+ public boolean clearUsageTimes() {
mLaunchTimes.clear();
mFullyDrawnTimes.clear();
- mLaunchCount = 0;
- mUsageTime = 0;
+ return super.clearUsageTimes();
+ }
+ }
+
+ static class ConfigUsageStatsExtended extends UsageStats.ConfigurationStats {
+ ConfigUsageStatsExtended(Configuration config) {
+ super(config);
+ }
+
+ ConfigUsageStatsExtended(Parcel in) {
+ super(in);
}
}
@@ -364,18 +375,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
+ VERSION + "; dropping");
return;
}
- int N = in.readInt();
- while (N > 0) {
- N--;
- String pkgName = in.readString();
- if (pkgName == null) {
- break;
- }
- if (localLOGV) Slog.v(TAG, "Reading package #" + N + ": " + pkgName);
- PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
- synchronized (mStatsLock) {
- mStats.put(pkgName, pus);
- }
+ LocalUsageStats stats = new LocalUsageStats(in, true);
+ synchronized (mStatsLock) {
+ mStats = stats;
}
}
@@ -419,12 +421,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
try {
long lastResumeTime = Long.parseLong(lastResumeTimeStr);
synchronized (mStatsLock) {
- ArrayMap<String, Long> lrt = mLastResumeTimes.get(pkg);
- if (lrt == null) {
- lrt = new ArrayMap<String, Long>();
- mLastResumeTimes.put(pkg, lrt);
- }
- lrt.put(comp, lastResumeTime);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)
+ mStats.getOrCreatePackageStats(pkg);
+ pus.componentResumeTimes.put(comp, lastResumeTime);
}
} catch (NumberFormatException e) {
}
@@ -543,6 +542,15 @@ public final class UsageStatsService extends IUsageStats.Stub {
return;
}
+ Parcel out = Parcel.obtain();
+ synchronized (mStatsLock) {
+ out.writeInt(VERSION);
+ mStats.writeExtendedToParcel(out, 0);
+ if (dayChanged) {
+ mStats.clearUsageTimes();
+ }
+ }
+
synchronized (mFileLock) {
// Get the most recent file
mFileLeaf = getCurrentDateStr(FILE_PREFIX);
@@ -553,6 +561,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
if (!backupFile.exists()) {
if (!mFile.renameTo(backupFile)) {
Slog.w(TAG, "Failed to persist new stats");
+ out.recycle();
return;
}
} else {
@@ -562,14 +571,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
try {
// Write mStats to file
- writeStatsFLOCK(mFile);
+ writeStatsFLOCK(mFile, out);
mLastWriteElapsedTime.set(currElapsedTime);
if (dayChanged) {
mLastWriteDay.set(curDay);
- // clear stats
- synchronized (mStats) {
- mStats.clear();
- }
mFile = new File(mDir, mFileLeaf);
checkFileLimitFLOCK();
}
@@ -590,17 +595,15 @@ public final class UsageStatsService extends IUsageStats.Stub {
backupFile.renameTo(mFile);
}
}
+ out.recycle();
}
if (localLOGV) Slog.d(TAG, "Dumped usage stats.");
}
- private void writeStatsFLOCK(File file) throws IOException {
+ private void writeStatsFLOCK(File file, Parcel parcel) throws IOException {
FileOutputStream stream = new FileOutputStream(file);
try {
- Parcel out = Parcel.obtain();
- writeStatsToParcelFLOCK(out);
- stream.write(out.marshall());
- out.recycle();
+ stream.write(parcel.marshall());
stream.flush();
} finally {
FileUtils.sync(stream);
@@ -608,29 +611,14 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- private void writeStatsToParcelFLOCK(Parcel out) {
- synchronized (mStatsLock) {
- out.writeInt(VERSION);
- Set<String> keys = mStats.keySet();
- out.writeInt(keys.size());
- for (String key : keys) {
- PkgUsageStatsExtended pus = mStats.get(key);
- out.writeString(key);
- pus.writeToParcel(out);
- }
- }
- }
-
/** Filter out stats for any packages which aren't present anymore. */
private void filterHistoryStats() {
synchronized (mStatsLock) {
IPackageManager pm = AppGlobals.getPackageManager();
- for (int i=0; i<mLastResumeTimes.size(); i++) {
- String pkg = mLastResumeTimes.keyAt(i);
+ for (int i=mStats.mPackages.size()-1; i>=0; i--) {
try {
- if (pm.getPackageUid(pkg, 0) < 0) {
- mLastResumeTimes.removeAt(i);
- i--;
+ if (pm.getPackageUid(mStats.mPackages.valueAt(i).getPackageName(), 0) < 0) {
+ mStats.mPackages.removeAt(i);
}
} catch (RemoteException e) {
}
@@ -648,10 +636,12 @@ public final class UsageStatsService extends IUsageStats.Stub {
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
out.startTag(null, "usage-history");
synchronized (mStatsLock) {
- for (int i=0; i<mLastResumeTimes.size(); i++) {
+ int NP = mStats.mPackages.size();
+ for (int i=0; i<NP; i++) {
+ UsageStats.PackageStats ps = mStats.mPackages.valueAt(i);
out.startTag(null, "pkg");
- out.attribute(null, "name", mLastResumeTimes.keyAt(i));
- ArrayMap<String, Long> comp = mLastResumeTimes.valueAt(i);
+ out.attribute(null, "name", ps.getPackageName());
+ ArrayMap<String, Long> comp = ps.componentResumeTimes;
for (int j=0; j<comp.size(); j++) {
out.startTag(null, "comp");
out.attribute(null, "name", comp.keyAt(j));
@@ -678,6 +668,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
ServiceManager.addService(SERVICE_NAME, asBinder());
}
+ public void systemReady() {
+ mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
+ }
+
/**
* Start watching packages to remove stats when a package is uninstalled.
* May only be called when the package manager is ready.
@@ -687,7 +681,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
@Override
public void onPackageRemovedAllUsers(String packageName, int uid) {
synchronized (mStatsLock) {
- mLastResumeTimes.remove(packageName);
+ mStats.mPackages.remove(packageName);
}
}
};
@@ -729,9 +723,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
// to recover.
if (REPORT_UNEXPECTED) Slog.i(TAG, "Unexpected resume of " + pkgName
+ " while already resumed in " + mLastResumedPkg);
- PkgUsageStatsExtended pus = mStats.get(mLastResumedPkg);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(
+ mLastResumedPkg);
if (pus != null) {
- pus.updatePause();
+ pus.pause();
}
}
}
@@ -744,22 +739,13 @@ public final class UsageStatsService extends IUsageStats.Stub {
mLastResumedComp = componentName.getClassName();
if (localLOGV) Slog.i(TAG, "started component:" + pkgName);
- PkgUsageStatsExtended pus = mStats.get(pkgName);
- if (pus == null) {
- pus = new PkgUsageStatsExtended();
- mStats.put(pkgName, pus);
- }
- pus.updateResume(mLastResumedComp, !samePackage);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)
+ mStats.getOrCreatePackageStats(pkgName);
+ pus.resume(!samePackage);
if (!sameComp) {
pus.addLaunchCount(mLastResumedComp);
}
-
- ArrayMap<String, Long> componentResumeTimes = mLastResumeTimes.get(pkgName);
- if (componentResumeTimes == null) {
- componentResumeTimes = new ArrayMap<String, Long>();
- mLastResumeTimes.put(pkgName, componentResumeTimes);
- }
- componentResumeTimes.put(mLastResumedComp, System.currentTimeMillis());
+ pus.componentResumeTimes.put(mLastResumedComp, System.currentTimeMillis());
}
}
@@ -782,13 +768,13 @@ public final class UsageStatsService extends IUsageStats.Stub {
if (localLOGV) Slog.i(TAG, "paused component:"+pkgName);
- PkgUsageStatsExtended pus = mStats.get(pkgName);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
if (pus == null) {
// Weird some error here
Slog.i(TAG, "No package stats for pkg:"+pkgName);
return;
}
- pus.updatePause();
+ pus.pause();
}
// Persist current data to file if needed.
@@ -808,7 +794,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
writeStatsToFile(false, false);
synchronized (mStatsLock) {
- PkgUsageStatsExtended pus = mStats.get(pkgName);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
if (pus != null) {
pus.addLaunchTime(componentName.getClassName(), millis);
}
@@ -827,13 +813,29 @@ public final class UsageStatsService extends IUsageStats.Stub {
writeStatsToFile(false, false);
synchronized (mStatsLock) {
- PkgUsageStatsExtended pus = mStats.get(pkgName);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
if (pus != null) {
pus.addFullyDrawnTime(componentName.getClassName(), millis);
}
}
}
+ public void noteStartConfig(Configuration config) {
+ enforceCallingPermission();
+ synchronized (mStatsLock) {
+ config = new Configuration(config);
+ ConfigUsageStatsExtended cus = (ConfigUsageStatsExtended)
+ mStats.getOrCreateConfigurationStats(config);
+ if (cus != mCurrentConfigStats) {
+ if (mCurrentConfigStats != null) {
+ mCurrentConfigStats.stop();
+ }
+ cus.start();
+ mCurrentConfigStats = cus;
+ }
+ }
+ }
+
public void enforceCallingPermission() {
if (Binder.getCallingPid() == Process.myPid()) {
return;
@@ -843,53 +845,71 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
@Override
- public PkgUsageStats getPkgUsageStats(ComponentName componentName) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+ public UsageStats.PackageStats getPkgUsageStats(String callingPkg,
+ ComponentName componentName) {
+ checkCallerPermission(callingPkg, "getPkgUsageStats");
String pkgName;
if ((componentName == null) ||
((pkgName = componentName.getPackageName()) == null)) {
return null;
}
synchronized (mStatsLock) {
- PkgUsageStatsExtended pus = mStats.get(pkgName);
- Map<String, Long> lastResumeTimes = mLastResumeTimes.get(pkgName);
- if (pus == null && lastResumeTimes == null) {
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
+ if (pus == null) {
return null;
}
- int launchCount = pus != null ? pus.mLaunchCount : 0;
- long usageTime = pus != null ? pus.mUsageTime : 0;
- return new PkgUsageStats(pkgName, launchCount, usageTime, lastResumeTimes);
+ return new UsageStats.PackageStats(pus);
}
}
@Override
- public PkgUsageStats[] getAllPkgUsageStats() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+ public UsageStats.PackageStats[] getAllPkgUsageStats(String callingPkg) {
+ checkCallerPermission(callingPkg, "getAllPkgUsageStats");
synchronized (mStatsLock) {
- int size = mLastResumeTimes.size();
- if (size <= 0) {
+ int NP = mStats.mPackages.size();
+ if (NP <= 0) {
return null;
}
- PkgUsageStats retArr[] = new PkgUsageStats[size];
- for (int i=0; i<size; i++) {
- String pkg = mLastResumeTimes.keyAt(i);
- long usageTime = 0;
- int launchCount = 0;
-
- PkgUsageStatsExtended pus = mStats.get(pkg);
- if (pus != null) {
- usageTime = pus.mUsageTime;
- launchCount = pus.mLaunchCount;
- }
- retArr[i] = new PkgUsageStats(pkg, launchCount, usageTime,
- mLastResumeTimes.valueAt(i));
+ UsageStats.PackageStats retArr[] = new UsageStats.PackageStats[NP];
+ for (int p=0; p<NP; p++) {
+ UsageStats.PackageStats ps = mStats.mPackages.valueAt(p);
+ retArr[p] = new UsageStats.PackageStats(ps);
}
return retArr;
}
}
+ @Override
+ public ParcelableParcel getCurrentStats(String callingPkg) {
+ checkCallerPermission(callingPkg, "getCurrentStats");
+ synchronized (mStatsLock) {
+ ParcelableParcel out = new ParcelableParcel(null);
+ mStats.writeToParcel(out.getParcel(), 0);
+ return out;
+ }
+ }
+
+ private void checkCallerPermission(String callingPkg, String callingOp) {
+ // Because the permission for this is system-only, its use with
+ // app ops is a little different: the op is disabled by default,
+ // and enabling it allows apps to get access even if they don't
+ // hold the permission.
+ int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_GET_USAGE_STATS, Binder.getCallingUid(),
+ callingPkg);
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ return;
+ } else if (mode != AppOpsManager.MODE_IGNORED) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_USAGE_STATS)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ }
+
+ String msg = "Package " + callingPkg + " not allowed to call " + callingOp;
+ throw new SecurityException(msg);
+ }
+
static byte[] readFully(FileInputStream stream) throws IOException {
int pos = 0;
int avail = stream.available();
@@ -963,31 +983,28 @@ public final class UsageStatsService extends IUsageStats.Stub {
return;
}
- pw.println(sb.toString());
- int N = in.readInt();
+ final LocalUsageStats stats = new LocalUsageStats(in, true);
+ final long time = SystemClock.elapsedRealtime();
- while (N > 0) {
- N--;
- String pkgName = in.readString();
- if (pkgName == null) {
- break;
- }
+ pw.println(sb.toString());
+ int NP = stats.mPackages.size();
+ for (int p=0; p<NP; p++) {
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)stats.mPackages.valueAt(p);
sb.setLength(0);
- PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
- if (packages != null && !packages.contains(pkgName)) {
+ if (packages != null && !packages.contains(pus.getPackageName())) {
// This package has not been requested -- don't print
// anything for it.
} else if (isCompactOutput) {
sb.append("P:");
- sb.append(pkgName);
+ sb.append(pus.getPackageName());
sb.append(',');
- sb.append(pus.mLaunchCount);
+ sb.append(pus.getLaunchCount());
sb.append(',');
- sb.append(pus.mUsageTime);
+ sb.append(pus.getUsageTime(time));
sb.append('\n');
final int NLT = pus.mLaunchTimes.size();
for (int i=0; i<NLT; i++) {
- sb.append("A:");
+ sb.append("L:");
String activity = pus.mLaunchTimes.keyAt(i);
sb.append(activity);
TimeStats times = pus.mLaunchTimes.valueAt(i);
@@ -1001,7 +1018,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
final int NFDT = pus.mFullyDrawnTimes.size();
for (int i=0; i<NFDT; i++) {
- sb.append("A:");
+ sb.append("D:");
String activity = pus.mFullyDrawnTimes.keyAt(i);
sb.append(activity);
TimeStats times = pus.mFullyDrawnTimes.valueAt(i);
@@ -1011,15 +1028,23 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
sb.append('\n');
}
+ final int NC = pus.componentResumeTimes.size();
+ for (int c=0; c<NC; c++) {
+ pw.print("R:"); pw.print(pus.componentResumeTimes.keyAt(c)); pw.print(",");
+ pw.println(pus.componentResumeTimes.valueAt(c));
+ }
} else {
sb.append(" ");
- sb.append(pkgName);
- sb.append(": ");
- sb.append(pus.mLaunchCount);
- sb.append(" times, ");
- sb.append(pus.mUsageTime);
- sb.append(" ms");
+ sb.append(pus.getPackageName());
+ if (pus.getLaunchCount() != 0 || pus.getUsageTime(time) != 0) {
+ sb.append(": ");
+ sb.append(pus.getLaunchCount());
+ sb.append(" times, ");
+ TimeUtils.formatDuration(pus.getUsageTime(time), sb);
+ } else {
+ sb.append(":");
+ }
sb.append('\n');
final int NLT = pus.mLaunchTimes.size();
for (int i=0; i<NLT; i++) {
@@ -1084,10 +1109,50 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
sb.append('\n');
}
+ final int NC = pus.componentResumeTimes.size();
+ for (int c=0; c<NC; c++) {
+ sb.append(" ");
+ sb.append(pus.componentResumeTimes.keyAt(c));
+ sb.append(" last resumed ");
+ sb.append(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+ pus.componentResumeTimes.valueAt(c)).toString());
+ sb.append('\n');
+ }
}
pw.write(sb.toString());
}
+ if (packages == null) {
+ int NC = stats.mConfigurations.size();
+ for (int c=0; c<NC; c++) {
+ ConfigUsageStatsExtended cus
+ = (ConfigUsageStatsExtended)stats.mConfigurations.valueAt(c);
+ sb.setLength(0);
+ if (isCompactOutput) {
+ sb.append("C:"); sb.append(cus.getConfiguration().toString());
+ sb.append(","); sb.append(cus.getUsageCount()); sb.append(",");
+ sb.append(cus.getUsageTime(time));
+ } else {
+ sb.append(" ");
+ sb.append(cus.getConfiguration().toString());
+ sb.append(":\n");
+ if (cus.getUsageCount() != 0 || cus.getUsageTime(time) != 0) {
+ sb.append(" Used ");
+ sb.append(cus.getUsageCount());
+ sb.append(" times, ");
+ TimeUtils.formatDuration(cus.getUsageTime(time), sb);
+ sb.append("\n");
+ }
+ if (cus.getLastUsedTime() > 0) {
+ sb.append(" Last used: ");
+ sb.append(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+ cus.getLastUsedTime()).toString());
+ sb.append("\n");
+ }
+ }
+ pw.write(sb.toString());
+ }
+ }
}
/**
@@ -1174,5 +1239,4 @@ public final class UsageStatsService extends IUsageStats.Stub {
collectDumpInfoFLOCK(pw, isCompactOutput, deleteAfterPrint, packages);
}
}
-
}