1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.devicelock; 18 19 import android.annotation.IntDef; 20 import android.os.OutcomeReceiver; 21 22 import com.android.devicelock.flags.Flags; 23 import com.android.internal.annotations.GuardedBy; 24 25 import java.lang.annotation.ElementType; 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 import java.lang.annotation.Target; 29 30 /** 31 * Stub implementation of the connector that is used when the device has had its restrictions 32 * cleared so that we don't try to bind to a disabled package. 33 */ 34 public class DeviceLockControllerConnectorStub implements DeviceLockControllerConnector { 35 // Pseudo states used for CTS conformance when a device is finalized. 36 @Target(ElementType.TYPE_USE) 37 @Retention(RetentionPolicy.SOURCE) 38 @IntDef({ 39 DevicePseudoState.UNDEFINED, 40 DevicePseudoState.LOCKED, 41 DevicePseudoState.UNLOCKED, 42 DevicePseudoState.CLEARED, 43 }) 44 private @interface DevicePseudoState { 45 int UNDEFINED = 0; 46 int UNLOCKED = 1; 47 int LOCKED = 2; 48 int CLEARED = 3; 49 } 50 51 @GuardedBy("this") 52 private @DevicePseudoState int mPseudoState = DevicePseudoState.UNDEFINED; 53 54 @Override unbind()55 public void unbind() {} 56 57 @Override lockDevice(OutcomeReceiver<Void, Exception> callback)58 public void lockDevice(OutcomeReceiver<Void, Exception> callback) { 59 synchronized (this) { 60 if (setExceptionIfDeviceIsCleared(callback)) { 61 return; 62 } 63 64 mPseudoState = DevicePseudoState.LOCKED; 65 } 66 callback.onResult(/* result= */ null); 67 } 68 69 @Override unlockDevice(OutcomeReceiver<Void, Exception> callback)70 public void unlockDevice(OutcomeReceiver<Void, Exception> callback) { 71 synchronized (this) { 72 if (setExceptionIfDeviceIsCleared(callback)) { 73 return; 74 } 75 76 mPseudoState = DevicePseudoState.UNLOCKED; 77 } 78 callback.onResult(/* result= */ null); 79 } 80 81 @Override isDeviceLocked(OutcomeReceiver<Boolean, Exception> callback)82 public void isDeviceLocked(OutcomeReceiver<Boolean, Exception> callback) { 83 boolean isLocked; 84 85 synchronized (this) { 86 if (setExceptionIfDeviceIsCleared(callback)) { 87 return; 88 } 89 90 if (mPseudoState == DevicePseudoState.UNDEFINED) { 91 setException(callback, "isLocked called before setting the lock state"); 92 93 return; 94 } 95 96 isLocked = mPseudoState == DevicePseudoState.LOCKED; 97 } 98 99 callback.onResult(isLocked); 100 } 101 102 @Override getDeviceId(OutcomeReceiver<String, Exception> callback)103 public void getDeviceId(OutcomeReceiver<String, Exception> callback) { 104 setException(callback, "No registered Device ID found"); 105 } 106 107 @Override clearDeviceRestrictions(OutcomeReceiver<Void, Exception> callback)108 public void clearDeviceRestrictions(OutcomeReceiver<Void, Exception> callback) { 109 synchronized (this) { 110 if (setExceptionIfDeviceIsCleared(callback)) { 111 return; 112 } 113 114 mPseudoState = DevicePseudoState.CLEARED; 115 } 116 callback.onResult(/* result= */ null); 117 } 118 119 @Override onUserSwitching(OutcomeReceiver<Void, Exception> callback)120 public void onUserSwitching(OutcomeReceiver<Void, Exception> callback) { 121 // Do not throw exception as we expect this to be called 122 callback.onResult(/* result= */ null); 123 } 124 125 @Override onUserUnlocked(OutcomeReceiver<Void, Exception> callback)126 public void onUserUnlocked(OutcomeReceiver<Void, Exception> callback) { 127 // Do not throw exception as we expect this to be called 128 callback.onResult(/* result= */ null); 129 } 130 131 @Override onUserSetupCompleted(OutcomeReceiver<Void, Exception> callback)132 public void onUserSetupCompleted(OutcomeReceiver<Void, Exception> callback) { 133 // Do not throw exception as we expect this to be called 134 callback.onResult(/* result= */ null); 135 } 136 137 @Override onAppCrashed(boolean isKiosk, OutcomeReceiver<Void, Exception> callback)138 public void onAppCrashed(boolean isKiosk, OutcomeReceiver<Void, Exception> callback) { 139 setException(callback, "Device lock controller package is disabled"); 140 } 141 setException(OutcomeReceiver<?, Exception> callback, String message)142 private static void setException(OutcomeReceiver<?, Exception> callback, String message) { 143 callback.onError(new IllegalStateException(message)); 144 } 145 146 @GuardedBy("this") setExceptionIfDeviceIsCleared(OutcomeReceiver<?, Exception> callback)147 private boolean setExceptionIfDeviceIsCleared(OutcomeReceiver<?, Exception> callback) { 148 if (Flags.clearDeviceRestrictions()) { 149 return false; 150 } 151 152 if (mPseudoState == DevicePseudoState.CLEARED) { 153 setException(callback, "Device has been cleared!"); 154 155 return true; 156 } 157 158 return false; 159 } 160 } 161