1 /* 2 * Copyright (C) 2024 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.adservices.spe; 18 19 import static com.android.adservices.shared.spe.JobServiceConstants.JOB_ENABLED_STATUS_DISABLED_FOR_BACK_COMPAT_OTA; 20 import static com.android.adservices.spe.AdServicesJobInfo.FLEDGE_BACKGROUND_FETCH_JOB; 21 import static com.android.adservices.spe.AdServicesJobInfo.MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB; 22 import static com.android.adservices.spe.AdServicesJobInfo.MDD_CHARGING_PERIODIC_TASK_JOB; 23 import static com.android.adservices.spe.AdServicesJobInfo.MDD_MAINTENANCE_PERIODIC_TASK_JOB; 24 import static com.android.adservices.spe.AdServicesJobInfo.MDD_WIFI_CHARGING_PERIODIC_TASK_JOB; 25 import static com.android.adservices.spe.AdServicesJobInfo.MEASUREMENT_ASYNC_REGISTRATION_FALLBACK_JOB; 26 import static com.android.adservices.spe.AdServicesJobInfo.TOPICS_EPOCH_JOB; 27 28 import android.app.job.JobParameters; 29 import android.os.Build; 30 31 import androidx.annotation.RequiresApi; 32 33 import com.android.adservices.LogUtil; 34 import com.android.adservices.service.Flags; 35 import com.android.adservices.service.FlagsFactory; 36 import com.android.adservices.service.common.compat.ServiceCompatUtils; 37 import com.android.adservices.shared.spe.framework.AbstractJobService; 38 import com.android.adservices.shared.spe.framework.JobServiceFactory; 39 import com.android.internal.annotations.VisibleForTesting; 40 41 /** The Adservices' implementation of {@link AbstractJobService}. */ 42 @RequiresApi(Build.VERSION_CODES.S) 43 public final class AdServicesJobService extends AbstractJobService { 44 @Override getJobServiceFactory()45 protected JobServiceFactory getJobServiceFactory() { 46 return AdServicesJobServiceFactory.getInstance(); 47 } 48 49 /** 50 * Overrides {@link AbstractJobService#onStartJob(JobParameters)} to add the logic to cancel 51 * Android S- job in T+ build. 52 */ 53 @Override onStartJob(JobParameters params)54 public boolean onStartJob(JobParameters params) { 55 int jobId = params.getJobId(); 56 if (ServiceCompatUtils.shouldDisableExtServicesJobOnTPlus(this)) { 57 getJobServiceFactory().getJobServiceLogger().recordOnStartJob(jobId); 58 59 LogUtil.d("Disabling job %d because it's running in ExtServices on T+", jobId); 60 skipAndCancelBackgroundJob(params, JOB_ENABLED_STATUS_DISABLED_FOR_BACK_COMPAT_OTA); 61 return false; 62 } 63 64 // Switch to the legacy job scheduling if SPE is disabled. Since job ID remains the same, 65 // the scheduled job will be cancelled and rescheduled with the legacy method. 66 // 67 // And after the job is rescheduled, it will execute once instantly so don't log execution 68 // stats here. 69 if (shouldRescheduleWithLegacyMethod(jobId)) { 70 LogUtil.d( 71 "SPE is disabled. Reschedule SPE job instance of jobId=%d with its legacy" 72 + " JobService scheduling method.", 73 jobId); 74 AdServicesJobServiceFactory factory = 75 (AdServicesJobServiceFactory) getJobServiceFactory(); 76 factory.rescheduleJobWithLegacyMethod(jobId); 77 return false; 78 } 79 80 return super.onStartJob(params); 81 } 82 83 // Determine whether we should cancel and reschedule current job with the legacy JobService 84 // class. It could happen when SPE has a production issue. 85 // 86 // First batch pilot jobs: MddJobService, job ID = 11, 12, 13, 14. 87 // Second batch pilot jobs: 88 // - EpochJobService, job ID = 2. 89 // - BackgroundFetchJobService, job ID = 9. 90 // - AsyncRegistrationFallbackJobService, job ID = 19. 91 @VisibleForTesting shouldRescheduleWithLegacyMethod(int jobId)92 boolean shouldRescheduleWithLegacyMethod(int jobId) { 93 Flags flags = FlagsFactory.getFlags(); 94 95 if (isFirstBatchPilotJobDisabledForSpe(jobId, flags)) { 96 return true; 97 } 98 99 if (isSecondBatchPilotJobDisabledForSpe(jobId, flags)) { 100 return true; 101 } 102 103 return false; 104 } 105 isFirstBatchPilotJobDisabledForSpe(int jobId, Flags flags)106 private boolean isFirstBatchPilotJobDisabledForSpe(int jobId, Flags flags) { 107 return (jobId == MDD_WIFI_CHARGING_PERIODIC_TASK_JOB.getJobId() 108 || jobId == MDD_MAINTENANCE_PERIODIC_TASK_JOB.getJobId() 109 || jobId == MDD_CHARGING_PERIODIC_TASK_JOB.getJobId() 110 || jobId == MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB.getJobId()) 111 && !flags.getSpeOnPilotJobsEnabled(); 112 } 113 isSecondBatchPilotJobDisabledForSpe(int jobId, Flags flags)114 private boolean isSecondBatchPilotJobDisabledForSpe(int jobId, Flags flags) { 115 if ((jobId == TOPICS_EPOCH_JOB.getJobId() && !flags.getSpeOnEpochJobEnabled()) 116 || (jobId == FLEDGE_BACKGROUND_FETCH_JOB.getJobId() 117 && !flags.getSpeOnBackgroundFetchJobEnabled()) 118 || (jobId == MEASUREMENT_ASYNC_REGISTRATION_FALLBACK_JOB.getJobId() 119 && !flags.getSpeOnAsyncRegistrationFallbackJobEnabled())) { 120 return true; 121 } 122 return false; 123 } 124 } 125