Merge "Fix secondary lock screen implementation such that DevicePolicyKeyguardService calls are made on the main (UI) thread." into rvc-dev

This commit is contained in:
Yvonne Jiang
2020-04-09 07:26:48 +00:00
committed by Android (Google) Code Review
6 changed files with 80 additions and 22 deletions

View File

@@ -16,12 +16,15 @@
package android.app.admin; package android.app.admin;
import android.annotation.MainThread;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.SystemApi; import android.annotation.SystemApi;
import android.app.Service; import android.app.Service;
import android.content.Intent; import android.content.Intent;
import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.view.SurfaceControlViewHost; import android.view.SurfaceControlViewHost;
@@ -41,26 +44,33 @@ import android.view.SurfaceControlViewHost;
@SystemApi @SystemApi
public class DevicePolicyKeyguardService extends Service { public class DevicePolicyKeyguardService extends Service {
private static final String TAG = "DevicePolicyKeyguardService"; private static final String TAG = "DevicePolicyKeyguardService";
private final Handler mHandler = new Handler(Looper.getMainLooper());
private IKeyguardCallback mCallback; private IKeyguardCallback mCallback;
private final IKeyguardClient mClient = new IKeyguardClient.Stub() { private final IKeyguardClient mClient = new IKeyguardClient.Stub() {
@MainThread
@Override @Override
public void onCreateKeyguardSurface(@Nullable IBinder hostInputToken, public void onCreateKeyguardSurface(@Nullable IBinder hostInputToken,
IKeyguardCallback callback) { @NonNull IKeyguardCallback callback) {
mCallback = callback; mCallback = callback;
SurfaceControlViewHost.SurfacePackage surfacePackage = mHandler.post(() -> {
DevicePolicyKeyguardService.this.onCreateKeyguardSurface(hostInputToken); SurfaceControlViewHost.SurfacePackage surfacePackage =
DevicePolicyKeyguardService.this.onCreateKeyguardSurface(hostInputToken);
if (mCallback != null) {
try { try {
mCallback.onRemoteContentReady(surfacePackage); mCallback.onRemoteContentReady(surfacePackage);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Failed to return created SurfacePackage", e); Log.e(TAG, "Failed to return created SurfacePackage", e);
} }
} });
} }
}; };
@Override
public void onDestroy() {
mHandler.removeCallbacksAndMessages(null);
}
@Override @Override
@Nullable @Nullable
public final IBinder onBind(@Nullable Intent intent) { public final IBinder onBind(@Nullable Intent intent) {
@@ -97,6 +107,10 @@ public class DevicePolicyKeyguardService extends Service {
*/ */
@Nullable @Nullable
public void dismiss() { public void dismiss() {
if (mCallback == null) {
Log.w(TAG, "KeyguardCallback was unexpectedly null");
return;
}
try { try {
mCallback.onDismiss(); mCallback.onDismiss();
} catch (RemoteException e) { } catch (RemoteException e) {

View File

@@ -34,6 +34,8 @@ import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import java.util.NoSuchElementException;
/** /**
* Encapsulates all logic for secondary lockscreen state management. * Encapsulates all logic for secondary lockscreen state management.
*/ */
@@ -79,7 +81,9 @@ public class AdminSecondaryLockScreenController {
private final IKeyguardCallback mCallback = new IKeyguardCallback.Stub() { private final IKeyguardCallback mCallback = new IKeyguardCallback.Stub() {
@Override @Override
public void onDismiss() { public void onDismiss() {
dismiss(UserHandle.getCallingUserId()); mHandler.post(() -> {
dismiss(UserHandle.getCallingUserId());
});
} }
@Override @Override
@@ -91,7 +95,9 @@ public class AdminSecondaryLockScreenController {
if (surfacePackage != null) { if (surfacePackage != null) {
mView.setChildSurfacePackage(surfacePackage); mView.setChildSurfacePackage(surfacePackage);
} else { } else {
dismiss(KeyguardUpdateMonitor.getCurrentUser()); mHandler.post(() -> {
dismiss(KeyguardUpdateMonitor.getCurrentUser());
});
} }
} }
}; };
@@ -122,6 +128,7 @@ public class AdminSecondaryLockScreenController {
// If the remote content is not readied within the timeout period, // If the remote content is not readied within the timeout period,
// move on without the secondary lockscreen. // move on without the secondary lockscreen.
dismiss(userId); dismiss(userId);
Log.w(TAG, "Timed out waiting for secondary lockscreen content.");
}, },
REMOTE_CONTENT_READY_TIMEOUT_MILLIS); REMOTE_CONTENT_READY_TIMEOUT_MILLIS);
} }
@@ -150,8 +157,12 @@ public class AdminSecondaryLockScreenController {
* Displays the Admin security Surface view. * Displays the Admin security Surface view.
*/ */
public void show(Intent serviceIntent) { public void show(Intent serviceIntent) {
mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE); if (mClient == null) {
mParent.addView(mView); mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
}
if (!mView.isAttachedToWindow()) {
mParent.addView(mView);
}
} }
/** /**
@@ -162,7 +173,11 @@ public class AdminSecondaryLockScreenController {
mParent.removeView(mView); mParent.removeView(mView);
} }
if (mClient != null) { if (mClient != null) {
mClient.asBinder().unlinkToDeath(mKeyguardClientDeathRecipient, 0); try {
mClient.asBinder().unlinkToDeath(mKeyguardClientDeathRecipient, 0);
} catch (NoSuchElementException e) {
Log.w(TAG, "IKeyguardClient death recipient already released");
}
mContext.unbindService(mConnection); mContext.unbindService(mConnection);
mClient = null; mClient = null;
} }
@@ -185,10 +200,12 @@ public class AdminSecondaryLockScreenController {
private void dismiss(int userId) { private void dismiss(int userId) {
mHandler.removeCallbacksAndMessages(null); mHandler.removeCallbacksAndMessages(null);
if (mView != null && mView.isAttachedToWindow() if (mView.isAttachedToWindow() && userId == KeyguardUpdateMonitor.getCurrentUser()) {
&& userId == KeyguardUpdateMonitor.getCurrentUser()) {
hide(); hide();
mKeyguardCallback.dismiss(true, userId); if (mKeyguardCallback != null) {
mKeyguardCallback.dismiss(/* securityVerified= */ true, userId,
/* bypassSecondaryLockScreen= */true);
}
} }
} }

