diff options
author | Adam He <adamhe@google.com> | 2019-01-23 15:59:09 -0800 |
---|---|---|
committer | Adam He <adamhe@google.com> | 2019-05-14 11:33:33 -0700 |
commit | 420947c4cc237ec3bf286d10cbd74d4971e8d82e (patch) | |
tree | 15c16bcaee2fc891c51ea0a33254d04973361ef8 /services/contentcapture | |
parent | bf66ce55f0b791a58148cdd3ca809a1ad9a8858a (diff) |
Metrics for content capture.
Bug: 119613670
Test: statsd_testdrive & manual test
Change-Id: If43465ccee7454a7ebf9e15caa23fce7bae33cfe
Diffstat (limited to 'services/contentcapture')
3 files changed, 162 insertions, 5 deletions
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java new file mode 100644 index 000000000000..dd1b84b16f68 --- /dev/null +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java @@ -0,0 +1,106 @@ +/* + * 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.contentcapture; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.ContentCaptureOptions; +import android.service.contentcapture.FlushMetrics; +import android.util.StatsLog; + +import java.util.List; + +/** @hide */ +public final class ContentCaptureMetricsLogger { + /** + * Class only contains static utility functions, and should not be instantiated + */ + private ContentCaptureMetricsLogger() { + } + + /** @hide */ + public static void writeServiceEvent(int eventType, @NonNull String serviceName, + @Nullable String targetPackage) { + StatsLog.write(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS, eventType, serviceName, + targetPackage); + } + + /** @hide */ + public static void writeServiceEvent(int eventType, @NonNull ComponentName service, + @Nullable ComponentName target) { + writeServiceEvent(eventType, ComponentName.flattenToShortString(service), + ComponentName.flattenToShortString(target)); + } + + /** @hide */ + public static void writeServiceEvent(int eventType, @NonNull ComponentName service, + @Nullable String targetPackage) { + writeServiceEvent(eventType, ComponentName.flattenToShortString(service), targetPackage); + } + + /** @hide */ + public static void writeServiceEvent(int eventType, @NonNull ComponentName service) { + writeServiceEvent(eventType, ComponentName.flattenToShortString(service), null); + } + + /** @hide */ + public static void writeSetWhitelistEvent(@Nullable ComponentName service, + @Nullable List<String> packages, @Nullable List<ComponentName> activities) { + final String serviceName = ComponentName.flattenToShortString(service); + StringBuilder stringBuilder = new StringBuilder(); + if (packages != null && packages.size() > 0) { + final int size = packages.size(); + stringBuilder.append(packages.get(0)); + for (int i = 1; i < size; i++) { + stringBuilder.append(" "); + stringBuilder.append(packages.get(i)); + } + } + if (activities != null && activities.size() > 0) { + stringBuilder.append(" "); + stringBuilder.append(activities.get(0).flattenToShortString()); + final int size = activities.size(); + for (int i = 1; i < size; i++) { + stringBuilder.append(" "); + stringBuilder.append(activities.get(i).flattenToShortString()); + } + } + StatsLog.write(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS, + StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__SET_WHITELIST, + serviceName, stringBuilder.toString()); + } + + /** @hide */ + public static void writeSessionEvent(int sessionId, int event, int flags, + @NonNull ComponentName service, @Nullable ComponentName app, boolean isChildSession) { + StatsLog.write(StatsLog.CONTENT_CAPTURE_SESSION_EVENTS, sessionId, event, flags, + ComponentName.flattenToShortString(service), + ComponentName.flattenToShortString(app), isChildSession); + } + + /** @hide */ + public static void writeSessionFlush(int sessionId, @NonNull ComponentName service, + @Nullable ComponentName app, @NonNull FlushMetrics fm, + @NonNull ContentCaptureOptions options, int flushReason) { + StatsLog.write(StatsLog.CONTENT_CAPTURE_FLUSHED, sessionId, + ComponentName.flattenToShortString(service), + ComponentName.flattenToShortString(app), fm.sessionStarted, fm.sessionFinished, + fm.viewAppearedCount, fm.viewDisappearedCount, fm.viewTextChangedCount, + options.maxBufferSize, options.idleFlushingFrequencyMs, + options.textChangeFlushingFrequencyMs, flushReason); + } +} diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index 67c3d01cb86b..a186d4e7f467 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -24,6 +24,9 @@ import static android.view.contentcapture.ContentCaptureSession.STATE_INTERNAL_E import static android.view.contentcapture.ContentCaptureSession.STATE_NOT_WHITELISTED; import static android.view.contentcapture.ContentCaptureSession.STATE_NO_SERVICE; +import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeServiceEvent; +import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeSessionEvent; +import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeSetWhitelistEvent; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE; @@ -35,6 +38,7 @@ import android.app.ActivityManagerInternal; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.content.ComponentName; +import android.content.ContentCaptureOptions; import android.content.pm.ActivityPresentationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -48,6 +52,7 @@ import android.service.contentcapture.ActivityEvent; import android.service.contentcapture.ActivityEvent.ActivityEventType; import android.service.contentcapture.ContentCaptureService; import android.service.contentcapture.ContentCaptureServiceInfo; +import android.service.contentcapture.FlushMetrics; import android.service.contentcapture.IContentCaptureServiceCallback; import android.service.contentcapture.SnapshotData; import android.util.ArrayMap; @@ -55,6 +60,7 @@ import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.StatsLog; import android.view.contentcapture.ContentCaptureCondition; import android.view.contentcapture.DataRemovalRequest; @@ -231,7 +237,6 @@ final class ContentCapturePerUserService resurrectSessionsLocked(); } - // TODO(b/119613670): log metrics @GuardedBy("mLock") public void startSessionLocked(@NonNull IBinder activityToken, @NonNull ActivityPresentationInfo activityPresentationInfo, int sessionId, int uid, @@ -263,9 +268,14 @@ final class ContentCapturePerUserService if (!enabled) { // TODO: it would be better to split in differet reasons, like - // STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY + // STATE_DISABLED_NO and STATE_DISABLED_BY_DEVICE_POLICY setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE, /* binder= */ null); + // Log metrics. + writeSessionEvent(sessionId, + StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, + STATE_DISABLED | STATE_NO_SERVICE, serviceComponentName, + componentName, /* isChildSession= */ false); return; } if (serviceComponentName == null) { @@ -285,6 +295,11 @@ final class ContentCapturePerUserService } setClientState(clientReceiver, STATE_DISABLED | STATE_NOT_WHITELISTED, /* binder= */ null); + // Log metrics. + writeSessionEvent(sessionId, + StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, + STATE_DISABLED | STATE_NOT_WHITELISTED, serviceComponentName, + componentName, /* isChildSession= */ false); return; } @@ -294,6 +309,11 @@ final class ContentCapturePerUserService + ": ignoring because it already exists for " + existingSession.mActivityToken); setClientState(clientReceiver, STATE_DISABLED | STATE_DUPLICATED_ID, /* binder=*/ null); + // Log metrics. + writeSessionEvent(sessionId, + StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, + STATE_DISABLED | STATE_DUPLICATED_ID, + serviceComponentName, componentName, /* isChildSession= */ false); return; } @@ -302,11 +322,15 @@ final class ContentCapturePerUserService } if (mRemoteService == null) { - // TODO(b/119613670): log metrics Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken + ": ignoring because service is not set"); setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE, /* binder= */ null); + // Log metrics. + writeSessionEvent(sessionId, + StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, + STATE_DISABLED | STATE_NO_SERVICE, serviceComponentName, + componentName, /* isChildSession= */ false); return; } @@ -324,7 +348,6 @@ final class ContentCapturePerUserService newSession.notifySessionStartedLocked(clientReceiver); } - // TODO(b/119613670): log metrics @GuardedBy("mLock") public void finishSessionLocked(int sessionId) { if (!isEnabledLocked()) { @@ -553,6 +576,7 @@ final class ContentCapturePerUserService + " for user " + mUserId); } mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities); + writeSetWhitelistEvent(getServiceComponentName(), packages, activities); // Must disable session that are not the whitelist anymore... final int numSessions = mSessions.size(); @@ -602,7 +626,6 @@ final class ContentCapturePerUserService mConditionsByPkg.put(packageName, new ArraySet<>(conditions)); } } - // TODO(b/119613670): log metrics } @Override @@ -616,6 +639,15 @@ final class ContentCapturePerUserService } finally { Binder.restoreCallingIdentity(token); } + writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__SET_DISABLED, + getServiceComponentName()); + } + + @Override + public void writeSessionFlush(int sessionId, ComponentName app, FlushMetrics flushMetrics, + ContentCaptureOptions options, int flushReason) { + ContentCaptureMetricsLogger.writeSessionFlush(sessionId, getServiceComponentName(), app, + flushMetrics, options, flushReason); } } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java index 00bfb88c29fe..01d33b0e5445 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java @@ -18,6 +18,9 @@ package com.android.server.contentcapture; import static android.view.contentcapture.ContentCaptureHelper.sDebug; import static android.view.contentcapture.ContentCaptureHelper.sVerbose; +import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeServiceEvent; +import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeSessionEvent; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; @@ -28,6 +31,7 @@ import android.service.contentcapture.IContentCaptureService; import android.service.contentcapture.IContentCaptureServiceCallback; import android.service.contentcapture.SnapshotData; import android.util.Slog; +import android.util.StatsLog; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.DataRemovalRequest; @@ -77,6 +81,8 @@ final class RemoteContentCaptureService if (connected) { try { mService.onConnected(mServerCallback, sVerbose, sDebug); + writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_CONNECTED, + mComponentName); } finally { // Update the system-service state, in case the service reconnected after // dying @@ -84,6 +90,8 @@ final class RemoteContentCaptureService } } else { mService.onDisconnected(); + writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_DISCONNECTED, + mComponentName); } } catch (Exception e) { Slog.w(mTag, "Exception calling onConnectedStateChanged(" + connected + "): " + e); @@ -102,6 +110,10 @@ final class RemoteContentCaptureService @NonNull IResultReceiver clientReceiver, int initialState) { scheduleAsyncRequest( (s) -> s.onSessionStarted(context, sessionId, uid, clientReceiver, initialState)); + // Metrics logging. + writeSessionEvent(sessionId, + StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_STARTED, initialState, + getComponentName(), context.getActivityComponent(), /* is_child_session= */ false); } /** @@ -110,6 +122,11 @@ final class RemoteContentCaptureService */ public void onSessionFinished(int sessionId) { scheduleAsyncRequest((s) -> s.onSessionFinished(sessionId)); + // Metrics logging. + writeSessionEvent(sessionId, + StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_FINISHED, + /* flags= */ 0, getComponentName(), /* app= */ null, + /* is_child_session= */ false); } /** @@ -124,6 +141,8 @@ final class RemoteContentCaptureService */ public void onDataRemovalRequest(@NonNull DataRemovalRequest request) { scheduleAsyncRequest((s) -> s.onDataRemovalRequest(request)); + writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_USER_DATA_REMOVED, + mComponentName); } /** |