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.devicelockcontroller.debug; 18 19 import static com.android.devicelockcontroller.common.DeviceLockConstants.DeviceProvisionState.PROVISION_STATE_UNSPECIFIED; 20 import static com.android.devicelockcontroller.common.DeviceLockConstants.READY_FOR_PROVISION; 21 22 import android.content.Context; 23 import android.content.SharedPreferences; 24 import android.os.SystemClock; 25 import android.util.ArraySet; 26 27 import androidx.annotation.Keep; 28 import androidx.annotation.Nullable; 29 30 import com.android.devicelockcontroller.common.DeviceId; 31 import com.android.devicelockcontroller.common.DeviceLockConstants.DeviceCheckInStatus; 32 import com.android.devicelockcontroller.common.DeviceLockConstants.DeviceProvisionState; 33 import com.android.devicelockcontroller.common.DeviceLockConstants.ProvisionFailureReason; 34 import com.android.devicelockcontroller.common.DeviceLockConstants.ProvisioningType; 35 import com.android.devicelockcontroller.provision.grpc.DeviceCheckInClient; 36 import com.android.devicelockcontroller.provision.grpc.GetDeviceCheckInStatusGrpcResponse; 37 import com.android.devicelockcontroller.provision.grpc.IsDeviceInApprovedCountryGrpcResponse; 38 import com.android.devicelockcontroller.provision.grpc.PauseDeviceProvisioningGrpcResponse; 39 import com.android.devicelockcontroller.provision.grpc.ProvisioningConfiguration; 40 import com.android.devicelockcontroller.provision.grpc.ReportDeviceProvisionStateGrpcResponse; 41 import com.android.devicelockcontroller.util.LogUtil; 42 import com.android.devicelockcontroller.util.ThreadAsserts; 43 44 import java.time.Duration; 45 import java.time.Instant; 46 import java.util.List; 47 48 /** 49 * An implementation of the {@link DeviceCheckInClient} which simulate server responses by 50 * reading it from local storage. 51 */ 52 @Keep 53 public final class DeviceCheckInClientDebug extends DeviceCheckInClient { 54 55 public static final String TAG = "DeviceCheckInClientDebug"; 56 public static final String DEBUG_DEVICELOCK_CHECKIN_STATUS = "debug.devicelock.checkin.status"; 57 public static final String DEBUG_DEVICELOCK_CHECKIN_RETRY_DELAY = 58 "debug.devicelock.checkin.retry-delay"; 59 public static final String DEBUG_DEVICELOCK_CHECKIN_FORCE_PROVISIONING = 60 "debug.devicelock.checkin.force-provisioning"; 61 public static final String DEBUG_DEVICELOCK_CHECKIN_APPROVED_COUNTRY = 62 "debug.devicelock.checkin.approved-country"; 63 public static final String DEBUG_DEVICELOCK_CHECKIN_NEXT_PROVISION_STATE = 64 "debug.devicelock.checkin.next-provision-state"; 65 public static final String DEBUG_DEVICELOCK_CHECKIN_DAYS_LEFT_UNTIL_RESET = 66 "debug.devicelock.checkin.days-left-until-reset"; 67 setDebugClientEnabled(Context context, boolean enabled)68 static void setDebugClientEnabled(Context context, boolean enabled) { 69 getSharedPreferences(context).edit().putBoolean(DEBUG_DEVICELOCK_CHECKIN, enabled).apply(); 70 } 71 setDebugCheckInStatus(Context context, @DeviceCheckInStatus int status)72 static void setDebugCheckInStatus(Context context, @DeviceCheckInStatus int status) { 73 getSharedPreferences(context).edit().putInt(DEBUG_DEVICELOCK_CHECKIN_STATUS, 74 status).apply(); 75 } 76 setDebugForceProvisioning(Context context, boolean isForced)77 static void setDebugForceProvisioning(Context context, boolean isForced) { 78 getSharedPreferences(context).edit().putBoolean(DEBUG_DEVICELOCK_CHECKIN_FORCE_PROVISIONING, 79 isForced).apply(); 80 } 81 setDebugCheckInRetryDelay(Context context, int delayMinute)82 static void setDebugCheckInRetryDelay(Context context, int delayMinute) { 83 getSharedPreferences(context).edit().putInt(DEBUG_DEVICELOCK_CHECKIN_RETRY_DELAY, 84 delayMinute).apply(); 85 } 86 setDebugApprovedCountry(Context context, boolean isInApprovedCountry)87 static void setDebugApprovedCountry(Context context, 88 boolean isInApprovedCountry) { 89 getSharedPreferences(context).edit().putBoolean(DEBUG_DEVICELOCK_CHECKIN_APPROVED_COUNTRY, 90 isInApprovedCountry).apply(); 91 } 92 setDebugNextProvisionState( Context context, @DeviceProvisionState int provisionState)93 static void setDebugNextProvisionState( 94 Context context, @DeviceProvisionState int provisionState) { 95 getSharedPreferences(context).edit().putInt(DEBUG_DEVICELOCK_CHECKIN_NEXT_PROVISION_STATE, 96 provisionState).apply(); 97 } 98 setDebugDaysLeftUntilReset(Context context, int daysLeftUntilReset)99 static void setDebugDaysLeftUntilReset(Context context, 100 int daysLeftUntilReset) { 101 getSharedPreferences(context).edit().putInt(DEBUG_DEVICELOCK_CHECKIN_DAYS_LEFT_UNTIL_RESET, 102 daysLeftUntilReset).apply(); 103 } 104 dumpDebugCheckInClientResponses(Context context)105 static void dumpDebugCheckInClientResponses(Context context) { 106 LogUtil.d(TAG, 107 "Current Debug Client Responses:\n" + getSharedPreferences(context).getAll()); 108 } 109 clear(Context context)110 static void clear(Context context) { 111 getSharedPreferences(context).edit().clear().apply(); 112 } 113 getSharedPreference(String key, T defValue)114 private static <T> T getSharedPreference(String key, T defValue) { 115 SharedPreferences preferences = getSharedPreferences(/* context= */ null); 116 if (preferences == null) return defValue; 117 T value = (T) preferences.getAll().get(key); 118 return value == null ? defValue : value; 119 } 120 121 /** 122 * Check In with DeviceLock backend server and get the next step for the device. 123 */ 124 @Override getDeviceCheckInStatus(ArraySet<DeviceId> deviceIds, String carrierInfo, @Nullable String fcmRegistrationToken)125 public GetDeviceCheckInStatusGrpcResponse getDeviceCheckInStatus(ArraySet<DeviceId> deviceIds, 126 String carrierInfo, @Nullable String fcmRegistrationToken) { 127 ThreadAsserts.assertWorkerThread("getDeviceCheckInStatus"); 128 return new GetDeviceCheckInStatusGrpcResponse() { 129 @Override 130 @DeviceCheckInStatus 131 public int getDeviceCheckInStatus() { 132 return DebugLogUtil.logAndReturn(TAG, 133 getSharedPreference(DEBUG_DEVICELOCK_CHECKIN_STATUS, READY_FOR_PROVISION)); 134 } 135 136 @Nullable 137 @Override 138 public String getRegisteredDeviceIdentifier() { 139 return DebugLogUtil.logAndReturn(TAG, 140 !deviceIds.isEmpty() ? deviceIds.valueAt(0).getId() : null); 141 } 142 143 @Nullable 144 @Override 145 public Instant getNextCheckInTime() { 146 Duration delay = Duration.ofMinutes( 147 getSharedPreference(DEBUG_DEVICELOCK_CHECKIN_RETRY_DELAY, /* def= */ 1)); 148 return DebugLogUtil.logAndReturn(TAG, 149 SystemClock.currentNetworkTimeClock().instant().plus(delay)); 150 } 151 152 @Nullable 153 @Override 154 public ProvisioningConfiguration getProvisioningConfig() { 155 // This should be overridden using SetupParametersOverrider. 156 return new ProvisioningConfiguration( 157 /* kioskAppProviderName= */ "", 158 /* kioskAppPackageName= */ "", 159 /* kioskAppAllowlistPackages= */ List.of(""), 160 /* kioskAppEnableOutgoingCalls= */ false, 161 /* kioskAppEnableEnableNotifications= */ false, 162 /* disallowInstallingFromUnknownSources= */ false, 163 /* termsAndConditionsUrl= */ "", 164 /* supportUrl= */ ""); 165 } 166 167 @Override 168 public @ProvisioningType int getProvisioningType() { 169 // This should be overridden using SetupParametersOverrider. 170 return ProvisioningType.TYPE_UNDEFINED; 171 } 172 173 @Override 174 public boolean isProvisioningMandatory() { 175 // This should be overridden using SetupParametersOverrider. 176 return false; 177 } 178 179 @Override 180 public boolean isProvisionForced() { 181 return DebugLogUtil.logAndReturn(TAG, 182 getSharedPreference(DEBUG_DEVICELOCK_CHECKIN_FORCE_PROVISIONING, false)); 183 } 184 185 @Override 186 public boolean isDeviceInApprovedCountry() { 187 return DebugLogUtil.logAndReturn(TAG, 188 getSharedPreference(DEBUG_DEVICELOCK_CHECKIN_APPROVED_COUNTRY, true)); 189 } 190 191 @Override 192 public boolean isDebuggingAllowed() { 193 // This value should not matter since the device is already on a debug build and 194 // can use debugging. 195 return true; 196 } 197 }; 198 } 199 200 /** 201 * Check if the device is in an approved country for the device lock program. 202 */ 203 @Override 204 public IsDeviceInApprovedCountryGrpcResponse isDeviceInApprovedCountry( 205 @Nullable String carrierInfo) { 206 ThreadAsserts.assertWorkerThread("isDeviceInApprovedCountry"); 207 return new IsDeviceInApprovedCountryGrpcResponse() { 208 @Override 209 public boolean isDeviceInApprovedCountry() { 210 return DebugLogUtil.logAndReturn(TAG, 211 getSharedPreference(DEBUG_DEVICELOCK_CHECKIN_APPROVED_COUNTRY, true)); 212 } 213 }; 214 } 215 216 /** 217 * Inform the server that device provisioning has been paused for a certain amount of time. 218 */ 219 @Override 220 public PauseDeviceProvisioningGrpcResponse pauseDeviceProvisioning(int reason) { 221 ThreadAsserts.assertWorkerThread("pauseDeviceProvisioning"); 222 return new PauseDeviceProvisioningGrpcResponse(); 223 } 224 225 /** 226 * Reports the current provision state of the device. 227 */ 228 @Override 229 public ReportDeviceProvisionStateGrpcResponse reportDeviceProvisionState( 230 int lastReceivedProvisionState, boolean isSuccessful, 231 @ProvisionFailureReason int reason) { 232 ThreadAsserts.assertWorkerThread("reportDeviceProvisionState"); 233 return new ReportDeviceProvisionStateGrpcResponse() { 234 @Override 235 @DeviceProvisionState 236 public int getNextClientProvisionState() { 237 return DebugLogUtil.logAndReturn(TAG, getSharedPreference( 238 DEBUG_DEVICELOCK_CHECKIN_NEXT_PROVISION_STATE, 239 PROVISION_STATE_UNSPECIFIED)); 240 } 241 242 @Override 243 public int getDaysLeftUntilReset() { 244 return DebugLogUtil.logAndReturn(TAG, 245 getSharedPreference( 246 DEBUG_DEVICELOCK_CHECKIN_DAYS_LEFT_UNTIL_RESET, /* def= */ 1)); 247 } 248 }; 249 } 250 } 251