Merge "Add skeleton implementation for Attention API"
This commit is contained in:
@@ -358,6 +358,8 @@ java_defaults {
|
||||
"core/java/android/service/textclassifier/ITextLanguageCallback.aidl",
|
||||
"core/java/android/service/textclassifier/ITextLinksCallback.aidl",
|
||||
"core/java/android/service/textclassifier/ITextSelectionCallback.aidl",
|
||||
"core/java/android/service/attention/IAttentionService.aidl",
|
||||
"core/java/android/service/attention/IAttentionCallback.aidl",
|
||||
"core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl",
|
||||
"core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl",
|
||||
"core/java/android/view/accessibility/IAccessibilityManager.aidl",
|
||||
|
||||
@@ -18,6 +18,7 @@ package android {
|
||||
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
|
||||
field public static final java.lang.String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
|
||||
field public static final java.lang.String BACKUP = "android.permission.BACKUP";
|
||||
field public static final java.lang.String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE";
|
||||
field public static final java.lang.String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE";
|
||||
field public static final deprecated java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
|
||||
field public static final java.lang.String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
|
||||
@@ -5491,6 +5492,28 @@ package android.service.appprediction {
|
||||
|
||||
}
|
||||
|
||||
package android.service.attention {
|
||||
|
||||
public abstract class AttentionService extends android.app.Service {
|
||||
ctor public AttentionService();
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method public abstract void onCancelAttentionCheck(int);
|
||||
method public abstract void onCheckAttention(int, android.service.attention.AttentionService.AttentionCallback);
|
||||
field public static final int ATTENTION_FAILURE_PREEMPTED = 2; // 0x2
|
||||
field public static final int ATTENTION_FAILURE_TIMED_OUT = 3; // 0x3
|
||||
field public static final int ATTENTION_FAILURE_UNKNOWN = 4; // 0x4
|
||||
field public static final int ATTENTION_SUCCESS_ABSENT = 0; // 0x0
|
||||
field public static final int ATTENTION_SUCCESS_PRESENT = 1; // 0x1
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.attention.AttentionService";
|
||||
}
|
||||
|
||||
public static final class AttentionService.AttentionCallback {
|
||||
method public void onFailure(int, int);
|
||||
method public void onSuccess(int, int, long);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.service.autofill {
|
||||
|
||||
public abstract class AutofillFieldClassificationService extends android.app.Service {
|
||||
|
||||
73
core/java/android/attention/AttentionManagerInternal.java
Normal file
73
core/java/android/attention/AttentionManagerInternal.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.attention;
|
||||
|
||||
/**
|
||||
* Attention manager local system server interface.
|
||||
*
|
||||
* @hide Only for use within the system server.
|
||||
*/
|
||||
public abstract class AttentionManagerInternal {
|
||||
/**
|
||||
* Returns {@code true} if attention service is supported on this device.
|
||||
*/
|
||||
public abstract boolean isAttentionServiceSupported();
|
||||
|
||||
/**
|
||||
* Checks whether user attention is at the screen and calls in the provided callback.
|
||||
*
|
||||
* @param requestCode a code associated with the attention check request; this code would be
|
||||
* used to call back in {@link AttentionCallbackInternal#onSuccess} and
|
||||
* {@link AttentionCallbackInternal#onFailure}
|
||||
* @param timeoutMillis a budget for the attention check; if it takes longer - {@link
|
||||
* AttentionCallbackInternal#onFailure} would be called with the {@link
|
||||
* android.service.attention.AttentionService#ATTENTION_FAILURE_TIMED_OUT}
|
||||
* code
|
||||
* @param callback a callback for when the attention check has completed
|
||||
* @return {@code true} if the attention check should succeed; {@false} otherwise.
|
||||
*/
|
||||
public abstract boolean checkAttention(int requestCode,
|
||||
long timeoutMillis, AttentionCallbackInternal callback);
|
||||
|
||||
/**
|
||||
* Cancels the specified attention check in case it's no longer needed.
|
||||
*
|
||||
* @param requestCode a code provided during {@link #checkAttention}
|
||||
*/
|
||||
public abstract void cancelAttentionCheck(int requestCode);
|
||||
|
||||
/** Internal interface for attention callback. */
|
||||
public abstract static class AttentionCallbackInternal {
|
||||
/**
|
||||
* Provides the result of the attention check, if the check was successful.
|
||||
*
|
||||
* @param requestCode a code provided in {@link #checkAttention}
|
||||
* @param result an int with the result of the check
|
||||
* @param timestamp a {@code SystemClock.uptimeMillis()} timestamp associated with the
|
||||
* attention check
|
||||
*/
|
||||
public abstract void onSuccess(int requestCode, int result, long timestamp);
|
||||
|
||||
/**
|
||||
* Provides the explanation for why the attention check had failed.
|
||||
*
|
||||
* @param requestCode a code provided in {@link #checkAttention}
|
||||
* @param error an int with the reason for failure
|
||||
*/
|
||||
public abstract void onFailure(int requestCode, int error);
|
||||
}
|
||||
}
|
||||
160
core/java/android/service/attention/AttentionService.java
Normal file
160
core/java/android/service/attention/AttentionService.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.attention;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class for Attention service.
|
||||
*
|
||||
* <p> An attention service provides attention estimation related features to the system.
|
||||
* The system's default AttentionService implementation is configured in
|
||||
* {@code config_AttentionComponent}. If this config has no value, a stub is returned.
|
||||
*
|
||||
* See: {@link AttentionManagerService}.
|
||||
*
|
||||
* <pre>
|
||||
* {@literal
|
||||
* <service android:name=".YourAttentionService"
|
||||
* android:permission="android.permission.BIND_ATTENTION_SERVICE">
|
||||
* </service>}
|
||||
* </pre>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public abstract class AttentionService extends Service {
|
||||
/**
|
||||
* The {@link Intent} that must be declared as handled by the service. To be supported, the
|
||||
* service must also require the {@link android.Manifest.permission#BIND_ATTENTION_SERVICE}
|
||||
* permission so that other applications can not abuse it.
|
||||
*/
|
||||
public static final String SERVICE_INTERFACE =
|
||||
"android.service.attention.AttentionService";
|
||||
|
||||
/** Attention is absent. */
|
||||
public static final int ATTENTION_SUCCESS_ABSENT = 0;
|
||||
|
||||
/** Attention is present. */
|
||||
public static final int ATTENTION_SUCCESS_PRESENT = 1;
|
||||
|
||||
/** Preempted by other camera user. */
|
||||
public static final int ATTENTION_FAILURE_PREEMPTED = 2;
|
||||
|
||||
/** Preempted by other camera user. */
|
||||
public static final int ATTENTION_FAILURE_TIMED_OUT = 3;
|
||||
|
||||
/** Unknown reasons for failing to determine the attention. */
|
||||
public static final int ATTENTION_FAILURE_UNKNOWN = 4;
|
||||
|
||||
/**
|
||||
* Result codes for when attention check was successful.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = {"ATTENTION_SUCCESS_"}, value = {ATTENTION_SUCCESS_ABSENT,
|
||||
ATTENTION_SUCCESS_PRESENT})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface AttentionSuccessCodes {
|
||||
}
|
||||
|
||||
/**
|
||||
* Result codes explaining why attention check was not successful.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = {"ATTENTION_FAILURE_"}, value = {ATTENTION_FAILURE_PREEMPTED,
|
||||
ATTENTION_FAILURE_TIMED_OUT, ATTENTION_FAILURE_UNKNOWN})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface AttentionFailureCodes {
|
||||
}
|
||||
|
||||
private final IAttentionService.Stub mBinder = new IAttentionService.Stub() {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void checkAttention(int requestCode, IAttentionCallback callback) {
|
||||
Preconditions.checkNotNull(callback);
|
||||
AttentionService.this.onCheckAttention(requestCode, new AttentionCallback(callback));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void cancelAttentionCheck(int requestCode) {
|
||||
AttentionService.this.onCancelAttentionCheck(requestCode);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public final IBinder onBind(Intent intent) {
|
||||
if (SERVICE_INTERFACE.equals(intent.getAction())) {
|
||||
return mBinder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user attention and calls into the provided callback.
|
||||
*
|
||||
* @param requestCode an identifier that could be used to cancel the request
|
||||
* @param callback the callback to return the result to
|
||||
*/
|
||||
public abstract void onCheckAttention(int requestCode, @NonNull AttentionCallback callback);
|
||||
|
||||
/** Cancels the attention check for a given request code. */
|
||||
public abstract void onCancelAttentionCheck(int requestCode);
|
||||
|
||||
|
||||
/** Callbacks for AttentionService results. */
|
||||
public static final class AttentionCallback {
|
||||
private final IAttentionCallback mCallback;
|
||||
|
||||
private AttentionCallback(IAttentionCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
/** Returns the result. */
|
||||
public void onSuccess(int requestCode, @AttentionSuccessCodes int result, long timestamp) {
|
||||
try {
|
||||
mCallback.onSuccess(requestCode, result, timestamp);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/** Signals a failure. */
|
||||
public void onFailure(int requestCode, @AttentionFailureCodes int error) {
|
||||
try {
|
||||
mCallback.onFailure(requestCode, error);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
core/java/android/service/attention/IAttentionCallback.aidl
Normal file
27
core/java/android/service/attention/IAttentionCallback.aidl
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.attention;
|
||||
|
||||
/**
|
||||
* Callback for onCheckAttention request.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IAttentionCallback {
|
||||
void onSuccess(int requestCode, int result, long timestamp);
|
||||
void onFailure(int requestCode, int error);
|
||||
}
|
||||
29
core/java/android/service/attention/IAttentionService.aidl
Normal file
29
core/java/android/service/attention/IAttentionService.aidl
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.attention;
|
||||
|
||||
import android.service.attention.IAttentionCallback;
|
||||
|
||||
/**
|
||||
* Interface for a concrete implementation to provide to the AttentionManagerService.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IAttentionService {
|
||||
void checkAttention(int requestCode, IAttentionCallback callback);
|
||||
void cancelAttentionCheck(int requestCode);
|
||||
}
|
||||
@@ -3056,6 +3056,15 @@
|
||||
<permission android:name="android.permission.BIND_TEXT_SERVICE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @SystemApi Must be required by a AttentionService
|
||||
to ensure that only the system can bind to it.
|
||||
<p>Protection level: signature
|
||||
@hide
|
||||
-->
|
||||
<permission android:name="android.permission.BIND_ATTENTION_SERVICE"
|
||||
android:protectionLevel="signature" />
|
||||
<uses-permission android:name="android.permission.BIND_ATTENTION_SERVICE" />
|
||||
|
||||
<!-- Must be required by a {@link android.net.VpnService},
|
||||
to ensure that only the system can bind to it.
|
||||
<p>Protection level: signature
|
||||
|
||||
@@ -3449,7 +3449,7 @@
|
||||
See android.view.textclassifier.TextClassificationManager.
|
||||
-->
|
||||
<string name="config_defaultTextClassifierPackage" translatable="false"></string>
|
||||
|
||||
|
||||
<!-- The package name for the default wellbeing app.
|
||||
This package must be trusted, as it has the permissions to control other applications
|
||||
on the device.
|
||||
@@ -3457,6 +3457,12 @@
|
||||
-->
|
||||
<string name="config_defaultWellbeingPackage" translatable="false"></string>
|
||||
|
||||
<!-- The component name for the default system attention service.
|
||||
This service must be trusted, as it can be activated without explicit consent of the user.
|
||||
See android.attention.AttentionManagerService.
|
||||
-->
|
||||
<string name="config_defaultAttentionService" translatable="false"></string>
|
||||
|
||||
<!-- The package name for the system's content capture service.
|
||||
This service must be trusted, as it can be activated without explicit consent of the user.
|
||||
If no service with the specified name exists on the device, content capture will be
|
||||
|
||||
@@ -3287,6 +3287,7 @@
|
||||
<java-symbol type="string" name="config_defaultAugmentedAutofillService" />
|
||||
<java-symbol type="string" name="config_defaultAppPredictionService" />
|
||||
<java-symbol type="string" name="config_defaultContentSuggestionsService" />
|
||||
<java-symbol type="string" name="config_defaultAttentionService" />
|
||||
|
||||
<java-symbol type="string" name="notification_channel_foreground_service" />
|
||||
<java-symbol type="string" name="foreground_service_app_in_background" />
|
||||
|
||||
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
* 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.attention;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManager;
|
||||
import android.attention.AttentionManagerInternal;
|
||||
import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.service.attention.AttentionService;
|
||||
import android.service.attention.AttentionService.AttentionFailureCodes;
|
||||
import android.service.attention.IAttentionCallback;
|
||||
import android.service.attention.IAttentionService;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* An attention service implementation that runs in System Server process.
|
||||
* This service publishes a LocalService and reroutes calls to a {@link AttentionService} that it
|
||||
* manages.
|
||||
*/
|
||||
public class AttentionManagerService extends SystemService {
|
||||
private static final String LOG_TAG = "AttentionManagerService";
|
||||
|
||||
/** Service will unbind if connection is not used for that amount of time. */
|
||||
private static final long CONNECTION_TTL_MILLIS = 60_000;
|
||||
|
||||
/** If the check attention called within that period - cached value will be returned. */
|
||||
private static final long STALE_AFTER_MILLIS = 5_000;
|
||||
|
||||
private final Context mContext;
|
||||
private final PowerManager mPowerManager;
|
||||
private final ActivityManager mActivityManager;
|
||||
private final Object mLock;
|
||||
@GuardedBy("mLock")
|
||||
private final SparseArray<UserState> mUserStates = new SparseArray<>();
|
||||
private final AttentionHandler mAttentionHandler;
|
||||
|
||||
private ComponentName mComponentName;
|
||||
|
||||
public AttentionManagerService(Context context) {
|
||||
super(context);
|
||||
mContext = Preconditions.checkNotNull(context);
|
||||
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||
mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
mLock = new Object();
|
||||
mAttentionHandler = new AttentionHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishLocalService(AttentionManagerInternal.class, new LocalService());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopUser(int userId) {
|
||||
cancelAndUnbindLocked(peekUserStateLocked(userId),
|
||||
AttentionService.ATTENTION_FAILURE_UNKNOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
super.onBootPhase(phase);
|
||||
if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
|
||||
mComponentName = resolveAttentionService(mContext);
|
||||
if (mComponentName != null) {
|
||||
// If the service is supported we want to keep receiving the screen off events.
|
||||
mContext.registerReceiver(new ScreenStateReceiver(),
|
||||
new IntentFilter(Intent.ACTION_SCREEN_OFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if attention service is supported on this device.
|
||||
*/
|
||||
public boolean isAttentionServiceSupported() {
|
||||
return mComponentName != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether user attention is at the screen and calls in the provided callback.
|
||||
*
|
||||
* @return {@code true} if the framework was able to send the provided callback to the service
|
||||
*/
|
||||
public boolean checkAttention(int requestCode, long timeout,
|
||||
AttentionCallbackInternal callback) {
|
||||
Preconditions.checkNotNull(callback);
|
||||
|
||||
if (!isAttentionServiceSupported()) {
|
||||
Slog.w(LOG_TAG, "Trying to call checkAttention() on an unsupported device.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// don't allow attention check in screen off state
|
||||
if (!mPowerManager.isInteractive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
unbindAfterTimeoutLocked();
|
||||
|
||||
final UserState userState = getOrCreateCurrentUserStateLocked();
|
||||
// lazily start the service, which should be very lightweight to start
|
||||
if (!userState.bindLocked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (userState.mService == null) {
|
||||
// make sure every callback is called back
|
||||
if (userState.mPendingAttentionCheck != null) {
|
||||
userState.mPendingAttentionCheck.cancel(
|
||||
AttentionService.ATTENTION_FAILURE_UNKNOWN);
|
||||
}
|
||||
userState.mPendingAttentionCheck = new PendingAttentionCheck(requestCode,
|
||||
callback, () -> checkAttention(requestCode, timeout, callback));
|
||||
} else {
|
||||
try {
|
||||
// throttle frequent requests
|
||||
final AttentionCheckCache attentionCheckCache = userState.mAttentionCheckCache;
|
||||
if (attentionCheckCache != null && SystemClock.uptimeMillis()
|
||||
< attentionCheckCache.mLastComputed + STALE_AFTER_MILLIS) {
|
||||
callback.onSuccess(requestCode, attentionCheckCache.mResult,
|
||||
attentionCheckCache.mTimestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
cancelAfterTimeoutLocked(timeout);
|
||||
|
||||
userState.mCurrentAttentionCheckRequestCode = requestCode;
|
||||
userState.mService.checkAttention(requestCode, new IAttentionCallback.Stub() {
|
||||
@Override
|
||||
public void onSuccess(int requestCode, int result, long timestamp) {
|
||||
callback.onSuccess(requestCode, result, timestamp);
|
||||
userState.mAttentionCheckCache = new AttentionCheckCache(
|
||||
SystemClock.uptimeMillis(), result,
|
||||
timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int requestCode, int error) {
|
||||
callback.onFailure(requestCode, error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder asBinder() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(LOG_TAG, "Cannot call into the AttentionService");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Cancels the specified attention check. */
|
||||
public void cancelAttentionCheck(int requestCode) {
|
||||
final UserState userState = getOrCreateCurrentUserStateLocked();
|
||||
try {
|
||||
userState.mService.cancelAttentionCheck(requestCode);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(LOG_TAG, "Cannot call into the AttentionService");
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void unbindAfterTimeoutLocked() {
|
||||
mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CONNECTION_EXPIRED,
|
||||
CONNECTION_TTL_MILLIS);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void cancelAfterTimeoutLocked(long timeout) {
|
||||
mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.ATTENTION_CHECK_TIMEOUT,
|
||||
timeout);
|
||||
}
|
||||
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private UserState getOrCreateCurrentUserStateLocked() {
|
||||
return getOrCreateUserStateLocked(mActivityManager.getCurrentUser());
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private UserState getOrCreateUserStateLocked(int userId) {
|
||||
UserState result = mUserStates.get(userId);
|
||||
if (result == null) {
|
||||
result = new UserState(userId, mContext, mLock);
|
||||
mUserStates.put(userId, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
UserState peekCurrentUserStateLocked() {
|
||||
return peekUserStateLocked(mActivityManager.getCurrentUser());
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
UserState peekUserStateLocked(int userId) {
|
||||
return mUserStates.get(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides attention service component name at runtime, making sure it's provided by the
|
||||
* system.
|
||||
*/
|
||||
private static ComponentName resolveAttentionService(Context context) {
|
||||
// TODO(b/111939367): add a flag to turn on/off.
|
||||
final String componentNameString = context.getString(
|
||||
R.string.config_defaultAttentionService);
|
||||
|
||||
if (TextUtils.isEmpty(componentNameString)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
|
||||
if (componentName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Intent intent = new Intent(AttentionService.SERVICE_INTERFACE).setPackage(
|
||||
componentName.getPackageName());
|
||||
|
||||
// Make sure that only system apps can declare the AttentionService.
|
||||
final ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent,
|
||||
PackageManager.MATCH_SYSTEM_ONLY);
|
||||
if (resolveInfo == null || resolveInfo.serviceInfo == null) {
|
||||
Slog.wtf(LOG_TAG, String.format("Service %s not found in package %s",
|
||||
AttentionService.SERVICE_INTERFACE, componentName
|
||||
));
|
||||
return null;
|
||||
}
|
||||
|
||||
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
|
||||
final String permission = serviceInfo.permission;
|
||||
if (Manifest.permission.BIND_ATTENTION_SERVICE.equals(permission)) {
|
||||
return serviceInfo.getComponentName();
|
||||
}
|
||||
Slog.e(LOG_TAG, String.format(
|
||||
"Service %s should require %s permission. Found %s permission",
|
||||
serviceInfo.getComponentName(),
|
||||
Manifest.permission.BIND_ATTENTION_SERVICE,
|
||||
serviceInfo.permission));
|
||||
return null;
|
||||
}
|
||||
|
||||
private void dumpInternal(PrintWriter pw) {
|
||||
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
|
||||
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
|
||||
ipw.println("Attention Manager Service (dumpsys attention)\n");
|
||||
|
||||
ipw.printPair("context", mContext);
|
||||
pw.println();
|
||||
synchronized (mLock) {
|
||||
int size = mUserStates.size();
|
||||
ipw.print("Number user states: ");
|
||||
pw.println(size);
|
||||
if (size > 0) {
|
||||
ipw.increaseIndent();
|
||||
for (int i = 0; i < size; i++) {
|
||||
UserState userState = mUserStates.valueAt(i);
|
||||
ipw.print(i);
|
||||
ipw.print(":");
|
||||
userState.dump(ipw);
|
||||
ipw.println();
|
||||
}
|
||||
ipw.decreaseIndent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class LocalService extends AttentionManagerInternal {
|
||||
@Override
|
||||
public boolean isAttentionServiceSupported() {
|
||||
return AttentionManagerService.this.isAttentionServiceSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkAttention(int requestCode, long timeout,
|
||||
AttentionCallbackInternal callback) {
|
||||
return AttentionManagerService.this.checkAttention(requestCode, timeout, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelAttentionCheck(int requestCode) {
|
||||
AttentionManagerService.this.cancelAttentionCheck(requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AttentionCheckCache {
|
||||
private final long mLastComputed;
|
||||
private final int mResult;
|
||||
private final long mTimestamp;
|
||||
|
||||
AttentionCheckCache(long lastComputed, @AttentionService.AttentionSuccessCodes int result,
|
||||
long timestamp) {
|
||||
mLastComputed = lastComputed;
|
||||
mResult = result;
|
||||
mTimestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PendingAttentionCheck {
|
||||
private final int mRequestCode;
|
||||
private final AttentionCallbackInternal mCallback;
|
||||
private final Runnable mRunnable;
|
||||
|
||||
PendingAttentionCheck(int requestCode, AttentionCallbackInternal callback,
|
||||
Runnable runnable) {
|
||||
mRequestCode = requestCode;
|
||||
mCallback = callback;
|
||||
mRunnable = runnable;
|
||||
}
|
||||
|
||||
void cancel(@AttentionFailureCodes int failureCode) {
|
||||
mCallback.onFailure(mRequestCode, failureCode);
|
||||
}
|
||||
|
||||
void run() {
|
||||
mRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class UserState {
|
||||
final AttentionServiceConnection mConnection = new AttentionServiceConnection();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
IAttentionService mService;
|
||||
@GuardedBy("mLock")
|
||||
boolean mBinding;
|
||||
@GuardedBy("mLock")
|
||||
int mCurrentAttentionCheckRequestCode;
|
||||
@GuardedBy("mLock")
|
||||
PendingAttentionCheck mPendingAttentionCheck;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
AttentionCheckCache mAttentionCheckCache;
|
||||
|
||||
@UserIdInt
|
||||
final int mUserId;
|
||||
final Context mContext;
|
||||
final Object mLock;
|
||||
|
||||
private UserState(int userId, Context context, Object lock) {
|
||||
mUserId = userId;
|
||||
mContext = Preconditions.checkNotNull(context);
|
||||
mLock = Preconditions.checkNotNull(lock);
|
||||
}
|
||||
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void handlePendingCallbackLocked() {
|
||||
if (mService != null && mPendingAttentionCheck != null) {
|
||||
mPendingAttentionCheck.run();
|
||||
mPendingAttentionCheck = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Binds to the system's AttentionService which provides an actual implementation. */
|
||||
@GuardedBy("mLock")
|
||||
private boolean bindLocked() {
|
||||
// No need to bind if service is binding or has already been bound.
|
||||
if (mBinding || mService != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final boolean willBind;
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
|
||||
try {
|
||||
final ComponentName componentName =
|
||||
resolveAttentionService(mContext);
|
||||
if (componentName == null) {
|
||||
// Might happen if the storage is encrypted and the user is not unlocked
|
||||
return false;
|
||||
}
|
||||
final Intent mServiceIntent = new Intent(
|
||||
AttentionService.SERVICE_INTERFACE).setComponent(
|
||||
componentName);
|
||||
willBind = mContext.bindServiceAsUser(mServiceIntent, mConnection,
|
||||
Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
|
||||
mBinding = willBind;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
return willBind;
|
||||
}
|
||||
|
||||
private void dump(IndentingPrintWriter pw) {
|
||||
pw.printPair("context", mContext);
|
||||
pw.printPair("userId", mUserId);
|
||||
synchronized (mLock) {
|
||||
pw.printPair("binding", mBinding);
|
||||
pw.printPair("isAttentionCheckPending", mPendingAttentionCheck != null);
|
||||
}
|
||||
}
|
||||
|
||||
private final class AttentionServiceConnection implements ServiceConnection {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
init(IAttentionService.Stub.asInterface(service));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
cleanupService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindingDied(ComponentName name) {
|
||||
cleanupService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNullBinding(ComponentName name) {
|
||||
cleanupService();
|
||||
}
|
||||
|
||||
void cleanupService() {
|
||||
init(null);
|
||||
}
|
||||
|
||||
private void init(@Nullable IAttentionService service) {
|
||||
synchronized (mLock) {
|
||||
mService = service;
|
||||
mBinding = false;
|
||||
handlePendingCallbackLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AttentionHandler extends Handler {
|
||||
private static final int CONNECTION_EXPIRED = 1;
|
||||
private static final int ATTENTION_CHECK_TIMEOUT = 2;
|
||||
|
||||
AttentionHandler() {
|
||||
super(Looper.myLooper());
|
||||
}
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
// Do not occupy resources when not in use - unbind proactively.
|
||||
case CONNECTION_EXPIRED: {
|
||||
for (int i = 0; i < mUserStates.size(); i++) {
|
||||
cancelAndUnbindLocked(mUserStates.valueAt(i),
|
||||
AttentionService.ATTENTION_FAILURE_UNKNOWN);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Callee is no longer interested in the attention check result - cancel.
|
||||
case ATTENTION_CHECK_TIMEOUT: {
|
||||
cancelAndUnbindLocked(peekCurrentUserStateLocked(),
|
||||
AttentionService.ATTENTION_FAILURE_TIMED_OUT);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void cancelAndUnbindLocked(UserState userState,
|
||||
@AttentionFailureCodes int failureCode) {
|
||||
synchronized (mLock) {
|
||||
if (userState != null && userState.mService != null) {
|
||||
try {
|
||||
userState.mService.cancelAttentionCheck(
|
||||
userState.mCurrentAttentionCheckRequestCode);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(LOG_TAG, "Unable to cancel attention check");
|
||||
}
|
||||
|
||||
if (userState.mPendingAttentionCheck != null) {
|
||||
userState.mPendingAttentionCheck.cancel(failureCode);
|
||||
}
|
||||
mContext.unbindService(userState.mConnection);
|
||||
userState.mConnection.cleanupService();
|
||||
mUserStates.remove(userState.mUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbinds and stops the service when the screen off intent is received.
|
||||
* Attention service only makes sense when screen is ON; disconnect and stop service otherwise.
|
||||
*/
|
||||
private final class ScreenStateReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
|
||||
cancelAndUnbindLocked(peekCurrentUserStateLocked(),
|
||||
AttentionService.ATTENTION_FAILURE_UNKNOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@ import com.android.internal.util.EmergencyAffordanceManager;
|
||||
import com.android.internal.widget.ILockSettings;
|
||||
import com.android.server.am.ActivityManagerService;
|
||||
import com.android.server.appbinding.AppBindingService;
|
||||
import com.android.server.attention.AttentionManagerService;
|
||||
import com.android.server.audio.AudioService;
|
||||
import com.android.server.biometrics.BiometricService;
|
||||
import com.android.server.biometrics.face.FaceService;
|
||||
@@ -148,10 +149,11 @@ import com.android.server.webkit.WebViewUpdateService;
|
||||
import com.android.server.wm.ActivityTaskManagerService;
|
||||
import com.android.server.wm.WindowManagerGlobalLock;
|
||||
import com.android.server.wm.WindowManagerService;
|
||||
import com.google.android.startop.iorap.IorapForwardingService;
|
||||
|
||||
import dalvik.system.VMRuntime;
|
||||
|
||||
import com.google.android.startop.iorap.IorapForwardingService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
@@ -1230,6 +1232,10 @@ public final class SystemServer {
|
||||
traceEnd();
|
||||
}
|
||||
|
||||
traceBeginAndSlog("StartAttentionManagerService");
|
||||
mSystemServiceManager.startService(AttentionManagerService.class);
|
||||
traceEnd();
|
||||
|
||||
traceBeginAndSlog("StartNetworkScoreService");
|
||||
mSystemServiceManager.startService(NetworkScoreService.Lifecycle.class);
|
||||
traceEnd();
|
||||
|
||||
Reference in New Issue
Block a user