• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 
20 import static com.android.adservices.shared.spe.JobServiceConstants.JOB_ENABLED_STATUS_DISABLED_FOR_KILL_SWITCH_ON;
21 import static com.android.adservices.shared.spe.JobServiceConstants.JOB_ENABLED_STATUS_DISABLED_FOR_USER_CONSENT_REVOKED;
22 import static com.android.adservices.shared.spe.JobServiceConstants.JOB_ENABLED_STATUS_ENABLED;
23 
24 import static com.google.android.libraries.mobiledatadownload.TaskScheduler.WIFI_CHARGING_PERIODIC_TASK;
25 
26 import android.content.Context;
27 
28 import com.android.adservices.shared.spe.framework.ExecutionResult;
29 import com.android.adservices.shared.spe.framework.ExecutionRuntimeParameters;
30 import com.android.adservices.shared.spe.framework.JobWorker;
31 import com.android.adservices.shared.spe.scheduling.BackoffPolicy;
32 import com.android.internal.annotations.VisibleForTesting;
33 import com.android.ondevicepersonalization.internal.util.LoggerFactory;
34 import com.android.ondevicepersonalization.services.Flags;
35 import com.android.ondevicepersonalization.services.FlagsFactory;
36 import com.android.ondevicepersonalization.services.OnDevicePersonalizationExecutors;
37 import com.android.ondevicepersonalization.services.data.user.UserPrivacyStatus;
38 import com.android.ondevicepersonalization.services.download.OnDevicePersonalizationDownloadProcessingJob;
39 
40 import com.google.android.libraries.mobiledatadownload.tracing.PropagatedFutures;
41 import com.google.common.util.concurrent.ListenableFuture;
42 import com.google.common.util.concurrent.ListeningExecutorService;
43 
44 /**
45  * MDD JobService. This will download MDD files in background tasks.
46  */
47 public final class MddJob implements JobWorker {
48     private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger();
49     private static final String TAG = "MddJob";
50 
51     private final String mMddTaskTag;
52     private final Injector mInjector;
53 
MddJob(String mddTaskTag)54     public MddJob(String mddTaskTag) {
55         mInjector = new Injector();
56         mMddTaskTag = mddTaskTag;
57     }
58 
59     @VisibleForTesting
MddJob(String mddTaskTag, Injector injector)60     public MddJob(String mddTaskTag, Injector injector) {
61         mInjector = injector;
62         mMddTaskTag = mddTaskTag;
63     }
64 
65     static class Injector {
getBackgroundExecutor()66         ListeningExecutorService getBackgroundExecutor() {
67             return OnDevicePersonalizationExecutors.getBackgroundExecutor();
68         }
69 
getFlags()70         Flags getFlags() {
71             return FlagsFactory.getFlags();
72         }
73     }
74 
75     @Override
getExecutionFuture( Context context, ExecutionRuntimeParameters executionRuntimeParameters)76     public ListenableFuture<ExecutionResult> getExecutionFuture(
77             Context context, ExecutionRuntimeParameters executionRuntimeParameters) {
78         ListenableFuture<Void> handleTaskFuture =
79                 PropagatedFutures.submitAsync(
80                         () -> MobileDataDownloadFactory.getMdd(context).handleTask(mMddTaskTag),
81                         mInjector.getBackgroundExecutor());
82 
83         return PropagatedFutures.transform(handleTaskFuture, unused -> {
84             if (WIFI_CHARGING_PERIODIC_TASK.equals(mMddTaskTag)) {
85                 OnDevicePersonalizationDownloadProcessingJob.schedule(context);
86             }
87             return ExecutionResult.SUCCESS;
88         }, mInjector.getBackgroundExecutor());
89     }
90 
91     @Override
92     public ListenableFuture<Void> getExecutionStopFuture(
93             Context context, ExecutionRuntimeParameters executionRuntimeParameters) {
94         // Attempt to process any data downloaded before the worker was stopped.
95         return PropagatedFutures.submit(() -> {
96             if (WIFI_CHARGING_PERIODIC_TASK.equals(mMddTaskTag)) {
97                 OnDevicePersonalizationDownloadProcessingJob.schedule(context);
98             }
99         },
100         mInjector.getBackgroundExecutor());
101     }
102 
103     @Override
104     public int getJobEnablementStatus() {
105         if (mInjector.getFlags().getGlobalKillSwitch()) {
106             sLogger.d(TAG + ": GlobalKillSwitch enabled, skip execution of MddJob.");
107             return JOB_ENABLED_STATUS_DISABLED_FOR_KILL_SWITCH_ON;
108         }
109         if (!mInjector.getFlags().getSpeOnMddJobEnabled()) {
110             sLogger.d(TAG + ": mdd is disabled; skipping and cancelling job");
111             return JOB_ENABLED_STATUS_DISABLED_FOR_KILL_SWITCH_ON;
112         }
113         if (UserPrivacyStatus.getInstance().isProtectedAudienceAndMeasurementBothDisabled()) {
114             sLogger.d(TAG + ": consent revoked; skipping, cancelling job");
115             return JOB_ENABLED_STATUS_DISABLED_FOR_USER_CONSENT_REVOKED;
116         }
117         return JOB_ENABLED_STATUS_ENABLED;
118     }
119 
120     @Override
121     public BackoffPolicy getBackoffPolicy() {
122         return new BackoffPolicy.Builder().setShouldRetryOnExecutionStop(true).build();
123     }
124 }
125