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.service.measurement.registration; 18 19 import static com.android.adservices.service.Flags.ASYNC_REGISTRATION_JOB_QUEUE_INTERVAL_MS; 20 import static com.android.adservices.service.measurement.util.JobLockHolder.Type.ASYNC_REGISTRATION_PROCESSING; 21 import static com.android.adservices.shared.proto.JobPolicy.BatteryType.BATTERY_TYPE_REQUIRE_NOT_LOW; 22 import static com.android.adservices.shared.proto.JobPolicy.NetworkType.NETWORK_TYPE_ANY; 23 import static com.android.adservices.shared.spe.JobServiceConstants.JOB_ENABLED_STATUS_DISABLED_FOR_KILL_SWITCH_ON; 24 import static com.android.adservices.shared.spe.JobServiceConstants.JOB_ENABLED_STATUS_ENABLED; 25 import static com.android.adservices.shared.spe.framework.ExecutionResult.SUCCESS; 26 import static com.android.adservices.spe.AdServicesJobInfo.MEASUREMENT_ASYNC_REGISTRATION_FALLBACK_JOB; 27 28 import android.annotation.RequiresApi; 29 import android.content.Context; 30 import android.os.Build; 31 32 import com.android.adservices.LoggerFactory; 33 import com.android.adservices.concurrency.AdServicesExecutors; 34 import com.android.adservices.service.FlagsFactory; 35 import com.android.adservices.service.measurement.util.JobLockHolder; 36 import com.android.adservices.shared.proto.JobPolicy; 37 import com.android.adservices.shared.spe.framework.ExecutionResult; 38 import com.android.adservices.shared.spe.framework.ExecutionRuntimeParameters; 39 import com.android.adservices.shared.spe.framework.JobWorker; 40 import com.android.adservices.shared.spe.scheduling.BackoffPolicy; 41 import com.android.adservices.shared.spe.scheduling.JobSpec; 42 import com.android.adservices.spe.AdServicesJobScheduler; 43 import com.android.adservices.spe.AdServicesJobServiceFactory; 44 import com.android.internal.annotations.VisibleForTesting; 45 46 import com.google.common.util.concurrent.Futures; 47 import com.google.common.util.concurrent.ListenableFuture; 48 49 /** Fallback Job Service for servicing queued registration requests. */ 50 // TODO(b/328287543): Since Rb has released to R so functionally this class should support R. Due to 51 // Legacy issue, class such as BackgroundJobsManager and MddJobService which have to support R also 52 // have this annotation. It won't have production impact but is needed to bypass the build error. 53 @RequiresApi(Build.VERSION_CODES.S) 54 public final class AsyncRegistrationFallbackJob implements JobWorker { 55 private static final LoggerFactory.Logger sLogger = LoggerFactory.getMeasurementLogger(); 56 57 @Override getExecutionFuture( Context context, ExecutionRuntimeParameters executionRuntimeParameters)58 public ListenableFuture<ExecutionResult> getExecutionFuture( 59 Context context, ExecutionRuntimeParameters executionRuntimeParameters) { 60 return Futures.submit( 61 () -> { 62 processAsyncRecords(context); 63 return SUCCESS; 64 }, 65 AdServicesExecutors.getBlockingExecutor()); 66 } 67 68 @Override getJobEnablementStatus()69 public int getJobEnablementStatus() { 70 if (FlagsFactory.getFlags().getAsyncRegistrationFallbackJobKillSwitch()) { 71 return JOB_ENABLED_STATUS_DISABLED_FOR_KILL_SWITCH_ON; 72 } 73 74 return JOB_ENABLED_STATUS_ENABLED; 75 } 76 77 /** Schedules the {@link AsyncRegistrationFallbackJob}. */ schedule()78 public static void schedule() { 79 // If SPE is not enabled, force to schedule the job with the old JobService. 80 if (!FlagsFactory.getFlags().getSpeOnAsyncRegistrationFallbackJobEnabled()) { 81 sLogger.d( 82 "SPE is not enabled. Schedule the job with" 83 + " AsyncRegistrationFallbackJobService."); 84 int resultCode = 85 AsyncRegistrationFallbackJobService.scheduleIfNeeded( 86 /* forceSchedule= */ false); 87 88 AdServicesJobServiceFactory.getInstance() 89 .getJobSchedulingLogger() 90 .recordOnSchedulingLegacy( 91 MEASUREMENT_ASYNC_REGISTRATION_FALLBACK_JOB.getJobId(), resultCode); 92 return; 93 } 94 95 AdServicesJobScheduler.getInstance().schedule(createDefaultJobSpec()); 96 } 97 98 @VisibleForTesting createDefaultJobSpec()99 static JobSpec createDefaultJobSpec() { 100 JobPolicy jobPolicy = 101 JobPolicy.newBuilder() 102 .setJobId(MEASUREMENT_ASYNC_REGISTRATION_FALLBACK_JOB.getJobId()) 103 .setBatteryType(BATTERY_TYPE_REQUIRE_NOT_LOW) 104 .setPeriodicJobParams( 105 JobPolicy.PeriodicJobParams.newBuilder() 106 .setPeriodicIntervalMs( 107 ASYNC_REGISTRATION_JOB_QUEUE_INTERVAL_MS) 108 .build()) 109 .setNetworkType(NETWORK_TYPE_ANY) 110 .setIsPersisted(true) 111 .build(); 112 113 BackoffPolicy backoffPolicy = 114 new BackoffPolicy.Builder().setShouldRetryOnExecutionStop(true).build(); 115 116 return new JobSpec.Builder(jobPolicy).setBackoffPolicy(backoffPolicy).build(); 117 } 118 119 @VisibleForTesting processAsyncRecords(Context context)120 void processAsyncRecords(Context context) { 121 final JobLockHolder lock = JobLockHolder.getInstance(ASYNC_REGISTRATION_PROCESSING); 122 if (lock.tryLock()) { 123 try { 124 AsyncRegistrationQueueRunner.getInstance(context).runAsyncRegistrationQueueWorker(); 125 return; 126 } finally { 127 lock.unlock(); 128 } 129 } 130 131 sLogger.d("AsyncRegistrationFallbackJob did not acquire the lock"); 132 } 133 } 134