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 package com.android.adservices.topics;
17 
18 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_CLASS__TARGETING;
19 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__TOPICS_API_DISABLED;
20 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__TOPICS;
21 
22 import android.app.Service;
23 import android.content.Intent;
24 import android.os.Build;
25 import android.os.IBinder;
26 
27 import androidx.annotation.RequiresApi;
28 
29 import com.android.adservices.LoggerFactory;
30 import com.android.adservices.data.enrollment.EnrollmentDao;
31 import com.android.adservices.download.MddJob;
32 import com.android.adservices.download.MobileDataDownloadFactory;
33 import com.android.adservices.errorlogging.ErrorLogUtil;
34 import com.android.adservices.service.FlagsFactory;
35 import com.android.adservices.service.MaintenanceJobService;
36 import com.android.adservices.service.common.AppImportanceFilter;
37 import com.android.adservices.service.common.PackageChangedReceiver;
38 import com.android.adservices.service.common.Throttler;
39 import com.android.adservices.service.common.compat.BuildCompatUtils;
40 import com.android.adservices.service.consent.AdServicesApiType;
41 import com.android.adservices.service.consent.ConsentManager;
42 import com.android.adservices.service.encryptionkey.EncryptionKeyJobService;
43 import com.android.adservices.service.stats.AdServicesLoggerImpl;
44 import com.android.adservices.service.topics.CacheManager;
45 import com.android.adservices.service.topics.EpochJob;
46 import com.android.adservices.service.topics.EpochManager;
47 import com.android.adservices.service.topics.TopicsServiceImpl;
48 import com.android.adservices.service.topics.TopicsWorker;
49 import com.android.adservices.shared.util.Clock;
50 
51 import java.io.FileDescriptor;
52 import java.io.PrintWriter;
53 import java.util.Objects;
54 
55 /** Topics Service */
56 @RequiresApi(Build.VERSION_CODES.S)
57 public class TopicsService extends Service {
58     private static final LoggerFactory.Logger sLogger = LoggerFactory.getTopicsLogger();
59 
60     /** The binder service. This field must only be accessed on the main thread. */
61     private TopicsServiceImpl mTopicsService;
62 
63     @Override
onCreate()64     public void onCreate() {
65         super.onCreate();
66 
67         if (FlagsFactory.getFlags().getTopicsKillSwitch()) {
68             sLogger.e("onCreate(): Topics API is disabled");
69             ErrorLogUtil.e(
70                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__TOPICS_API_DISABLED,
71                     AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__TOPICS);
72             return;
73         }
74 
75         AppImportanceFilter appImportanceFilter =
76                 AppImportanceFilter.create(
77                         this,
78                         AD_SERVICES_API_CALLED__API_CLASS__TARGETING,
79                         () -> FlagsFactory.getFlags().getForegroundStatuslLevelForValidation());
80 
81         if (mTopicsService == null) {
82             mTopicsService =
83                     new TopicsServiceImpl(
84                             this,
85                             TopicsWorker.getInstance(),
86                             ConsentManager.getInstance(),
87                             AdServicesLoggerImpl.getInstance(),
88                             Clock.getInstance(),
89                             FlagsFactory.getFlags(),
90                             Throttler.getInstance(FlagsFactory.getFlags()),
91                             EnrollmentDao.getInstance(),
92                             appImportanceFilter);
93             mTopicsService.init();
94         }
95         if (hasUserConsent()) {
96             PackageChangedReceiver.enableReceiver(this, FlagsFactory.getFlags());
97             schedulePeriodicJobs();
98         }
99     }
100 
schedulePeriodicJobs()101     private void schedulePeriodicJobs() {
102         MaintenanceJobService.scheduleIfNeeded(this, /* forceSchedule */ false);
103         EncryptionKeyJobService.scheduleIfNeeded(this, /* forceSchedule */ false);
104         MddJob.scheduleAllMddJobs();
105         EpochJob.schedule();
106     }
107 
hasUserConsent()108     private boolean hasUserConsent() {
109         return ConsentManager.getInstance().getConsent(AdServicesApiType.TOPICS).isGiven();
110     }
111 
112     @Override
onBind(Intent intent)113     public IBinder onBind(Intent intent) {
114         if (FlagsFactory.getFlags().getTopicsKillSwitch()) {
115             sLogger.e("onBind(): Topics API is disabled, return nullBinding.");
116             ErrorLogUtil.e(
117                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__TOPICS_API_DISABLED,
118                     AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__TOPICS);
119             // Return null so that clients can not bind to the service.
120             return null;
121         }
122         return Objects.requireNonNull(mTopicsService);
123     }
124 
125     // TODO(b/246316128): Add dump() in Consent Manager.
126     @Override
dump(FileDescriptor fd, PrintWriter writer, String[] args)127     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
128         super.dump(fd, writer, args);
129         FlagsFactory.getFlags().dump(writer, args);
130         if (BuildCompatUtils.isDebuggable()) {
131             writer.println("Build is Debuggable, dumping information for TopicsService");
132             EpochManager.getInstance().dump(writer, args);
133             CacheManager.getInstance().dump(writer, args);
134             MobileDataDownloadFactory.dump(writer);
135             writer.println("=== User Consent State For Topics Service ===");
136             writer.println("User Consent is given: " + hasUserConsent());
137         } else {
138             writer.println("Build is not Debuggable");
139         }
140     }
141 }
142