summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Varun Shah <varunshah@google.com> 2019-09-17 13:48:38 -0700
committer Varun Shah <varunshah@google.com> 2019-10-08 21:24:15 -0700
commit358d5006234b1e5f0feb95f72ef42e592d28e661 (patch)
tree36966604501cff3b3f776af1aa7bb2c0005f6d67
parente1ba9cde53546caca0befe65611bac10f7f67622 (diff)
Catch exceptions in UsageStatsService on bad data.
Instead of throwing exceptions from UsageStatsService and potentially crashing the system server, catch exception on reading/writing bad data and log the exception. Also ensure proper handling of deobfuscating bad data. Bug: 140459061 Bug: 135484470 Test: atest IntervalStatsTests Test: atest UsageStatsDatabaseTest Change-Id: I17d6ad5e377a2636ff42c9b422fe6ddf1201fc08
-rw-r--r--core/java/android/app/usage/EventList.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java191
-rw-r--r--services/usage/java/com/android/server/usage/IntervalStats.java51
-rw-r--r--services/usage/java/com/android/server/usage/PackagesTokenData.java13
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsDatabase.java26
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsProto.java140
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsProtoV2.java262
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java2
8 files changed, 544 insertions, 156 deletions
diff --git a/core/java/android/app/usage/EventList.java b/core/java/android/app/usage/EventList.java
index 8c0340585573..afdcbe6d164f 100644
--- a/core/java/android/app/usage/EventList.java
+++ b/core/java/android/app/usage/EventList.java
@@ -79,6 +79,21 @@ public class EventList {
}
/**
+ * Removes the event at the given index.
+ *
+ * @param index the index of the event to remove
+ * @return the event removed, or {@code null} if the index was out of bounds
+ */
+ public UsageEvents.Event remove(int index) {
+ try {
+ return mEvents.remove(index);
+ } catch (IndexOutOfBoundsException e) {
+ // catch and handle the exception here instead of throwing it to the client
+ return null;
+ }
+ }
+
+ /**
* Finds the index of the first event whose timestamp is greater than or equal to the given
* timestamp.
*
diff --git a/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java
new file mode 100644
index 000000000000..f1b2ef811885
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2019 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.usage;
+
+import static android.app.usage.UsageEvents.Event.MAX_EVENT_TYPE;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import android.app.usage.UsageEvents;
+import android.content.res.Configuration;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IntervalStatsTests {
+ private static final int NUMBER_OF_PACKAGES = 7;
+ private static final int NUMBER_OF_EVENTS_PER_PACKAGE = 200;
+ private static final int NUMBER_OF_EVENTS = NUMBER_OF_PACKAGES * NUMBER_OF_EVENTS_PER_PACKAGE;
+
+ private long mEndTime = 0;
+
+ private void populateIntervalStats(IntervalStats intervalStats) {
+ final int timeProgression = 23;
+ long time = System.currentTimeMillis() - (NUMBER_OF_EVENTS * timeProgression);
+
+ intervalStats.majorVersion = 7;
+ intervalStats.minorVersion = 8;
+ intervalStats.beginTime = time;
+ intervalStats.interactiveTracker.count = 2;
+ intervalStats.interactiveTracker.duration = 111111;
+ intervalStats.nonInteractiveTracker.count = 3;
+ intervalStats.nonInteractiveTracker.duration = 222222;
+ intervalStats.keyguardShownTracker.count = 4;
+ intervalStats.keyguardShownTracker.duration = 333333;
+ intervalStats.keyguardHiddenTracker.count = 5;
+ intervalStats.keyguardHiddenTracker.duration = 4444444;
+
+ for (int i = 0; i < NUMBER_OF_EVENTS; i++) {
+ UsageEvents.Event event = new UsageEvents.Event();
+ final int packageInt = ((i / 3) % NUMBER_OF_PACKAGES); // clusters of 3 events
+ event.mPackage = "fake.package.name" + packageInt;
+ if (packageInt == 3) {
+ // Third app is an instant app
+ event.mFlags |= UsageEvents.Event.FLAG_IS_PACKAGE_INSTANT_APP;
+ }
+
+ final int instanceId = i % 11;
+ event.mClass = ".fake.class.name" + instanceId;
+ event.mTimeStamp = time;
+ event.mEventType = i % (MAX_EVENT_TYPE + 1); //"random" event type
+ event.mInstanceId = instanceId;
+
+
+ final int rootPackageInt = (i % 5); // 5 "apps" start each task
+ event.mTaskRootPackage = "fake.package.name" + rootPackageInt;
+
+ final int rootClassInt = i % 6;
+ event.mTaskRootClass = ".fake.class.name" + rootClassInt;
+
+ switch (event.mEventType) {
+ case UsageEvents.Event.CONFIGURATION_CHANGE:
+ event.mConfiguration = new Configuration(); //empty config
+ break;
+ case UsageEvents.Event.SHORTCUT_INVOCATION:
+ event.mShortcutId = "shortcut" + (i % 8); //"random" shortcut
+ break;
+ case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
+ //"random" bucket and reason
+ event.mBucketAndReason = (((i % 5 + 1) * 10) << 16) & (i % 5 + 1) << 8;
+ break;
+ case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+ event.mNotificationChannelId = "channel" + (i % 5); //"random" channel
+ break;
+ }
+
+ intervalStats.addEvent(event);
+ intervalStats.update(event.mPackage, event.mClass, event.mTimeStamp, event.mEventType,
+ event.mInstanceId);
+
+ time += timeProgression; // Arbitrary progression of time
+ }
+ mEndTime = time;
+
+ final Configuration config1 = new Configuration();
+ config1.fontScale = 3.3f;
+ config1.mcc = 4;
+ intervalStats.getOrCreateConfigurationStats(config1);
+
+ final Configuration config2 = new Configuration();
+ config2.mnc = 5;
+ config2.setLocale(new Locale("en", "US"));
+ intervalStats.getOrCreateConfigurationStats(config2);
+
+ intervalStats.activeConfiguration = config2;
+ }
+
+ @Test
+ public void testObfuscation() {
+ final IntervalStats intervalStats = new IntervalStats();
+ populateIntervalStats(intervalStats);
+
+ final PackagesTokenData packagesTokenData = new PackagesTokenData();
+ intervalStats.obfuscateData(packagesTokenData);
+
+ // data is populated with 7 different "apps"
+ assertEquals(packagesTokenData.tokensToPackagesMap.size(), NUMBER_OF_PACKAGES);
+ assertEquals(packagesTokenData.packagesToTokensMap.size(), NUMBER_OF_PACKAGES);
+ assertEquals(packagesTokenData.counter, NUMBER_OF_PACKAGES + 1);
+
+ assertEquals(intervalStats.events.size(), NUMBER_OF_EVENTS);
+ assertEquals(intervalStats.packageStats.size(), NUMBER_OF_PACKAGES);
+ }
+
+ @Test
+ public void testDeobfuscation() {
+ final IntervalStats intervalStats = new IntervalStats();
+ populateIntervalStats(intervalStats);
+
+ final PackagesTokenData packagesTokenData = new PackagesTokenData();
+ intervalStats.obfuscateData(packagesTokenData);
+ intervalStats.deobfuscateData(packagesTokenData);
+
+ // ensure deobfuscation doesn't update any of the mappings data
+ assertEquals(packagesTokenData.tokensToPackagesMap.size(), NUMBER_OF_PACKAGES);
+ assertEquals(packagesTokenData.packagesToTokensMap.size(), NUMBER_OF_PACKAGES);
+ assertEquals(packagesTokenData.counter, NUMBER_OF_PACKAGES + 1);
+
+ // ensure deobfuscation didn't remove any events or usage stats
+ assertEquals(intervalStats.events.size(), NUMBER_OF_EVENTS);
+ assertEquals(intervalStats.packageStats.size(), NUMBER_OF_PACKAGES);
+ }
+
+ @Test
+ public void testBadDataOnDeobfuscation() {
+ final IntervalStats intervalStats = new IntervalStats();
+ populateIntervalStats(intervalStats);
+
+ final PackagesTokenData packagesTokenData = new PackagesTokenData();
+ intervalStats.obfuscateData(packagesTokenData);
+ intervalStats.packageStats.clear();
+
+ // remove the mapping for token 2
+ packagesTokenData.tokensToPackagesMap.remove(2);
+
+ intervalStats.deobfuscateData(packagesTokenData);
+ // deobfuscation should have removed all events mapped to package token 2
+ assertEquals(intervalStats.events.size(),
+ NUMBER_OF_EVENTS - NUMBER_OF_EVENTS_PER_PACKAGE - 1);
+ assertEquals(intervalStats.packageStats.size(), NUMBER_OF_PACKAGES - 1);
+ }
+
+ @Test
+ public void testBadPackageDataOnDeobfuscation() {
+ final IntervalStats intervalStats = new IntervalStats();
+ populateIntervalStats(intervalStats);
+
+ final PackagesTokenData packagesTokenData = new PackagesTokenData();
+ intervalStats.obfuscateData(packagesTokenData);
+ intervalStats.packageStats.clear();
+
+ // remove mapping number 2 within package 3 (random)
+ packagesTokenData.tokensToPackagesMap.valueAt(3).remove(2);
+
+ intervalStats.deobfuscateData(packagesTokenData);
+ // deobfuscation should not have removed all events for a package - however, it's possible
+ // that some events were removed because of how shortcut and notification events are handled
+ assertTrue(intervalStats.events.size() > NUMBER_OF_EVENTS - NUMBER_OF_EVENTS_PER_PACKAGE);
+ assertEquals(intervalStats.packageStats.size(), NUMBER_OF_PACKAGES);
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 02e48928a7ba..7ea669d1f0a2 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -45,6 +45,7 @@ import android.content.res.Configuration;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.proto.ProtoInputStream;
@@ -55,6 +56,8 @@ import java.io.IOException;
import java.util.List;
public class IntervalStats {
+ private static final String TAG = "IntervalStats";
+
public static final int CURRENT_MAJOR_VERSION = 1;
public static final int CURRENT_MINOR_VERSION = 1;
public int majorVersion = CURRENT_MAJOR_VERSION;
@@ -453,6 +456,10 @@ public class IntervalStats {
final UsageStats usageStats = packageStatsObfuscated.valueAt(statsIndex);
usageStats.mPackageName = packagesTokenData.getString(packageToken,
PackagesTokenData.PACKAGE_NAME_INDEX);
+ if (usageStats.mPackageName == null) {
+ Slog.e(TAG, "Unable to parse usage stats package " + packageToken);
+ continue;
+ }
// Update chooser counts
final int chooserActionsSize = usageStats.mChooserCountsObfuscated.size();
@@ -460,6 +467,11 @@ public class IntervalStats {
final ArrayMap<String, Integer> categoryCountsMap = new ArrayMap<>();
final int actionToken = usageStats.mChooserCountsObfuscated.keyAt(actionIndex);
final String action = packagesTokenData.getString(packageToken, actionToken);
+ if (action == null) {
+ Slog.i(TAG, "Unable to parse chooser action " + actionToken
+ + " for package " + packageToken);
+ continue;
+ }
final SparseIntArray categoryCounts =
usageStats.mChooserCountsObfuscated.valueAt(actionIndex);
final int categoriesSize = categoryCounts.size();
@@ -467,6 +479,11 @@ public class IntervalStats {
final int categoryToken = categoryCounts.keyAt(categoryIndex);
final String category = packagesTokenData.getString(packageToken,
categoryToken);
+ if (category == null) {
+ Slog.i(TAG, "Unable to parse chooser category " + categoryToken
+ + " for package " + packageToken);
+ continue;
+ }
categoryCountsMap.put(category, categoryCounts.valueAt(categoryIndex));
}
usageStats.mChooserCounts.put(action, categoryCountsMap);
@@ -481,22 +498,39 @@ public class IntervalStats {
* shortcut or notification channel tokens.
*/
private void deobfuscateEvents(PackagesTokenData packagesTokenData) {
- final int eventsSize = this.events.size();
- for (int i = 0; i < eventsSize; i++) {
+ for (int i = this.events.size() - 1; i >= 0; i--) {
final Event event = this.events.get(i);
final int packageToken = event.mPackageToken;
event.mPackage = packagesTokenData.getString(packageToken,
PackagesTokenData.PACKAGE_NAME_INDEX);
+ if (event.mPackage == null) {
+ Slog.e(TAG, "Unable to parse event package " + packageToken);
+ this.events.remove(i);
+ continue;
+ }
+
if (event.mClassToken != PackagesTokenData.UNASSIGNED_TOKEN) {
event.mClass = packagesTokenData.getString(packageToken, event.mClassToken);
+ if (event.mClass == null) {
+ Slog.i(TAG, "Unable to parse class " + event.mClassToken
+ + " for package " + packageToken);
+ }
}
if (event.mTaskRootPackageToken != PackagesTokenData.UNASSIGNED_TOKEN) {
event.mTaskRootPackage = packagesTokenData.getString(packageToken,
event.mTaskRootPackageToken);
+ if (event.mTaskRootPackage == null) {
+ Slog.i(TAG, "Unable to parse task root package " + event.mTaskRootPackageToken
+ + " for package " + packageToken);
+ }
}
if (event.mTaskRootClassToken != PackagesTokenData.UNASSIGNED_TOKEN) {
event.mTaskRootClass = packagesTokenData.getString(packageToken,
event.mTaskRootClassToken);
+ if (event.mTaskRootClass == null) {
+ Slog.i(TAG, "Unable to parse task root class " + event.mTaskRootClassToken
+ + " for package " + packageToken);
+ }
}
switch (event.mEventType) {
case CONFIGURATION_CHANGE:
@@ -507,10 +541,23 @@ public class IntervalStats {
case SHORTCUT_INVOCATION:
event.mShortcutId = packagesTokenData.getString(packageToken,
event.mShortcutIdToken);
+ if (event.mShortcutId == null) {
+ Slog.e(TAG, "Unable to parse shortcut " + event.mShortcutIdToken
+ + " for package " + packageToken);
+ this.events.remove(i);
+ continue;
+ }
break;
case NOTIFICATION_INTERRUPTION:
event.mNotificationChannelId = packagesTokenData.getString(packageToken,
event.mNotificationChannelIdToken);
+ if (event.mNotificationChannelId == null) {
+ Slog.e(TAG, "Unable to parse notification channel "
+ + event.mNotificationChannelIdToken + " for package "
+ + packageToken);
+ this.events.remove(i);
+ continue;
+ }
break;
}
}
diff --git a/services/usage/java/com/android/server/usage/PackagesTokenData.java b/services/usage/java/com/android/server/usage/PackagesTokenData.java
index 8e4c639a54e4..3beee678d7ff 100644
--- a/services/usage/java/com/android/server/usage/PackagesTokenData.java
+++ b/services/usage/java/com/android/server/usage/PackagesTokenData.java
@@ -16,6 +16,7 @@
package com.android.server.usage;
import android.util.ArrayMap;
+import android.util.Slog;
import android.util.SparseArray;
import java.util.ArrayList;
@@ -107,9 +108,17 @@ public final class PackagesTokenData {
*
* @param packageToken the package token for which this token belongs to
* @param token the token whose string needs to be fetched
- * @return the string representing the given token
+ * @return the string representing the given token or {@code null} if not found
*/
public String getString(int packageToken, int token) {
- return tokensToPackagesMap.get(packageToken).get(token);
+ try {
+ return tokensToPackagesMap.get(packageToken).get(token);
+ } catch (NullPointerException npe) {
+ Slog.e("PackagesTokenData",
+ "Unable to find tokenized strings for package " + packageToken, npe);
+ return null;
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index d29b77c78e1c..5c785f76d4db 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -869,11 +869,19 @@ public class UsageStatsDatabase {
UsageStatsXml.write(out, stats);
break;
case 4:
- UsageStatsProto.write(out, stats);
+ try {
+ UsageStatsProto.write(out, stats);
+ } catch (IOException | IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write interval stats to proto.", e);
+ }
break;
case 5:
stats.obfuscateData(packagesTokenData);
- UsageStatsProtoV2.write(out, stats);
+ try {
+ UsageStatsProtoV2.write(out, stats);
+ } catch (IOException | IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write interval stats to proto.", e);
+ }
break;
default:
throw new RuntimeException(
@@ -920,10 +928,18 @@ public class UsageStatsDatabase {
UsageStatsXml.read(in, statsOut);
break;
case 4:
- UsageStatsProto.read(in, statsOut);
+ try {
+ UsageStatsProto.read(in, statsOut);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read interval stats from proto.", e);
+ }
break;
case 5:
- UsageStatsProtoV2.read(in, statsOut);
+ try {
+ UsageStatsProtoV2.read(in, statsOut);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read interval stats from proto.", e);
+ }
statsOut.deobfuscateData(packagesTokenData);
break;
default:
@@ -974,6 +990,8 @@ public class UsageStatsDatabase {
UsageStatsProtoV2.writeObfuscatedData(fos, mPackagesTokenData);
file.finishWrite(fos);
fos = null;
+ } catch (IOException | IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write obfuscated data to proto.", e);
} finally {
file.failWrite(fos);
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index 53ab230ef4a1..5d1f730694ef 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -120,10 +120,14 @@ final class UsageStatsProto {
IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT);
break;
case (int) IntervalStatsProto.UsageStats.CHOOSER_ACTIONS:
- final long chooserToken = proto.start(
- IntervalStatsProto.UsageStats.CHOOSER_ACTIONS);
- loadChooserCounts(proto, stats);
- proto.end(chooserToken);
+ try {
+ final long chooserToken = proto.start(
+ IntervalStatsProto.UsageStats.CHOOSER_ACTIONS);
+ loadChooserCounts(proto, stats);
+ proto.end(chooserToken);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read chooser counts for " + stats.mPackageName, e);
+ }
break;
case (int) IntervalStatsProto.UsageStats.LAST_TIME_SERVICE_USED_MS:
// Time attributes stored is an offset of the beginTime.
@@ -153,20 +157,24 @@ final class UsageStatsProto {
}
private static void loadCountAndTime(ProtoInputStream proto, long fieldId,
- IntervalStats.EventTracker tracker) throws IOException {
- final long token = proto.start(fieldId);
- while (true) {
- switch (proto.nextField()) {
- case (int) IntervalStatsProto.CountAndTime.COUNT:
- tracker.count = proto.readInt(IntervalStatsProto.CountAndTime.COUNT);
- break;
- case (int) IntervalStatsProto.CountAndTime.TIME_MS:
- tracker.duration = proto.readLong(IntervalStatsProto.CountAndTime.TIME_MS);
- break;
- case ProtoInputStream.NO_MORE_FIELDS:
- proto.end(token);
- return;
+ IntervalStats.EventTracker tracker) {
+ try {
+ final long token = proto.start(fieldId);
+ while (true) {
+ switch (proto.nextField()) {
+ case (int) IntervalStatsProto.CountAndTime.COUNT:
+ tracker.count = proto.readInt(IntervalStatsProto.CountAndTime.COUNT);
+ break;
+ case (int) IntervalStatsProto.CountAndTime.TIME_MS:
+ tracker.duration = proto.readLong(IntervalStatsProto.CountAndTime.TIME_MS);
+ break;
+ case ProtoInputStream.NO_MORE_FIELDS:
+ proto.end(token);
+ return;
+ }
}
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read event tracker " + fieldId, e);
}
}
@@ -306,7 +314,7 @@ final class UsageStatsProto {
}
private static void writeStringPool(ProtoOutputStream proto, final IntervalStats stats)
- throws IOException {
+ throws IllegalArgumentException {
final long token = proto.start(IntervalStatsProto.STRINGPOOL);
final int size = stats.mStringCache.size();
proto.write(IntervalStatsProto.StringPool.SIZE, size);
@@ -317,7 +325,8 @@ final class UsageStatsProto {
}
private static void writeUsageStats(ProtoOutputStream proto, long fieldId,
- final IntervalStats stats, final UsageStats usageStats) throws IOException {
+ final IntervalStats stats, final UsageStats usageStats)
+ throws IllegalArgumentException {
final long token = proto.start(fieldId);
// Write the package name first, so loadUsageStats can avoid creating an extra object
final int packageIndex = stats.mStringCache.indexOf(usageStats.mPackageName);
@@ -347,12 +356,16 @@ final class UsageStatsProto {
proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_VISIBLE_MS,
usageStats.mTotalTimeVisible);
proto.write(IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT, usageStats.mAppLaunchCount);
- writeChooserCounts(proto, usageStats);
+ try {
+ writeChooserCounts(proto, usageStats);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write chooser counts for " + usageStats.mPackageName, e);
+ }
proto.end(token);
}
private static void writeCountAndTime(ProtoOutputStream proto, long fieldId, int count,
- long time) throws IOException {
+ long time) throws IllegalArgumentException {
final long token = proto.start(fieldId);
proto.write(IntervalStatsProto.CountAndTime.COUNT, count);
proto.write(IntervalStatsProto.CountAndTime.TIME_MS, time);
@@ -361,7 +374,7 @@ final class UsageStatsProto {
private static void writeChooserCounts(ProtoOutputStream proto, final UsageStats usageStats)
- throws IOException {
+ throws IllegalArgumentException {
if (usageStats == null || usageStats.mChooserCounts == null
|| usageStats.mChooserCounts.keySet().isEmpty()) {
return;
@@ -381,7 +394,7 @@ final class UsageStatsProto {
}
private static void writeCountsForAction(ProtoOutputStream proto,
- ArrayMap<String, Integer> counts) throws IOException {
+ ArrayMap<String, Integer> counts) throws IllegalArgumentException {
final int countsSize = counts.size();
for (int i = 0; i < countsSize; i++) {
String key = counts.keyAt(i);
@@ -397,7 +410,7 @@ final class UsageStatsProto {
private static void writeConfigStats(ProtoOutputStream proto, long fieldId,
final IntervalStats stats, final ConfigurationStats configStats, boolean isActive)
- throws IOException {
+ throws IllegalArgumentException {
final long token = proto.start(fieldId);
configStats.mConfiguration.writeToProto(proto, IntervalStatsProto.Configuration.CONFIG);
proto.write(IntervalStatsProto.Configuration.LAST_TIME_ACTIVE_MS,
@@ -410,7 +423,7 @@ final class UsageStatsProto {
}
private static void writeEvent(ProtoOutputStream proto, long fieldId, final IntervalStats stats,
- final UsageEvents.Event event) throws IOException {
+ final UsageEvents.Event event) throws IllegalArgumentException {
final long token = proto.start(fieldId);
final int packageIndex = stats.mStringCache.indexOf(event.mPackage);
if (packageIndex >= 0) {
@@ -541,17 +554,33 @@ final class UsageStatsProto {
statsOut.keyguardHiddenTracker);
break;
case (int) IntervalStatsProto.STRINGPOOL:
- stringPool = readStringPool(proto);
- statsOut.mStringCache.addAll(stringPool);
+ try {
+ stringPool = readStringPool(proto);
+ statsOut.mStringCache.addAll(stringPool);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read string pool from proto.", e);
+ }
break;
case (int) IntervalStatsProto.PACKAGES:
- loadUsageStats(proto, IntervalStatsProto.PACKAGES, statsOut, stringPool);
+ try {
+ loadUsageStats(proto, IntervalStatsProto.PACKAGES, statsOut, stringPool);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read some usage stats from proto.", e);
+ }
break;
case (int) IntervalStatsProto.CONFIGURATIONS:
- loadConfigStats(proto, IntervalStatsProto.CONFIGURATIONS, statsOut);
+ try {
+ loadConfigStats(proto, IntervalStatsProto.CONFIGURATIONS, statsOut);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read some configuration stats from proto.", e);
+ }
break;
case (int) IntervalStatsProto.EVENT_LOG:
- loadEvent(proto, IntervalStatsProto.EVENT_LOG, statsOut, stringPool);
+ try {
+ loadEvent(proto, IntervalStatsProto.EVENT_LOG, statsOut, stringPool);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read some events from proto.", e);
+ }
break;
case ProtoInputStream.NO_MORE_FIELDS:
if (statsOut.endTime == 0) {
@@ -570,37 +599,58 @@ final class UsageStatsProto {
* @param proto The serializer to which to write the packageStats data.
* @param stats The stats object to write to the XML file.
*/
- public static void write(OutputStream out, IntervalStats stats) throws IOException {
+ public static void write(OutputStream out, IntervalStats stats)
+ throws IOException, IllegalArgumentException {
final ProtoOutputStream proto = new ProtoOutputStream(out);
proto.write(IntervalStatsProto.END_TIME_MS, stats.endTime - stats.beginTime);
proto.write(IntervalStatsProto.MAJOR_VERSION, stats.majorVersion);
proto.write(IntervalStatsProto.MINOR_VERSION, stats.minorVersion);
// String pool should be written before the rest of the usage stats
- writeStringPool(proto, stats);
+ try {
+ writeStringPool(proto, stats);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write string pool to proto.", e);
+ }
- writeCountAndTime(proto, IntervalStatsProto.INTERACTIVE, stats.interactiveTracker.count,
- stats.interactiveTracker.duration);
- writeCountAndTime(proto, IntervalStatsProto.NON_INTERACTIVE,
- stats.nonInteractiveTracker.count, stats.nonInteractiveTracker.duration);
- writeCountAndTime(proto, IntervalStatsProto.KEYGUARD_SHOWN,
- stats.keyguardShownTracker.count, stats.keyguardShownTracker.duration);
- writeCountAndTime(proto, IntervalStatsProto.KEYGUARD_HIDDEN,
- stats.keyguardHiddenTracker.count, stats.keyguardHiddenTracker.duration);
+ try {
+ writeCountAndTime(proto, IntervalStatsProto.INTERACTIVE, stats.interactiveTracker.count,
+ stats.interactiveTracker.duration);
+ writeCountAndTime(proto, IntervalStatsProto.NON_INTERACTIVE,
+ stats.nonInteractiveTracker.count, stats.nonInteractiveTracker.duration);
+ writeCountAndTime(proto, IntervalStatsProto.KEYGUARD_SHOWN,
+ stats.keyguardShownTracker.count, stats.keyguardShownTracker.duration);
+ writeCountAndTime(proto, IntervalStatsProto.KEYGUARD_HIDDEN,
+ stats.keyguardHiddenTracker.count, stats.keyguardHiddenTracker.duration);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write some interval stats trackers to proto.", e);
+ }
final int statsCount = stats.packageStats.size();
for (int i = 0; i < statsCount; i++) {
- writeUsageStats(proto, IntervalStatsProto.PACKAGES, stats,
- stats.packageStats.valueAt(i));
+ try {
+ writeUsageStats(proto, IntervalStatsProto.PACKAGES, stats,
+ stats.packageStats.valueAt(i));
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write some usage stats to proto.", e);
+ }
}
final int configCount = stats.configurations.size();
for (int i = 0; i < configCount; i++) {
boolean active = stats.activeConfiguration.equals(stats.configurations.keyAt(i));
- writeConfigStats(proto, IntervalStatsProto.CONFIGURATIONS, stats,
- stats.configurations.valueAt(i), active);
+ try {
+ writeConfigStats(proto, IntervalStatsProto.CONFIGURATIONS, stats,
+ stats.configurations.valueAt(i), active);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write some configuration stats to proto.", e);
+ }
}
final int eventCount = stats.events.size();
for (int i = 0; i < eventCount; i++) {
- writeEvent(proto, IntervalStatsProto.EVENT_LOG, stats, stats.events.get(i));
+ try {
+ writeEvent(proto, IntervalStatsProto.EVENT_LOG, stats, stats.events.get(i));
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write some events to proto.", e);
+ }
}
proto.flush();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
index badb3eef714e..7d8e430e5416 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
@@ -19,6 +19,7 @@ import android.app.usage.ConfigurationStats;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.content.res.Configuration;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.proto.ProtoInputStream;
@@ -62,9 +63,13 @@ final class UsageStatsProtoV2 {
UsageStatsObfuscatedProto.APP_LAUNCH_COUNT);
break;
case (int) UsageStatsObfuscatedProto.CHOOSER_ACTIONS:
- final long token = proto.start(UsageStatsObfuscatedProto.CHOOSER_ACTIONS);
- loadChooserCounts(proto, stats);
- proto.end(token);
+ try {
+ final long token = proto.start(UsageStatsObfuscatedProto.CHOOSER_ACTIONS);
+ loadChooserCounts(proto, stats);
+ proto.end(token);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read chooser counts for " + stats.mPackageToken);
+ }
break;
case (int) UsageStatsObfuscatedProto.LAST_TIME_SERVICE_USED_MS:
stats.mLastTimeForegroundServiceUsed = beginTime + proto.readLong(
@@ -93,21 +98,26 @@ final class UsageStatsProtoV2 {
}
private static void loadCountAndTime(ProtoInputStream proto, long fieldId,
- IntervalStats.EventTracker tracker) throws IOException {
- final long token = proto.start(fieldId);
- while (true) {
- switch (proto.nextField()) {
- case (int) IntervalStatsObfuscatedProto.CountAndTime.COUNT:
- tracker.count = proto.readInt(IntervalStatsObfuscatedProto.CountAndTime.COUNT);
- break;
- case (int) IntervalStatsObfuscatedProto.CountAndTime.TIME_MS:
- tracker.duration = proto.readLong(
- IntervalStatsObfuscatedProto.CountAndTime.TIME_MS);
- break;
- case ProtoInputStream.NO_MORE_FIELDS:
- proto.end(token);
- return;
+ IntervalStats.EventTracker tracker) {
+ try {
+ final long token = proto.start(fieldId);
+ while (true) {
+ switch (proto.nextField()) {
+ case (int) IntervalStatsObfuscatedProto.CountAndTime.COUNT:
+ tracker.count = proto.readInt(
+ IntervalStatsObfuscatedProto.CountAndTime.COUNT);
+ break;
+ case (int) IntervalStatsObfuscatedProto.CountAndTime.TIME_MS:
+ tracker.duration = proto.readLong(
+ IntervalStatsObfuscatedProto.CountAndTime.TIME_MS);
+ break;
+ case ProtoInputStream.NO_MORE_FIELDS:
+ proto.end(token);
+ return;
+ }
}
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read event tracker " + fieldId, e);
}
}
@@ -278,7 +288,7 @@ final class UsageStatsProtoV2 {
}
private static void writeUsageStats(ProtoOutputStream proto, final long beginTime,
- final UsageStats stats) throws IOException {
+ final UsageStats stats) throws IllegalArgumentException {
// Time attributes stored as an offset of the beginTime.
proto.write(UsageStatsObfuscatedProto.PACKAGE_TOKEN, stats.mPackageToken + 1);
proto.write(UsageStatsObfuscatedProto.LAST_TIME_ACTIVE_MS, stats.mLastTimeUsed - beginTime);
@@ -291,11 +301,15 @@ final class UsageStatsProtoV2 {
stats.mLastTimeVisible - beginTime);
proto.write(UsageStatsObfuscatedProto.TOTAL_TIME_VISIBLE_MS, stats.mTotalTimeVisible);
proto.write(UsageStatsObfuscatedProto.APP_LAUNCH_COUNT, stats.mAppLaunchCount);
- writeChooserCounts(proto, stats);
+ try {
+ writeChooserCounts(proto, stats);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write chooser counts for " + stats.mPackageName, e);
+ }
}
private static void writeCountAndTime(ProtoOutputStream proto, long fieldId, int count,
- long time) throws IOException {
+ long time) throws IllegalArgumentException {
final long token = proto.start(fieldId);
proto.write(IntervalStatsObfuscatedProto.CountAndTime.COUNT, count);
proto.write(IntervalStatsObfuscatedProto.CountAndTime.TIME_MS, time);
@@ -303,7 +317,7 @@ final class UsageStatsProtoV2 {
}
private static void writeChooserCounts(ProtoOutputStream proto, final UsageStats stats)
- throws IOException {
+ throws IllegalArgumentException {
if (stats == null || stats.mChooserCountsObfuscated.size() == 0) {
return;
}
@@ -322,7 +336,7 @@ final class UsageStatsProtoV2 {
}
private static void writeCountsForAction(ProtoOutputStream proto, SparseIntArray counts)
- throws IOException {
+ throws IllegalArgumentException {
final int countsSize = counts.size();
for (int i = 0; i < countsSize; i++) {
final int category = counts.keyAt(i);
@@ -339,7 +353,8 @@ final class UsageStatsProtoV2 {
}
private static void writeConfigStats(ProtoOutputStream proto, final long statsBeginTime,
- final ConfigurationStats configStats, boolean isActive) throws IOException {
+ final ConfigurationStats configStats, boolean isActive)
+ throws IllegalArgumentException {
configStats.mConfiguration.writeToProto(proto,
IntervalStatsObfuscatedProto.Configuration.CONFIG);
proto.write(IntervalStatsObfuscatedProto.Configuration.LAST_TIME_ACTIVE_MS,
@@ -351,7 +366,7 @@ final class UsageStatsProtoV2 {
}
private static void writeEvent(ProtoOutputStream proto, final long statsBeginTime,
- final UsageEvents.Event event) throws IOException {
+ final UsageEvents.Event event) throws IllegalArgumentException {
proto.write(EventObfuscatedProto.PACKAGE_TOKEN, event.mPackageToken + 1);
if (event.mClassToken != PackagesTokenData.UNASSIGNED_TOKEN) {
proto.write(EventObfuscatedProto.CLASS_TOKEN, event.mClassToken + 1);
@@ -429,25 +444,39 @@ final class UsageStatsProtoV2 {
stats.keyguardHiddenTracker);
break;
case (int) IntervalStatsObfuscatedProto.PACKAGES:
- final long packagesToken = proto.start(IntervalStatsObfuscatedProto.PACKAGES);
- UsageStats usageStats = parseUsageStats(proto, stats.beginTime);
- if (usageStats.mPackageToken != PackagesTokenData.UNASSIGNED_TOKEN) {
- stats.packageStatsObfuscated.put(usageStats.mPackageToken, usageStats);
+ try {
+ final long packagesToken = proto.start(
+ IntervalStatsObfuscatedProto.PACKAGES);
+ UsageStats usageStats = parseUsageStats(proto, stats.beginTime);
+ if (usageStats.mPackageToken != PackagesTokenData.UNASSIGNED_TOKEN) {
+ stats.packageStatsObfuscated.put(usageStats.mPackageToken, usageStats);
+ }
+ proto.end(packagesToken);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read some usage stats from proto.", e);
}
- proto.end(packagesToken);
break;
case (int) IntervalStatsObfuscatedProto.CONFIGURATIONS:
- final long configsToken = proto.start(
- IntervalStatsObfuscatedProto.CONFIGURATIONS);
- loadConfigStats(proto, stats);
- proto.end(configsToken);
+ try {
+ final long configsToken = proto.start(
+ IntervalStatsObfuscatedProto.CONFIGURATIONS);
+ loadConfigStats(proto, stats);
+ proto.end(configsToken);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read some configuration stats from proto.", e);
+ }
break;
case (int) IntervalStatsObfuscatedProto.EVENT_LOG:
- final long eventsToken = proto.start(IntervalStatsObfuscatedProto.EVENT_LOG);
- UsageEvents.Event event = parseEvent(proto, stats.beginTime);
- proto.end(eventsToken);
- if (event != null) {
- stats.events.insert(event);
+ try {
+ final long eventsToken = proto.start(
+ IntervalStatsObfuscatedProto.EVENT_LOG);
+ UsageEvents.Event event = parseEvent(proto, stats.beginTime);
+ proto.end(eventsToken);
+ if (event != null) {
+ stats.events.insert(event);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read some events from proto.", e);
}
break;
case ProtoInputStream.NO_MORE_FIELDS:
@@ -466,39 +495,56 @@ final class UsageStatsProtoV2 {
* @param out the output stream to which to write the interval stats data.
* @param stats the interval stats object to write to the proto file.
*/
- public static void write(OutputStream out, IntervalStats stats) throws IOException {
+ public static void write(OutputStream out, IntervalStats stats)
+ throws IOException, IllegalArgumentException {
final ProtoOutputStream proto = new ProtoOutputStream(out);
proto.write(IntervalStatsObfuscatedProto.END_TIME_MS, stats.endTime - stats.beginTime);
proto.write(IntervalStatsObfuscatedProto.MAJOR_VERSION, stats.majorVersion);
proto.write(IntervalStatsObfuscatedProto.MINOR_VERSION, stats.minorVersion);
- writeCountAndTime(proto, IntervalStatsObfuscatedProto.INTERACTIVE,
- stats.interactiveTracker.count, stats.interactiveTracker.duration);
- writeCountAndTime(proto, IntervalStatsObfuscatedProto.NON_INTERACTIVE,
- stats.nonInteractiveTracker.count, stats.nonInteractiveTracker.duration);
- writeCountAndTime(proto, IntervalStatsObfuscatedProto.KEYGUARD_SHOWN,
- stats.keyguardShownTracker.count, stats.keyguardShownTracker.duration);
- writeCountAndTime(proto, IntervalStatsObfuscatedProto.KEYGUARD_HIDDEN,
- stats.keyguardHiddenTracker.count, stats.keyguardHiddenTracker.duration);
+ try {
+ writeCountAndTime(proto, IntervalStatsObfuscatedProto.INTERACTIVE,
+ stats.interactiveTracker.count, stats.interactiveTracker.duration);
+ writeCountAndTime(proto, IntervalStatsObfuscatedProto.NON_INTERACTIVE,
+ stats.nonInteractiveTracker.count, stats.nonInteractiveTracker.duration);
+ writeCountAndTime(proto, IntervalStatsObfuscatedProto.KEYGUARD_SHOWN,
+ stats.keyguardShownTracker.count, stats.keyguardShownTracker.duration);
+ writeCountAndTime(proto, IntervalStatsObfuscatedProto.KEYGUARD_HIDDEN,
+ stats.keyguardHiddenTracker.count, stats.keyguardHiddenTracker.duration);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write some interval stats trackers to proto.", e);
+ }
final int statsCount = stats.packageStatsObfuscated.size();
for (int i = 0; i < statsCount; i++) {
- final long token = proto.start(IntervalStatsObfuscatedProto.PACKAGES);
- writeUsageStats(proto, stats.beginTime, stats.packageStatsObfuscated.valueAt(i));
- proto.end(token);
+ try {
+ final long token = proto.start(IntervalStatsObfuscatedProto.PACKAGES);
+ writeUsageStats(proto, stats.beginTime, stats.packageStatsObfuscated.valueAt(i));
+ proto.end(token);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write some usage stats to proto.", e);
+ }
}
final int configCount = stats.configurations.size();
for (int i = 0; i < configCount; i++) {
boolean active = stats.activeConfiguration.equals(stats.configurations.keyAt(i));
- final long token = proto.start(IntervalStatsObfuscatedProto.CONFIGURATIONS);
- writeConfigStats(proto, stats.beginTime, stats.configurations.valueAt(i), active);
- proto.end(token);
+ try {
+ final long token = proto.start(IntervalStatsObfuscatedProto.CONFIGURATIONS);
+ writeConfigStats(proto, stats.beginTime, stats.configurations.valueAt(i), active);
+ proto.end(token);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write some configuration stats to proto.", e);
+ }
}
final int eventCount = stats.events.size();
for (int i = 0; i < eventCount; i++) {
- final long token = proto.start(IntervalStatsObfuscatedProto.EVENT_LOG);
- writeEvent(proto, stats.beginTime, stats.events.get(i));
- proto.end(token);
+ try {
+ final long token = proto.start(IntervalStatsObfuscatedProto.EVENT_LOG);
+ writeEvent(proto, stats.beginTime, stats.events.get(i));
+ proto.end(token);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write some events to proto.", e);
+ }
}
proto.flush();
@@ -559,7 +605,7 @@ final class UsageStatsProtoV2 {
* @param packagesTokenData the packages data object holding the data to write.
*/
static void writeObfuscatedData(OutputStream out, PackagesTokenData packagesTokenData)
- throws IOException {
+ throws IOException, IllegalArgumentException {
final ProtoOutputStream proto = new ProtoOutputStream(out);
proto.write(ObfuscatedPackagesProto.COUNTER, packagesTokenData.counter);
@@ -660,11 +706,15 @@ final class UsageStatsProtoV2 {
while (true) {
switch (proto.nextField()) {
case (int) IntervalStatsObfuscatedProto.PENDING_EVENTS:
- final long token = proto.start(IntervalStatsObfuscatedProto.PENDING_EVENTS);
- UsageEvents.Event event = parsePendingEvent(proto);
- proto.end(token);
- if (event != null) {
- events.add(event);
+ try {
+ final long token = proto.start(IntervalStatsObfuscatedProto.PENDING_EVENTS);
+ UsageEvents.Event event = parsePendingEvent(proto);
+ proto.end(token);
+ if (event != null) {
+ events.add(event);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to parse some pending events from proto.", e);
}
break;
case ProtoInputStream.NO_MORE_FIELDS:
@@ -673,6 +723,47 @@ final class UsageStatsProtoV2 {
}
}
+ private static void writePendingEvent(ProtoOutputStream proto, UsageEvents.Event event)
+ throws IllegalArgumentException {
+ proto.write(PendingEventProto.PACKAGE_NAME, event.mPackage);
+ if (event.mClass != null) {
+ proto.write(PendingEventProto.CLASS_NAME, event.mClass);
+ }
+ proto.write(PendingEventProto.TIME_MS, event.mTimeStamp);
+ proto.write(PendingEventProto.FLAGS, event.mFlags);
+ proto.write(PendingEventProto.TYPE, event.mEventType);
+ proto.write(PendingEventProto.INSTANCE_ID, event.mInstanceId);
+ if (event.mTaskRootPackage != null) {
+ proto.write(PendingEventProto.TASK_ROOT_PACKAGE, event.mTaskRootPackage);
+ }
+ if (event.mTaskRootClass != null) {
+ proto.write(PendingEventProto.TASK_ROOT_CLASS, event.mTaskRootClass);
+ }
+ switch (event.mEventType) {
+ case UsageEvents.Event.CONFIGURATION_CHANGE:
+ if (event.mConfiguration != null) {
+ event.mConfiguration.writeToProto(proto, PendingEventProto.CONFIG);
+ }
+ break;
+ case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
+ if (event.mBucketAndReason != 0) {
+ proto.write(PendingEventProto.STANDBY_BUCKET, event.mBucketAndReason);
+ }
+ break;
+ case UsageEvents.Event.SHORTCUT_INVOCATION:
+ if (event.mShortcutId != null) {
+ proto.write(PendingEventProto.SHORTCUT_ID, event.mShortcutId);
+ }
+ break;
+ case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+ if (event.mNotificationChannelId != null) {
+ proto.write(PendingEventProto.NOTIFICATION_CHANNEL_ID,
+ event.mNotificationChannelId);
+ }
+ break;
+ }
+ }
+
/**
* Writes the pending events to a ProtoBuf file.
*
@@ -680,50 +771,17 @@ final class UsageStatsProtoV2 {
* @param events the list of pending events.
*/
static void writePendingEvents(OutputStream out, LinkedList<UsageEvents.Event> events)
- throws IOException {
+ throws IOException, IllegalArgumentException {
final ProtoOutputStream proto = new ProtoOutputStream(out);
final int eventCount = events.size();
for (int i = 0; i < eventCount; i++) {
- final long token = proto.start(IntervalStatsObfuscatedProto.PENDING_EVENTS);
- final UsageEvents.Event event = events.get(i);
- proto.write(PendingEventProto.PACKAGE_NAME, event.mPackage);
- if (event.mClass != null) {
- proto.write(PendingEventProto.CLASS_NAME, event.mClass);
- }
- proto.write(PendingEventProto.TIME_MS, event.mTimeStamp);
- proto.write(PendingEventProto.FLAGS, event.mFlags);
- proto.write(PendingEventProto.TYPE, event.mEventType);
- proto.write(PendingEventProto.INSTANCE_ID, event.mInstanceId);
- if (event.mTaskRootPackage != null) {
- proto.write(PendingEventProto.TASK_ROOT_PACKAGE, event.mTaskRootPackage);
- }
- if (event.mTaskRootClass != null) {
- proto.write(PendingEventProto.TASK_ROOT_CLASS, event.mTaskRootClass);
- }
- switch (event.mEventType) {
- case UsageEvents.Event.CONFIGURATION_CHANGE:
- if (event.mConfiguration != null) {
- event.mConfiguration.writeToProto(proto, PendingEventProto.CONFIG);
- }
- break;
- case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
- if (event.mBucketAndReason != 0) {
- proto.write(PendingEventProto.STANDBY_BUCKET, event.mBucketAndReason);
- }
- break;
- case UsageEvents.Event.SHORTCUT_INVOCATION:
- if (event.mShortcutId != null) {
- proto.write(PendingEventProto.SHORTCUT_ID, event.mShortcutId);
- }
- break;
- case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
- if (event.mNotificationChannelId != null) {
- proto.write(PendingEventProto.NOTIFICATION_CHANNEL_ID,
- event.mNotificationChannelId);
- }
- break;
+ try {
+ final long token = proto.start(IntervalStatsObfuscatedProto.PENDING_EVENTS);
+ writePendingEvent(proto, events.get(i));
+ proto.end(token);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write some pending events to proto.", e);
}
- proto.end(token);
}
proto.flush();
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 8e392a7a8456..b12d9008689a 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -654,7 +654,7 @@ public class UsageStatsService extends SystemService implements
af.finishWrite(fos);
fos = null;
pendingEvents.clear();
- } catch (IOException e) {
+ } catch (IOException | IllegalArgumentException e) {
Slog.e(TAG, "Failed to write " + pendingEventsFile.getAbsolutePath()
+ " for user " + userId);
} finally {