blob: 994802d928f10aa344fdb019cb5a3a6baf7d332c [file] [log] [blame]
/*
* Copyright (C) 2022 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.autofill;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_REQUEST_REPORTED;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_EXPLICITLY_REQUESTED;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_NORMAL_TRIGGER;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_PRE_TRIGGER;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_RETRIGGER;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_UNKNOWN;
import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.IntDef;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Optional;
/**
* Helper class to log Autofill FillRequest filing stats.
*/
public final class FillRequestEventLogger {
private static final String TAG = "FillRequestEventLogger";
/**
* Reasons why presentation was not shown. These are wrappers around
* {@link com.android.os.AtomsProto.AutofillFillRequestReported.RequestTriggerReason}.
*/
@IntDef(prefix = {"TRIGGER_REASON"}, value = {
TRIGGER_REASON_UNKNOWN,
TRIGGER_REASON_EXPLICITLY_REQUESTED,
TRIGGER_REASON_RETRIGGER,
TRIGGER_REASON_PRE_TRIGGER,
TRIGGER_REASON_NORMAL_TRIGGER,
TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE
})
@Retention(RetentionPolicy.SOURCE)
public @interface TriggerReason {
}
public static final int TRIGGER_REASON_UNKNOWN =
AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_UNKNOWN;
public static final int TRIGGER_REASON_EXPLICITLY_REQUESTED =
AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_EXPLICITLY_REQUESTED;
public static final int TRIGGER_REASON_RETRIGGER =
AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_RETRIGGER;
public static final int TRIGGER_REASON_PRE_TRIGGER =
AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_PRE_TRIGGER;
public static final int TRIGGER_REASON_NORMAL_TRIGGER =
AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_NORMAL_TRIGGER;
public static final int TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE =
AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE;
private final int mSessionId;
private Optional<FillRequestEventInternal> mEventInternal;
private FillRequestEventLogger(int sessionId) {
mSessionId = sessionId;
mEventInternal = Optional.empty();
}
/**
* A factory constructor to create FillRequestEventLogger.
*/
public static FillRequestEventLogger forSessionId(int sessionId) {
return new FillRequestEventLogger(sessionId);
}
/**
* Reset mEventInternal before logging for a new request. It shall be called for each
* FillRequest.
*/
public void startLogForNewRequest() {
if (!mEventInternal.isEmpty()) {
Slog.w(TAG, "FillRequestEventLogger is not empty before starting for a new " +
"request");
}
mEventInternal = Optional.of(new FillRequestEventInternal());
}
/**
* Set request_id as long as mEventInternal presents.
* For the case of Augmented Autofill, set to -2.
*/
public void maybeSetRequestId(int requestId) {
mEventInternal.ifPresent(event -> event.mRequestId = requestId);
}
/**
* Set service_uid as long as mEventInternal presents.
*/
public void maybeSetAutofillServiceUid(int uid) {
mEventInternal.ifPresent(event -> {
event.mAutofillServiceUid = uid;
});
}
/**
* Set inline_suggestion_host_uid as long as mEventInternal presents.
*/
public void maybeSetInlineSuggestionHostUid(Context context, int userId) {
mEventInternal.ifPresent(event -> {
String imeString = Settings.Secure.getStringForUser(context.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, userId);
if (TextUtils.isEmpty(imeString)) {
Slog.w(TAG, "No default IME found");
return;
}
ComponentName imeComponent = ComponentName.unflattenFromString(imeString);
if (imeComponent == null) {
Slog.w(TAG, "No default IME found");
return;
}
int imeUid;
String packageName = imeComponent.getPackageName();
try {
imeUid = context.getPackageManager().getApplicationInfoAsUser(packageName,
PackageManager.ApplicationInfoFlags.of(0), userId).uid;
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Couldn't find packageName: " + packageName);
return;
}
event.mInlineSuggestionHostUid = imeUid;
});
}
/**
* Set flags as long as mEventInternal presents.
*/
public void maybeSetFlags(int flags) {
mEventInternal.ifPresent(event -> {
event.mFlags = flags;
});
}
/**
* Set request_trigger_reason as long as mEventInternal presents.
*/
public void maybeSetRequestTriggerReason(@TriggerReason int reason) {
mEventInternal.ifPresent(event -> {
event.mRequestTriggerReason = reason;
});
}
/**
* Set is_augmented as long as mEventInternal presents.
*/
public void maybeSetIsAugmented(boolean val) {
mEventInternal.ifPresent(event -> {
event.mIsAugmented = val;
});
}
/**
* Set is_client_suggestion as long as mEventInternal presents.
*/
public void maybeSetIsClientSuggestionFallback(boolean val) {
mEventInternal.ifPresent(event -> {
event.mIsClientSuggestionFallback = val;
});
}
/**
* Set is_fill_dialog_eligible as long as mEventInternal presents.
*/
public void maybeSetIsFillDialogEligible(boolean val) {
mEventInternal.ifPresent(event -> {
event.mIsFillDialogEligible = val;
});
}
/**
* Set latency_fill_request_sent_millis as long as mEventInternal presents.
*/
public void maybeSetLatencyFillRequestSentMillis(int timestamp) {
mEventInternal.ifPresent(event -> {
event.mLatencyFillRequestSentMillis = timestamp;
});
}
/**
* Set app_package_uid as long as mEventInternal presents.
*/
public void maybeSetAppPackageUid(int uid) {
mEventInternal.ifPresent(event -> {
event.mAppPackageUid = uid;
});
}
/**
* Log an AUTOFILL_FILL_REQUEST_REPORTED event.
*/
public void logAndEndEvent() {
if (!mEventInternal.isPresent()) {
Slog.w(TAG, "Shouldn't be logging AutofillFillRequestReported again for same "
+ "event");
return;
}
FillRequestEventInternal event = mEventInternal.get();
if (sVerbose) {
Slog.v(TAG, "Log AutofillFillRequestReported:"
+ " requestId=" + event.mRequestId
+ " sessionId=" + mSessionId
+ " mAutofillServiceUid=" + event.mAutofillServiceUid
+ " mInlineSuggestionHostUid=" + event.mInlineSuggestionHostUid
+ " mIsAugmented=" + event.mIsAugmented
+ " mIsClientSuggestionFallback=" + event.mIsClientSuggestionFallback
+ " mIsFillDialogEligible=" + event.mIsFillDialogEligible
+ " mRequestTriggerReason=" + event.mRequestTriggerReason
+ " mFlags=" + event.mFlags
+ " mLatencyFillRequestSentMillis=" + event.mLatencyFillRequestSentMillis
+ " mAppPackageUid=" + event.mAppPackageUid);
}
FrameworkStatsLog.write(
AUTOFILL_FILL_REQUEST_REPORTED,
event.mRequestId,
mSessionId,
event.mAutofillServiceUid,
event.mInlineSuggestionHostUid,
event.mIsAugmented,
event.mIsClientSuggestionFallback,
event.mIsFillDialogEligible,
event.mRequestTriggerReason,
event.mFlags,
event.mLatencyFillRequestSentMillis,
event.mAppPackageUid);
mEventInternal = Optional.empty();
}
private static final class FillRequestEventInternal {
int mRequestId;
int mAppPackageUid = -1;
int mAutofillServiceUid = -1;
int mInlineSuggestionHostUid = -1;
boolean mIsAugmented = false;
boolean mIsClientSuggestionFallback = false;
boolean mIsFillDialogEligible = false;
int mRequestTriggerReason =
AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_UNKNOWN;
int mFlags = -1;
int mLatencyFillRequestSentMillis = -1;
FillRequestEventInternal() {
}
}
}