• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.topics;
18 
19 import static com.android.adservices.service.Flags.TOPICS_EPOCH_JOB_FLEX_MS;
20 import static com.android.adservices.service.Flags.TOPICS_EPOCH_JOB_PERIOD_MS;
21 import static com.android.adservices.shared.proto.JobPolicy.BatteryType.BATTERY_TYPE_REQUIRE_CHARGING;
22 import static com.android.adservices.shared.proto.JobPolicy.BatteryType.BATTERY_TYPE_REQUIRE_NOT_LOW;
23 import static com.android.adservices.shared.proto.JobPolicy.BatteryType.BATTERY_TYPE_UNKNOWN;
24 import static com.android.adservices.shared.spe.JobServiceConstants.JOB_ENABLED_STATUS_DISABLED_FOR_KILL_SWITCH_ON;
25 import static com.android.adservices.shared.spe.JobServiceConstants.JOB_ENABLED_STATUS_ENABLED;
26 import static com.android.adservices.shared.spe.framework.ExecutionResult.SUCCESS;
27 import static com.android.adservices.spe.AdServicesJobInfo.TOPICS_EPOCH_JOB;
28 
29 import android.content.Context;
30 import android.os.Build;
31 
32 import androidx.annotation.RequiresApi;
33 
34 import com.android.adservices.LoggerFactory;
35 import com.android.adservices.concurrency.AdServicesExecutors;
36 import com.android.adservices.service.FlagsFactory;
37 import com.android.adservices.shared.proto.JobPolicy;
38 import com.android.adservices.shared.spe.framework.ExecutionResult;
39 import com.android.adservices.shared.spe.framework.ExecutionRuntimeParameters;
40 import com.android.adservices.shared.spe.framework.JobWorker;
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 /** Epoch computation job. This will be run approximately once per epoch to compute Topics. */
50 @RequiresApi(Build.VERSION_CODES.S)
51 public final class EpochJob implements JobWorker {
52     @Override
getExecutionFuture( Context context, ExecutionRuntimeParameters executionRuntimeParameters)53     public ListenableFuture<ExecutionResult> getExecutionFuture(
54             Context context, ExecutionRuntimeParameters executionRuntimeParameters) {
55         return Futures.submit(
56                 () -> {
57                     TopicsWorker.getInstance().computeEpoch();
58                     return SUCCESS;
59                 },
60                 AdServicesExecutors.getBackgroundExecutor());
61     }
62 
63     @Override
getJobEnablementStatus()64     public int getJobEnablementStatus() {
65         if (FlagsFactory.getFlags().getTopicsKillSwitch()) {
66             LoggerFactory.getTopicsLogger()
67                     .e("Topics API is disabled, skipping and cancelling EpochJobService");
68             return JOB_ENABLED_STATUS_DISABLED_FOR_KILL_SWITCH_ON;
69         }
70 
71         return JOB_ENABLED_STATUS_ENABLED;
72     }
73 
74     /** Schedules the {@link EpochJob}. */
schedule()75     public static void schedule() {
76         // If SPE is not enabled, force to schedule the job with the old JobService.
77         if (!FlagsFactory.getFlags().getSpeOnEpochJobEnabled()) {
78             LoggerFactory.getTopicsLogger()
79                     .d("SPE is not enabled. Schedule the job with EpochJobService.");
80             int resultCode = EpochJobService.scheduleIfNeeded(/* forceSchedule= */ false);
81 
82             AdServicesJobServiceFactory.getInstance()
83                     .getJobSchedulingLogger()
84                     .recordOnSchedulingLegacy(TOPICS_EPOCH_JOB.getJobId(), resultCode);
85             return;
86         }
87 
88         AdServicesJobScheduler.getInstance().schedule(createDefaultJobSpec());
89     }
90 
91     @VisibleForTesting
createDefaultJobSpec()92     static JobSpec createDefaultJobSpec() {
93         JobPolicy.BatteryType batteryType = BATTERY_TYPE_UNKNOWN;
94         if (FlagsFactory.getFlags().getTopicsEpochJobBatteryNotLowInsteadOfCharging()) {
95             batteryType = BATTERY_TYPE_REQUIRE_NOT_LOW;
96         } else {
97             batteryType = BATTERY_TYPE_REQUIRE_CHARGING;
98         }
99         JobPolicy jobPolicy =
100                 JobPolicy.newBuilder()
101                         .setJobId(TOPICS_EPOCH_JOB.getJobId())
102                         .setBatteryType(batteryType)
103                         .setIsPersisted(true)
104                         .setPeriodicJobParams(
105                                 JobPolicy.PeriodicJobParams.newBuilder()
106                                         .setPeriodicIntervalMs(TOPICS_EPOCH_JOB_PERIOD_MS)
107                                         .setFlexInternalMs(TOPICS_EPOCH_JOB_FLEX_MS)
108                                         .build())
109                         .build();
110         LoggerFactory.getTopicsLogger().d(
111                 "SPE is enabled. Battery type of EpochJob: " + jobPolicy.getBatteryType());
112 
113         return new JobSpec.Builder(jobPolicy).build();
114     }
115 }
116