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.receivers;
18 
19 import static com.android.devicelockcontroller.common.DeviceLockConstants.DeviceProvisionState.PROVISION_STATE_RETRY;
20 import static com.android.devicelockcontroller.common.DeviceLockConstants.DeviceProvisionState.PROVISION_STATE_SUCCESS;
21 import static com.android.devicelockcontroller.common.DeviceLockConstants.DeviceProvisionState.PROVISION_STATE_UNSPECIFIED;
22 import static com.android.devicelockcontroller.policy.ProvisionStateController.ProvisionEvent.PROVISION_RETRY;
23 
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 
28 import androidx.annotation.VisibleForTesting;
29 import androidx.work.WorkManager;
30 
31 import com.android.devicelockcontroller.policy.PolicyObjectsProvider;
32 import com.android.devicelockcontroller.policy.ProvisionStateController;
33 import com.android.devicelockcontroller.provision.worker.ReportDeviceProvisionStateWorker;
34 import com.android.devicelockcontroller.storage.GlobalParametersClient;
35 import com.android.devicelockcontroller.util.LogUtil;
36 
37 import com.google.common.util.concurrent.FutureCallback;
38 import com.google.common.util.concurrent.Futures;
39 import com.google.common.util.concurrent.ListenableFuture;
40 import com.google.common.util.concurrent.MoreExecutors;
41 
42 import java.util.concurrent.Executor;
43 import java.util.concurrent.Executors;
44 
45 /**
46  * A broadcast receiver to perform the next step in the provision failure flow.
47  */
48 public final class NextProvisionFailedStepReceiver extends BroadcastReceiver {
49     public static final String TAG = "NextProvisionFailedStepReceiver";
50     private final Executor mExecutor;
51 
NextProvisionFailedStepReceiver()52     public NextProvisionFailedStepReceiver() {
53         this(Executors.newSingleThreadExecutor());
54     }
55 
56     @VisibleForTesting
NextProvisionFailedStepReceiver(Executor executor)57     NextProvisionFailedStepReceiver(Executor executor) {
58         mExecutor = executor;
59     }
60 
61     @Override
onReceive(Context context, Intent intent)62     public void onReceive(Context context, Intent intent) {
63         if (!NextProvisionFailedStepReceiver.class.getName().equals(
64                 intent.getComponent().getClassName())) {
65             throw new IllegalArgumentException("Can not handle implicit intent!");
66         }
67         Context applicationContext = context.getApplicationContext();
68         ProvisionStateController provisionStateController =
69                 ((PolicyObjectsProvider) applicationContext)
70                         .getProvisionStateController();
71 
72         GlobalParametersClient globalParameters = GlobalParametersClient.getInstance();
73         ListenableFuture<Boolean> needToReportFuture = Futures.transform(
74                 globalParameters.getLastReceivedProvisionState(),
75                 provisionState -> {
76                     if (provisionState == PROVISION_STATE_RETRY) {
77                         // We cannot report the state here because we do not know the
78                         // result of the retry. It will be reported after the retry finishes no
79                         // matter whether it succeeds or fails.
80                         provisionStateController.postSetNextStateForEventRequest(
81                                 PROVISION_RETRY);
82                         return false;
83                     }
84                     return !(provisionState == PROVISION_STATE_SUCCESS
85                             || provisionState == PROVISION_STATE_UNSPECIFIED);
86                 }, mExecutor);
87         Futures.addCallback(needToReportFuture, new FutureCallback<>() {
88             @Override
89             public void onSuccess(Boolean needToReport) {
90                 if (needToReport) {
91                     ReportDeviceProvisionStateWorker.reportCurrentFailedStep(
92                             WorkManager.getInstance(context));
93                 }
94             }
95 
96             @Override
97             public void onFailure(Throwable t) {
98                 LogUtil.e(TAG, "Failed to perform next provision failed step", t);
99             }
100         }, MoreExecutors.directExecutor());
101     }
102 
103 }
104