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.worker; 18 19 import android.content.Context; 20 import android.util.Pair; 21 22 import androidx.annotation.NonNull; 23 import androidx.annotation.VisibleForTesting; 24 import androidx.work.ListenableWorker; 25 import androidx.work.WorkerParameters; 26 27 import com.android.devicelockcontroller.ClientInterceptorProvider; 28 import com.android.devicelockcontroller.R; 29 import com.android.devicelockcontroller.policy.FinalizationController; 30 import com.android.devicelockcontroller.policy.PolicyObjectsProvider; 31 import com.android.devicelockcontroller.provision.grpc.DeviceFinalizeClient; 32 import com.android.devicelockcontroller.storage.GlobalParametersClient; 33 import com.android.devicelockcontroller.util.LogUtil; 34 35 import com.google.common.util.concurrent.Futures; 36 import com.google.common.util.concurrent.ListenableFuture; 37 import com.google.common.util.concurrent.ListeningExecutorService; 38 import com.google.common.util.concurrent.MoreExecutors; 39 40 import io.grpc.ClientInterceptor; 41 42 /** 43 * A worker class dedicated to report completion of the device lock program. 44 */ 45 public final class ReportDeviceLockProgramCompleteWorker extends ListenableWorker { 46 47 private static final String TAG = ReportDeviceLockProgramCompleteWorker.class.getSimpleName(); 48 49 public static final String REPORT_DEVICE_LOCK_PROGRAM_COMPLETE_WORK_NAME = 50 "report-device-lock-program-complete"; 51 private final ListenableFuture<DeviceFinalizeClient> mClient; 52 private final PolicyObjectsProvider mPolicyObjectsProvider; 53 ReportDeviceLockProgramCompleteWorker(@onNull Context context, @NonNull WorkerParameters workerParams, ListeningExecutorService executorService)54 public ReportDeviceLockProgramCompleteWorker(@NonNull Context context, 55 @NonNull WorkerParameters workerParams, ListeningExecutorService executorService) { 56 this(context, 57 workerParams, 58 null, 59 ((PolicyObjectsProvider) context.getApplicationContext()), 60 executorService); 61 } 62 63 @VisibleForTesting ReportDeviceLockProgramCompleteWorker(@onNull Context context, @NonNull WorkerParameters workerParams, DeviceFinalizeClient client, PolicyObjectsProvider policyObjectsProvider, ListeningExecutorService executorService)64 ReportDeviceLockProgramCompleteWorker(@NonNull Context context, 65 @NonNull WorkerParameters workerParams, 66 DeviceFinalizeClient client, 67 PolicyObjectsProvider policyObjectsProvider, 68 ListeningExecutorService executorService) { 69 super(context, workerParams); 70 if (client == null) { 71 final String hostName = context.getResources().getString( 72 R.string.finalize_server_host_name); 73 final int portNumber = context.getResources().getInteger( 74 R.integer.finalize_server_port_number); 75 final Pair<String, String> apikey = new Pair<>( 76 context.getResources().getString(R.string.finalize_service_api_key_name), 77 context.getResources().getString(R.string.finalize_service_api_key_value)); 78 ListenableFuture<String> registeredDeviceId = 79 GlobalParametersClient.getInstance().getRegisteredDeviceId(); 80 final ClientInterceptorProvider clientInterceptorProvider = 81 (ClientInterceptorProvider) context.getApplicationContext(); 82 final ClientInterceptor clientInterceptor = 83 clientInterceptorProvider.getClientInterceptor(); 84 mClient = Futures.transform(registeredDeviceId, 85 id -> DeviceFinalizeClient.getInstance(context, hostName, 86 portNumber, clientInterceptor, id), executorService); 87 } else { 88 mClient = Futures.immediateFuture(client); 89 } 90 mPolicyObjectsProvider = policyObjectsProvider; 91 } 92 93 @NonNull 94 @Override startWork()95 public ListenableFuture<Result> startWork() { 96 FinalizationController controller = mPolicyObjectsProvider.getFinalizationController(); 97 return Futures.transformAsync(mClient, client -> { 98 DeviceFinalizeClient.ReportDeviceProgramCompleteResponse response = 99 client.reportDeviceProgramComplete(); 100 if (response.hasRecoverableError()) { 101 LogUtil.w(TAG, "Report finalization failed w/ recoverable error " + response 102 + "\nRetrying..."); 103 return Futures.immediateFuture(Result.retry()); 104 } 105 ListenableFuture<Void> notifyFuture = 106 controller.notifyFinalizationReportResult(response); 107 return Futures.transform(notifyFuture, 108 unused -> response.isSuccessful() ? Result.success() : Result.failure(), 109 MoreExecutors.directExecutor()); 110 }, getBackgroundExecutor()); 111 } 112 } 113