View File

@@ -85,7 +85,8 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
// the user proved presence via some other way to the trust agent. // the user proved presence via some other way to the trust agent.
Log.i(TAG, "TrustAgent dismissed Keyguard."); Log.i(TAG, "TrustAgent dismissed Keyguard.");
} }
dismiss(false /* authenticated */, userId); dismiss(false /* authenticated */, userId,
/* bypassSecondaryLockScreen */ false);
} else { } else {
mViewMediatorCallback.playTrustedSound(); mViewMediatorCallback.playTrustedSound();
} }
@@ -190,7 +191,7 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
* @return True if the keyguard is done. * @return True if the keyguard is done.
*/ */
public boolean dismiss(int targetUserId) { public boolean dismiss(int targetUserId) {
return dismiss(false, targetUserId); return dismiss(false, targetUserId, false);
} }
public boolean handleBackKey() { public boolean handleBackKey() {
@@ -206,8 +207,10 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
} }
@Override @Override
public boolean dismiss(boolean authenticated, int targetUserId) { public boolean dismiss(boolean authenticated, int targetUserId,
return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId); boolean bypassSecondaryLockScreen) {
return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId,
bypassSecondaryLockScreen);
} }
/** /**

View File

@@ -24,6 +24,15 @@ public interface KeyguardSecurityCallback {
*/ */
void dismiss(boolean securityVerified, int targetUserId); void dismiss(boolean securityVerified, int targetUserId);
/**
* Dismiss the given security screen.
* @param securityVerified true if the user correctly entered credentials for the given screen.
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
* @param bypassSecondaryLockScreen true if the user can bypass the secondary lock screen,
* if any, during this dismissal.
*/
void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen);
/** /**
* Manually report user activity to keep the device awake. * Manually report user activity to keep the device awake.
*/ */

View File

@@ -115,7 +115,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
// Used to notify the container when something interesting happens. // Used to notify the container when something interesting happens.
public interface SecurityCallback { public interface SecurityCallback {
public boolean dismiss(boolean authenticated, int targetUserId); public boolean dismiss(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen);
public void userActivity(); public void userActivity();
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
@@ -504,9 +505,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
* @param authenticated true if the user entered the correct authentication * @param authenticated true if the user entered the correct authentication
* @param targetUserId a user that needs to be the foreground user at the finish (if called) * @param targetUserId a user that needs to be the foreground user at the finish (if called)
* completion. * completion.
* @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
* secondary lock screen requirement, if any.
* @return true if keyguard is done * @return true if keyguard is done
*/ */
boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId) { boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) {
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
boolean finish = false; boolean finish = false;
boolean strongAuth = false; boolean strongAuth = false;
@@ -555,7 +559,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
} }
} }
// Check for device admin specified additional security measures. // Check for device admin specified additional security measures.
if (finish) { if (finish && !bypassSecondaryLockScreen) {
Intent secondaryLockscreenIntent = Intent secondaryLockscreenIntent =
mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId); mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
if (secondaryLockscreenIntent != null) { if (secondaryLockscreenIntent != null) {
@@ -636,8 +640,15 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
mUpdateMonitor.cancelFaceAuth(); mUpdateMonitor.cancelFaceAuth();
} }
@Override
public void dismiss(boolean authenticated, int targetId) { public void dismiss(boolean authenticated, int targetId) {
mSecurityCallback.dismiss(authenticated, targetId); dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
}
@Override
public void dismiss(boolean authenticated, int targetId,
boolean bypassSecondaryLockScreen) {
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
} }
public boolean isVerifyUnlockOnly() { public boolean isVerifyUnlockOnly() {
@@ -689,6 +700,9 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
@Override @Override
public void dismiss(boolean securityVerified, int targetUserId) { } public void dismiss(boolean securityVerified, int targetUserId) { }
@Override @Override
public void dismiss(boolean authenticated, int targetId,
boolean bypassSecondaryLockScreen) { }
@Override
public void onUserInput() { } public void onUserInput() { }
@Override @Override
public void reset() {} public void reset() {}

View File

@@ -115,6 +115,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
@Test @Test
public void testShow_dismissedByCallback() throws Exception { public void testShow_dismissedByCallback() throws Exception {
doAnswer(answerVoid(Runnable::run)).when(mHandler).post(any(Runnable.class));
doAnswer(invocation -> { doAnswer(invocation -> {
IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1]; IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
callback.onDismiss(); callback.onDismiss();
@@ -184,7 +185,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
private void verifyViewDismissed(SurfaceView v) throws Exception { private void verifyViewDismissed(SurfaceView v) throws Exception {
verify(mParent).removeView(v); verify(mParent).removeView(v);
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID); verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true);
assertThat(mContext.isBound(mComponentName)).isFalse(); assertThat(mContext.isBound(mComponentName)).isFalse();
} }
} }