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.download.mdd; 18 19 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_BACKGROUND_JOBS_EXECUTION_REPORTED__EXECUTION_RESULT_CODE__SKIP_FOR_KILL_SWITCH_ON; 20 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_BACKGROUND_JOBS_EXECUTION_REPORTED__EXECUTION_RESULT_CODE__SKIP_FOR_PERSONALIZATION_NOT_ENABLED; 21 import static com.android.ondevicepersonalization.services.download.mdd.MddTaskScheduler.MDD_TASK_TAG_KEY; 22 23 import static com.google.android.libraries.mobiledatadownload.TaskScheduler.WIFI_CHARGING_PERIODIC_TASK; 24 25 import android.app.job.JobParameters; 26 import android.app.job.JobScheduler; 27 import android.app.job.JobService; 28 import android.content.Context; 29 import android.os.PersistableBundle; 30 31 import com.android.ondevicepersonalization.internal.util.LoggerFactory; 32 import com.android.ondevicepersonalization.services.FlagsFactory; 33 import com.android.ondevicepersonalization.services.OnDevicePersonalizationExecutors; 34 import com.android.ondevicepersonalization.services.data.user.UserPrivacyStatus; 35 import com.android.ondevicepersonalization.services.download.OnDevicePersonalizationDownloadProcessingJobService; 36 import com.android.ondevicepersonalization.services.statsd.joblogging.OdpJobServiceLogger; 37 38 import com.google.android.libraries.mobiledatadownload.tracing.PropagatedFutures; 39 import com.google.common.util.concurrent.FutureCallback; 40 import com.google.common.util.concurrent.Futures; 41 import com.google.common.util.concurrent.ListenableFuture; 42 43 /** 44 * MDD JobService. This will download MDD files in background tasks. 45 */ 46 public class MddJobService extends JobService { 47 private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger(); 48 private static final String TAG = "MddJobService"; 49 50 private String mMddTaskTag; 51 52 @Override onStartJob(JobParameters params)53 public boolean onStartJob(JobParameters params) { 54 int jobId = getMddTaskJobId(params); 55 sLogger.d(TAG + ": onStartJob()"); 56 OdpJobServiceLogger.getInstance(this).recordOnStartJob(jobId); 57 if (FlagsFactory.getFlags().getGlobalKillSwitch()) { 58 sLogger.d(TAG + ": GlobalKillSwitch enabled, finishing job."); 59 return cancelAndFinishJob(params, 60 AD_SERVICES_BACKGROUND_JOBS_EXECUTION_REPORTED__EXECUTION_RESULT_CODE__SKIP_FOR_KILL_SWITCH_ON); 61 } 62 63 if (!UserPrivacyStatus.getInstance().isMeasurementEnabled() 64 && !UserPrivacyStatus.getInstance().isProtectedAudienceEnabled()) { 65 sLogger.d(TAG + ": User control is not given for all ODP services."); 66 OdpJobServiceLogger.getInstance(this).recordJobSkipped(jobId, 67 AD_SERVICES_BACKGROUND_JOBS_EXECUTION_REPORTED__EXECUTION_RESULT_CODE__SKIP_FOR_PERSONALIZATION_NOT_ENABLED); 68 jobFinished(params, false); 69 return true; 70 } 71 72 mMddTaskTag = getMddTaskTag(params); 73 74 ListenableFuture<Void> handleTaskFuture = 75 PropagatedFutures.submitAsync( 76 () -> MobileDataDownloadFactory.getMdd(this).handleTask(mMddTaskTag), 77 OnDevicePersonalizationExecutors.getBackgroundExecutor()); 78 79 Context context = this; 80 Futures.addCallback( 81 handleTaskFuture, 82 new FutureCallback<Void>() { 83 @Override 84 public void onSuccess(Void result) { 85 sLogger.d(TAG + ": MddJobService.MddHandleTask succeeded!"); 86 // Attempt to process any data downloaded 87 if (WIFI_CHARGING_PERIODIC_TASK.equals(mMddTaskTag)) { 88 OnDevicePersonalizationDownloadProcessingJobService.schedule(context); 89 } 90 boolean wantsReschedule = false; 91 OdpJobServiceLogger.getInstance(MddJobService.this) 92 .recordJobFinished(jobId, 93 /* isSuccessful= */ true, 94 wantsReschedule); 95 // Tell the JobScheduler that the job has completed and does not needs to be 96 // rescheduled. 97 jobFinished(params, wantsReschedule); 98 } 99 100 @Override 101 public void onFailure(Throwable t) { 102 sLogger.e(TAG + ": Failed to handle JobService: " + jobId, t); 103 boolean wantsReschedule = false; 104 OdpJobServiceLogger.getInstance(MddJobService.this) 105 .recordJobFinished(jobId, 106 /* isSuccessful= */ false, 107 wantsReschedule); 108 // When failure, also tell the JobScheduler that the job has completed and 109 // does not need to be rescheduled. 110 jobFinished(params, wantsReschedule); 111 } 112 }, 113 OnDevicePersonalizationExecutors.getBackgroundExecutor()); 114 115 return true; 116 } 117 118 @Override onStopJob(JobParameters params)119 public boolean onStopJob(JobParameters params) { 120 // Attempt to process any data downloaded before the worker was stopped. 121 if (WIFI_CHARGING_PERIODIC_TASK.equals(mMddTaskTag)) { 122 OnDevicePersonalizationDownloadProcessingJobService.schedule(this); 123 } 124 // Reschedule the job since it ended before finishing 125 boolean wantsReschedule = true; 126 OdpJobServiceLogger.getInstance(this) 127 .recordOnStopJob(params, getMddTaskJobId(params), wantsReschedule); 128 return wantsReschedule; 129 } 130 cancelAndFinishJob(final JobParameters params, int skipReason)131 private boolean cancelAndFinishJob(final JobParameters params, int skipReason) { 132 JobScheduler jobScheduler = this.getSystemService(JobScheduler.class); 133 int jobId = getMddTaskJobId(params); 134 if (jobScheduler != null) { 135 jobScheduler.cancel(jobId); 136 } 137 OdpJobServiceLogger.getInstance(this).recordJobSkipped(jobId, skipReason); 138 jobFinished(params, /* wantsReschedule = */ false); 139 return true; 140 } 141 getMddTaskJobId(final JobParameters params)142 private int getMddTaskJobId(final JobParameters params) { 143 mMddTaskTag = getMddTaskTag(params); 144 return MddTaskScheduler.getMddTaskJobId(mMddTaskTag); 145 } 146 getMddTaskTag(final JobParameters params)147 private String getMddTaskTag(final JobParameters params) { 148 // Get the MddTaskTag from input. 149 PersistableBundle extras = params.getExtras(); 150 if (null == extras) { 151 sLogger.e(TAG + ": can't find MDD task tag"); 152 throw new IllegalArgumentException("Can't find MDD Tasks Tag!"); 153 } 154 return extras.getString(MDD_TASK_TAG_KEY); 155 } 156 } 157