Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5da677f5 authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

Merge "Merge "Metrics for content capture." into qt-dev am: 815979d5 am:...

Merge "Merge "Metrics for content capture." into qt-dev am: 815979d5 am: e5e27dc6" into qt-r1-dev-plus-aosp
parents 21c90154 bdc08093
Loading
Loading
Loading
Loading
+93 −0
Original line number Diff line number Diff line
@@ -299,6 +299,10 @@ message Atom {
        CarPowerStateChanged car_power_state_changed = 203;
        GarageModeInfo garage_mode_info = 204;
        TestAtomReported test_atom_reported = 205 [(log_from_module) = "cts"];
        ContentCaptureCallerMismatchReported content_capture_caller_mismatch_reported = 206;
        ContentCaptureServiceEvents content_capture_service_events = 207;
        ContentCaptureSessionEvents content_capture_session_events = 208;
        ContentCaptureFlushed content_capture_flushed = 209;
    }

    // Pulled events will start at field 10000.
@@ -4830,6 +4834,95 @@ message BuildInformation {
    optional string tags = 9;
}

/**
 * Logs information about mismatched caller for content capture.
 *
 * Logged from:
 *   frameworks/base/core/java/android/service/contentcapture/ContentCaptureService.java
 */
message ContentCaptureCallerMismatchReported {
    optional string intended_package = 1;
    optional string calling_package = 2;
}

/**
 * Logs information about content capture service events.
 *
 * Logged from:
 *   frameworks/base/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
 */
message ContentCaptureServiceEvents {
    // The type of event.
    enum Event {
        UNKNOWN = 0;
        ON_CONNECTED = 1;
        ON_DISCONNECTED = 2;
        SET_WHITELIST = 3;
        SET_DISABLED = 4;
        ON_USER_DATA_REMOVED = 5;
    }
    optional Event event = 1;
    // component/package of content capture service.
    optional string service_info = 2;
    // component/package of target.
    // it's a concatenated list of component/package for SET_WHITELIST event
    // separated by " ".
    optional string target_info = 3;
}

/**
 * Logs information about content capture session events.
 *
 * Logged from:
 *   frameworks/base/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
 */
message ContentCaptureSessionEvents {
    // The type of event.
    enum Event {
        UNKNOWN = 0;
        ON_SESSION_STARTED = 1;
        ON_SESSION_FINISHED = 2;
        SESSION_NOT_CREATED = 3;
    }
    optional int32 session_id = 1;
    optional Event event = 2;
    // (n/a on session finished)
    optional int32 state_flags = 3;
    // component/package of content capture service.
    optional string service_info = 4;
    // component/package of app.
    // (n/a on session finished)
    optional string app_info = 5;
    optional bool is_child_session = 6;
}

/**
 * Logs information about session being flushed.
 *
 * Logged from:
 *   frameworks/base/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
 */
message ContentCaptureFlushed {
    optional int32 session_id = 1;
    // component/package of content capture service.
    optional string service_info = 2;
    // component/package of app.
    optional string app_info = 3;
    // session start/finish events
    optional int32 child_session_started = 4;
    optional int32 child_session_finished = 5;
    // count of view events.
    optional int32 view_appeared_count = 6;
    optional int32 view_disappeared_count = 7;
    optional int32 view_text_changed_count = 8;

    // Flush stats.
    optional int32 max_events = 9;
    optional int32 idle_flush_freq = 10;
    optional int32 text_flush_freq = 11;
    optional int32 flush_reason = 12;
}

/**
 * Pulls on-device BatteryStats power use calculations for the overall device.
 */
