• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.ondevicepersonalization.services;
18 
19 import static android.content.Intent.ACTION_BOOT_COMPLETED;
20 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
21 
22 import android.content.BroadcastReceiver;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.pm.PackageManager;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.odp.module.common.DeviceUtils;
30 import com.android.ondevicepersonalization.internal.util.LoggerFactory;
31 import com.android.ondevicepersonalization.services.data.errors.AggregateErrorDataReportingJob;
32 import com.android.ondevicepersonalization.services.data.user.UserDataCollectionJob;
33 import com.android.ondevicepersonalization.services.download.mdd.MobileDataDownloadFactory;
34 import com.android.ondevicepersonalization.services.maintenance.OnDevicePersonalizationMaintenanceJob;
35 
36 import com.google.common.util.concurrent.FutureCallback;
37 import com.google.common.util.concurrent.Futures;
38 import com.google.common.util.concurrent.ListenableFuture;
39 import com.google.common.util.concurrent.ListeningExecutorService;
40 
41 import java.util.List;
42 import java.util.concurrent.Executor;
43 
44 /** BroadcastReceiver used to schedule OnDevicePersonalization jobs/workers. */
45 public class OnDevicePersonalizationBroadcastReceiver extends BroadcastReceiver {
46     private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger();
47     private static final String TAG = "OnDevicePersonalizationBroadcastReceiver";
48     private final ListeningExecutorService mExecutor;
49 
OnDevicePersonalizationBroadcastReceiver()50     public OnDevicePersonalizationBroadcastReceiver() {
51         this(OnDevicePersonalizationExecutors.getLightweightExecutor());
52     }
53 
54     @VisibleForTesting
OnDevicePersonalizationBroadcastReceiver(ListeningExecutorService executor)55     OnDevicePersonalizationBroadcastReceiver(ListeningExecutorService executor) {
56         this.mExecutor = executor;
57     }
58 
59     /** Enable the OnDevicePersonalizationBroadcastReceiver */
enableReceiver(Context context)60     public static boolean enableReceiver(Context context) {
61         try {
62             context.getPackageManager()
63                     .setComponentEnabledSetting(
64                             new ComponentName(
65                                     context, OnDevicePersonalizationBroadcastReceiver.class),
66                             COMPONENT_ENABLED_STATE_ENABLED,
67                             PackageManager.DONT_KILL_APP);
68         } catch (IllegalArgumentException e) {
69             sLogger.e(TAG + ": enableService failed for " + context.getPackageName(), e);
70             return false;
71         }
72         return true;
73     }
74 
75     /**
76      * Called when the {@link ACTION_BOOT_COMPLETED} broadcast is received. OnDevicePersonalization
77      * jobs will be started here.
78      */
onReceive(Context context, Intent intent)79     public void onReceive(Context context, Intent intent) {
80         if (FlagsFactory.getFlags().getGlobalKillSwitch()) {
81             sLogger.d(TAG + ": GlobalKillSwitch on, skipped broadcast.");
82             return;
83         }
84 
85         if (!DeviceUtils.isOdpSupported(context)) {
86             sLogger.d(TAG + ": Unsupported device, skipped broadcast.");
87             return;
88         }
89 
90         sLogger.d(TAG + ": onReceive() with intent + " + intent.getAction());
91 
92         if (!ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
93             sLogger.d(TAG + ": Received unexpected intent " + intent.getAction());
94             return;
95         }
96         final PendingResult pendingResult = goAsync();
97         // Schedule maintenance and MDD tasks to download scripts periodically etc.
98         Futures.addCallback(
99                 restoreOdpJobs(context, mExecutor),
100                 new FutureCallback<List<Void>>() {
101                     @Override
102                     public void onSuccess(List<Void> result) {
103                         sLogger.d(TAG + ": handled job scheduling tasks successfully");
104                         pendingResult.finish();
105                     }
106 
107                     @Override
108                     public void onFailure(Throwable t) {
109                         sLogger.e(t, TAG + ": failed to handle all job scheduling tasks.");
110                         pendingResult.finish();
111                     }
112                 },
113                 mExecutor);
114     }
115 
116     /** Restores periodic jobs scheduling. */
restoreOdpJobs(Context context, Executor executor)117     static ListenableFuture<List<Void>> restoreOdpJobs(Context context, Executor executor) {
118         if (FlagsFactory.getFlags().getGlobalKillSwitch() || !DeviceUtils.isOdpSupported(context)) {
119             sLogger.d(TAG + ": ODP disabled or unsupported device");
120             return null;
121         }
122 
123         ListenableFuture<Void> maintenanceFuture =
124                 Futures.submit(
125                         () -> {
126                             // Schedule maintenance task
127                             OnDevicePersonalizationMaintenanceJob.schedule(context);
128                             // Schedule user data collection task
129                             UserDataCollectionJob.schedule(context);
130                             // Schedule regular ODP aggregated error reporting task if the flag
131                             // is enabled etc.
132                             AggregateErrorDataReportingJob.schedule(context);
133                         },
134                         executor);
135 
136         // Schedule MDD to download scripts periodically.
137         ListenableFuture<Void> mddFuture =
138                 MobileDataDownloadFactory.getMdd(context).schedulePeriodicBackgroundTasks();
139         return Futures.successfulAsList(maintenanceFuture, mddFuture);
140     }
141 }
142