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.provision.grpc; 18 19 import android.content.Context; 20 import android.content.SharedPreferences; 21 import android.os.Build; 22 import android.os.SystemProperties; 23 import android.os.UserHandle; 24 import android.util.Pair; 25 26 import androidx.annotation.NonNull; 27 import androidx.annotation.Nullable; 28 import androidx.annotation.WorkerThread; 29 30 import com.android.devicelockcontroller.provision.grpc.impl.DeviceFinalizeClientImpl; 31 import com.android.devicelockcontroller.util.LogUtil; 32 33 import io.grpc.ClientInterceptor; 34 import io.grpc.Status; 35 36 /** 37 * An abstract class that's intended for implementation of class that manages communication with 38 * Device finalize service. 39 */ 40 public abstract class DeviceFinalizeClient { 41 public static final String TAG = "DeviceFinalizeClient"; 42 private static final String FILENAME = "debug-finalize-preferences"; 43 private static final String HOST_NAME_OVERRIDE = "host.name.override"; 44 public static final String DEVICE_FINALIZE_CLIENT_DEBUG_CLASS_NAME = 45 "com.android.devicelockcontroller.debug.DeviceFinalizeClientDebug"; 46 private static volatile DeviceFinalizeClient sClient; 47 protected static String sRegisteredId = ""; 48 protected static String sHostName = ""; 49 protected static int sPortNumber = 0; 50 protected static Pair<String, String> sApiKey = new Pair<>("", ""); 51 private static volatile boolean sUseDebugClient; 52 @Nullable 53 private static volatile SharedPreferences sSharedPreferences; 54 55 @Nullable getSharedPreferences( @ullable Context context)56 private static synchronized SharedPreferences getSharedPreferences( 57 @Nullable Context context) { 58 if (sSharedPreferences == null && context != null) { 59 sSharedPreferences = 60 context.createContextAsUser(UserHandle.SYSTEM, /* flags= */ 61 0).createDeviceProtectedStorageContext().getSharedPreferences(FILENAME, 62 Context.MODE_PRIVATE); 63 } 64 return sSharedPreferences; 65 } 66 67 /** 68 * Override the host name so that the client always connects to it instead 69 */ setHostNameOverride(Context context, String override)70 public static void setHostNameOverride(Context context, String override) { 71 getSharedPreferences(context).edit().putString(HOST_NAME_OVERRIDE, override).apply(); 72 } 73 74 /** 75 * Get an instance of {@link DeviceFinalizeClient} object. 76 * Note that, the arguments will be ignored after first initialization. 77 */ getInstance( Context context, String hostName, int portNumber, ClientInterceptor clientInterceptor, String registeredId)78 public static DeviceFinalizeClient getInstance( 79 Context context, 80 String hostName, 81 int portNumber, 82 ClientInterceptor clientInterceptor, 83 String registeredId) { 84 boolean useDebugClient = false; 85 String hostNameOverride = ""; 86 if (Build.isDebuggable()) { 87 useDebugClient = 88 SystemProperties.getBoolean("debug.devicelock.finalize", /* def= */ false); 89 hostNameOverride = getSharedPreferences(context).getString( 90 HOST_NAME_OVERRIDE, /* def= */ ""); 91 if (!hostNameOverride.isEmpty()) { 92 hostName = hostNameOverride; 93 } 94 } 95 if (sClient == null || sUseDebugClient != useDebugClient) { 96 synchronized (DeviceFinalizeClient.class) { 97 // In case the initialization is already done by other thread use existing 98 // instance. 99 if (sClient != null && sUseDebugClient == useDebugClient) { 100 return sClient; 101 } 102 sHostName = hostName; 103 sPortNumber = portNumber; 104 sRegisteredId = registeredId; 105 sUseDebugClient = useDebugClient; 106 try { 107 if (Build.isDebuggable() && sUseDebugClient) { 108 final String className = DEVICE_FINALIZE_CLIENT_DEBUG_CLASS_NAME; 109 LogUtil.d(TAG, "Creating instance for " + className); 110 Class<?> clazz = Class.forName(className); 111 sClient = 112 (DeviceFinalizeClient) clazz.getDeclaredConstructor().newInstance(); 113 } else { 114 sClient = new DeviceFinalizeClientImpl(clientInterceptor); 115 } 116 117 } catch (Exception e) { 118 throw new RuntimeException("Failed to get DeviceFinalizeClient instance", e); 119 } 120 } 121 } 122 return sClient; 123 } 124 125 /** 126 * Reports that a device completed a Device Lock program. 127 */ 128 @WorkerThread reportDeviceProgramComplete()129 public abstract ReportDeviceProgramCompleteResponse reportDeviceProgramComplete(); 130 131 /** 132 * Class that used to indicate the successfulness / failure status of the response. 133 */ 134 public static final class ReportDeviceProgramCompleteResponse extends 135 GrpcResponse { ReportDeviceProgramCompleteResponse()136 public ReportDeviceProgramCompleteResponse() { 137 super(); 138 } 139 ReportDeviceProgramCompleteResponse(@onNull Status status)140 public ReportDeviceProgramCompleteResponse(@NonNull Status status) { 141 super(status); 142 } 143 } 144 } 145