+67 −6
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.Service;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
@@ -40,6 +41,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.StatsLog;
import android.view.contentcapture.ContentCaptureCondition;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureEvent;
@@ -114,6 +116,9 @@ public abstract class ContentCaptureService extends Service {
    private Handler mHandler;
    private IContentCaptureServiceCallback mCallback;

    private long mCallerMismatchTimeout = 1000;
    private long mLastCallerMismatchLog;

    /**
     * Binder that receives calls from the system server.
     */
@@ -176,9 +181,10 @@ public abstract class ContentCaptureService extends Service {
            new IContentCaptureDirectManager.Stub() {

        @Override
        public void sendEvents(@SuppressWarnings("rawtypes") ParceledListSlice events) {
        public void sendEvents(@SuppressWarnings("rawtypes") ParceledListSlice events, int reason,
                ContentCaptureOptions options) {
            mHandler.sendMessage(obtainMessage(ContentCaptureService::handleSendEvents,
                            ContentCaptureService.this, Binder.getCallingUid(), events));
                    ContentCaptureService.this, Binder.getCallingUid(), events, reason, options));
        }
    };

@@ -424,14 +430,23 @@ public abstract class ContentCaptureService extends Service {
    }

    private void handleSendEvents(int uid,
            @NonNull ParceledListSlice<ContentCaptureEvent> parceledEvents) {
            @NonNull ParceledListSlice<ContentCaptureEvent> parceledEvents, int reason,
            @Nullable ContentCaptureOptions options) {
        final List<ContentCaptureEvent> events = parceledEvents.getList();
        if (events.isEmpty()) {
            Log.w(TAG, "handleSendEvents() received empty list of events");
            return;
        }

        // Metrics.
        final FlushMetrics metrics = new FlushMetrics();
        ComponentName activityComponent = null;

        // Most events belong to the same session, so we can keep a reference to the last one
        // to avoid creating too many ContentCaptureSessionId objects
        int lastSessionId = NO_SESSION_ID;
        ContentCaptureSessionId sessionId = null;

        final List<ContentCaptureEvent> events = parceledEvents.getList();
        for (int i = 0; i < events.size(); i++) {
            final ContentCaptureEvent event = events.get(i);
            if (!handleIsRightCallerFor(event, uid)) continue;
@@ -439,22 +454,44 @@ public abstract class ContentCaptureService extends Service {
            if (sessionIdInt != lastSessionId) {
                sessionId = new ContentCaptureSessionId(sessionIdInt);
                lastSessionId = sessionIdInt;
                if (i != 0) {
                    writeFlushMetrics(lastSessionId, activityComponent, metrics, options, reason);
                    metrics.reset();
                }
            }
            final ContentCaptureContext clientContext = event.getContentCaptureContext();
            if (activityComponent == null && clientContext != null) {
                activityComponent = clientContext.getActivityComponent();
            }
            switch (event.getType()) {
                case ContentCaptureEvent.TYPE_SESSION_STARTED:
                    final ContentCaptureContext clientContext = event.getContentCaptureContext();
                    clientContext.setParentSessionId(event.getParentSessionId());
                    mSessionUids.put(sessionIdInt, uid);
                    onCreateContentCaptureSession(clientContext, sessionId);
                    metrics.sessionStarted++;
                    break;
                case ContentCaptureEvent.TYPE_SESSION_FINISHED:
                    mSessionUids.delete(sessionIdInt);
                    onDestroyContentCaptureSession(sessionId);
                    metrics.sessionFinished++;
                    break;
                case ContentCaptureEvent.TYPE_VIEW_APPEARED:
                    onContentCaptureEvent(sessionId, event);
                    metrics.viewAppearedCount++;
                    break;
                case ContentCaptureEvent.TYPE_VIEW_DISAPPEARED:
                    onContentCaptureEvent(sessionId, event);
                    metrics.viewDisappearedCount++;
                    break;
                case ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED:
                    onContentCaptureEvent(sessionId, event);
                    metrics.viewTextChangedCount++;
                    break;
                default:
                    onContentCaptureEvent(sessionId, event);
            }
        }
        writeFlushMetrics(lastSessionId, activityComponent, metrics, options, reason);
    }

    private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) {
@@ -499,7 +536,13 @@ public abstract class ContentCaptureService extends Service {
        if (rightUid != uid) {
            Log.e(TAG, "invalid call from UID " + uid + ": session " + sessionId + " belongs to "
                    + rightUid);
            //TODO(b/111276913): log metrics as this could be a malicious app forging a sessionId
            long now = System.currentTimeMillis();
            if (now - mLastCallerMismatchLog > mCallerMismatchTimeout) {
                StatsLog.write(StatsLog.CONTENT_CAPTURE_CALLER_MISMATCH_REPORTED,
                        getPackageManager().getNameForUid(rightUid),
                        getPackageManager().getNameForUid(uid));
                mLastCallerMismatchLog = now;
            }
            return false;
        }
        return true;
@@ -530,4 +573,22 @@ public abstract class ContentCaptureService extends Service {
            Slog.w(TAG, "Error async reporting result to client: " + e);
        }
    }

    /**
     * Logs the metrics for content capture events flushing.
     */
    private void writeFlushMetrics(int sessionId, @Nullable ComponentName app,
            @NonNull FlushMetrics flushMetrics, @Nullable ContentCaptureOptions options,
            int flushReason) {
        if (mCallback == null) {
            Log.w(TAG, "writeSessionFlush(): no server callback");
            return;
        }

        try {
            mCallback.writeSessionFlush(sessionId, app, flushMetrics, options, flushReason);
        } catch (RemoteException e) {
            Log.e(TAG, "failed to write flush metrics: " + e);
        }
    }
}
+20 −0
Original line number Diff line number Diff line
/**
 * 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 android.service.contentcapture;

/* @hide */
parcelable FlushMetrics;
+79 −0
Original line number Diff line number Diff line
/*
 * 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 android.service.contentcapture;

import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;

/**
 * Holds metrics for content capture events flushing.
 *
 * @hide
 */
public final class FlushMetrics implements Parcelable {
    public int viewAppearedCount;
    public int viewDisappearedCount;
    public int viewTextChangedCount;
    public int sessionStarted;
    public int sessionFinished;

    /**
     * Resets all flush metrics.
     */
    public void reset() {
        viewAppearedCount = 0;
        viewDisappearedCount = 0;
        viewTextChangedCount = 0;
        sessionStarted = 0;
        sessionFinished = 0;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(sessionStarted);
        out.writeInt(sessionFinished);
        out.writeInt(viewAppearedCount);
        out.writeInt(viewDisappearedCount);
        out.writeInt(viewTextChangedCount);
    }

    @NonNull
    public static final Creator<FlushMetrics> CREATOR = new Creator<FlushMetrics>() {
        @NonNull
        @Override
        public FlushMetrics createFromParcel(Parcel in) {
            final FlushMetrics flushMetrics = new FlushMetrics();
            flushMetrics.sessionStarted = in.readInt();
            flushMetrics.sessionFinished = in.readInt();
            flushMetrics.viewAppearedCount = in.readInt();
            flushMetrics.viewDisappearedCount = in.readInt();
            flushMetrics.viewTextChangedCount = in.readInt();
            return flushMetrics;
        }

        @Override
        public FlushMetrics[] newArray(int size) {
            return new FlushMetrics[size];
        }
    };
}
+7 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package android.service.contentcapture;

import android.content.ComponentName;
import android.view.contentcapture.ContentCaptureCondition;
import android.service.contentcapture.FlushMetrics;
import android.content.ContentCaptureOptions;

import java.util.List;

@@ -30,4 +32,8 @@ oneway interface IContentCaptureServiceCallback {
    void setContentCaptureWhitelist(in List<String> packages, in List<ComponentName> activities);
    void setContentCaptureConditions(String packageName, in List<ContentCaptureCondition> conditions);
    void disableSelf();

    // Logs aggregated content capture flush metrics to Statsd
    void writeSessionFlush(int sessionId, in ComponentName app, in FlushMetrics flushMetrics,
            in ContentCaptureOptions options, int flushReason);
}
Loading