• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.adservices.service.signals;
18 
19 import android.adservices.common.AdTechIdentifier;
20 import android.annotation.NonNull;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 
24 import com.android.adservices.LoggerFactory;
25 import com.android.adservices.data.enrollment.EnrollmentDao;
26 import com.android.adservices.data.signals.EncodedPayloadDao;
27 import com.android.adservices.data.signals.EncoderLogicHandler;
28 import com.android.adservices.data.signals.ProtectedSignalsDao;
29 import com.android.adservices.data.signals.ProtectedSignalsDatabase;
30 import com.android.adservices.service.Flags;
31 import com.android.adservices.service.FlagsFactory;
32 import com.android.internal.annotations.VisibleForTesting;
33 
34 import java.time.Clock;
35 import java.time.Instant;
36 import java.util.HashSet;
37 import java.util.List;
38 import java.util.Objects;
39 import java.util.Set;
40 
41 /** Utility class to perform Protected Signals maintenance tasks. */
42 public class SignalsMaintenanceTasksWorker {
43 
44     private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger();
45     @NonNull private final ProtectedSignalsDao mProtectedSignalsDao;
46     @NonNull private final EnrollmentDao mEnrollmentDao;
47     @NonNull private final EncodedPayloadDao mEncodedPayloadDao;
48     @NonNull private final Flags mFlags;
49     @NonNull private final Clock mClock;
50     @NonNull private final PackageManager mPackageManager;
51     @NonNull private final EncoderLogicHandler mEncoderLogicHandler;
52 
53     @VisibleForTesting
SignalsMaintenanceTasksWorker( @onNull Flags flags, @NonNull ProtectedSignalsDao protectedSignalsDao, @NonNull EncoderLogicHandler encoderLogicHandler, @NonNull EncodedPayloadDao encodedPayloadDao, @NonNull EnrollmentDao enrollmentDao, @NonNull Clock clock, @NonNull PackageManager packageManager)54     public SignalsMaintenanceTasksWorker(
55             @NonNull Flags flags,
56             @NonNull ProtectedSignalsDao protectedSignalsDao,
57             @NonNull EncoderLogicHandler encoderLogicHandler,
58             @NonNull EncodedPayloadDao encodedPayloadDao,
59             @NonNull EnrollmentDao enrollmentDao,
60             @NonNull Clock clock,
61             @NonNull PackageManager packageManager) {
62         Objects.requireNonNull(flags);
63         Objects.requireNonNull(protectedSignalsDao);
64         Objects.requireNonNull(enrollmentDao);
65         Objects.requireNonNull(clock);
66         Objects.requireNonNull(packageManager);
67 
68         mFlags = flags;
69         mProtectedSignalsDao = protectedSignalsDao;
70         mEnrollmentDao = enrollmentDao;
71         mEncodedPayloadDao = encodedPayloadDao;
72         mEncoderLogicHandler = encoderLogicHandler;
73         mClock = clock;
74         mPackageManager = packageManager;
75     }
76 
SignalsMaintenanceTasksWorker(@onNull Context context)77     private SignalsMaintenanceTasksWorker(@NonNull Context context) {
78         Objects.requireNonNull(context);
79         mFlags = FlagsFactory.getFlags();
80         mProtectedSignalsDao = ProtectedSignalsDatabase.getInstance().protectedSignalsDao();
81         mEnrollmentDao = EnrollmentDao.getInstance();
82         mEncoderLogicHandler = new EncoderLogicHandler(context);
83         mEncodedPayloadDao = ProtectedSignalsDatabase.getInstance().getEncodedPayloadDao();
84         mClock = Clock.systemUTC();
85         mPackageManager = context.getPackageManager();
86     }
87 
88     /** Creates a new instance of {@link SignalsMaintenanceTasksWorker}. */
89     // TODO(b/311183933): Remove passed in Context from static method.
90     @SuppressWarnings("AvoidStaticContext")
create(@onNull Context context)91     public static SignalsMaintenanceTasksWorker create(@NonNull Context context) {
92         Objects.requireNonNull(context);
93         return new SignalsMaintenanceTasksWorker(context);
94     }
95 
96     /**
97      * Clears invalid signals from the protected signals table. Not flagged since the job will only
98      * run if protected signals is enabled.
99      *
100      * <ul>
101      *   <li>Expired signals
102      *   <li>Disallowed buyer signals
103      *   <li>Disallowed source app signals
104      *   <li>Uninstalled source app signals
105      *       <p>Also clears data for disallowed buyers and expired encoding related information such
106      *       as:
107      *       <ul>
108      *         <li>Encoder end-point
109      *         <li>Encoding logic
110      *         <li>Encoded Signals payload
111      *       </ul>
112      */
clearInvalidProtectedSignalsData()113     public void clearInvalidProtectedSignalsData() {
114         Instant now = mClock.instant();
115         Instant expirationInstant = now.minusSeconds(ProtectedSignal.EXPIRATION_SECONDS);
116         clearInvalidSignals(expirationInstant, now);
117         clearInvalidEncoders(expirationInstant);
118         clearInvalidEncodedPayloads(expirationInstant);
119     }
120 
121     @VisibleForTesting
clearInvalidSignals(Instant expirationInstant, Instant now)122     void clearInvalidSignals(Instant expirationInstant, Instant now) {
123 
124         sLogger.v("Clearing expired signals older than %s", expirationInstant);
125         int numExpiredSignals =
126                 mProtectedSignalsDao.deleteExpiredSignalsAndUpdateSignalsUpdateMetadata(
127                         expirationInstant, now);
128         sLogger.v("Cleared %d expired signals", numExpiredSignals);
129 
130         // Read from flags directly, since this maintenance task worker is attached to a background
131         //  job with unknown lifetime
132         if (mFlags.getDisableFledgeEnrollmentCheck()) {
133             sLogger.v(
134                     "FLEDGE enrollment check disabled; skipping disallowed buyer signal"
135                             + " maintenance");
136         } else {
137             sLogger.v("Clearing signals for disallowed buyer ad techs");
138             int numDisallowedBuyerEvents =
139                     mProtectedSignalsDao.deleteDisallowedBuyerSignals(mEnrollmentDao);
140             sLogger.v("Cleared %d signals for disallowed buyer ad techs", numDisallowedBuyerEvents);
141         }
142 
143         sLogger.v("Clearing signals for disallowed source apps");
144         int numDisallowedSourceAppSignals =
145                 mProtectedSignalsDao.deleteAllDisallowedPackageSignalsAndUpdateSignalUpdateMetadata(
146                         mPackageManager, mFlags, now);
147         sLogger.v("Cleared %d signals for disallowed source apps", numDisallowedSourceAppSignals);
148     }
149 
150     @VisibleForTesting
clearInvalidEncoders(Instant expirationInstant)151     void clearInvalidEncoders(Instant expirationInstant) {
152 
153         Set<AdTechIdentifier> buyersWithConsentRevoked = new HashSet<>();
154         if (mFlags.getDisableFledgeEnrollmentCheck()) {
155             sLogger.v(
156                     "FLEDGE enrollment check disabled; skipping disallowed buyer encoding logic"
157                             + " maintenance");
158         } else {
159             sLogger.v("Gathering buyers with consent revoked");
160             List<AdTechIdentifier> registeredBuyers = mEncoderLogicHandler.getBuyersWithEncoders();
161             buyersWithConsentRevoked = getBuyersWithRevokedConsent(new HashSet<>(registeredBuyers));
162         }
163 
164         sLogger.v("Clearing expired encoders older than %s", expirationInstant);
165         Set<AdTechIdentifier> buyersWithStaleEncoders =
166                 new HashSet<>(mEncoderLogicHandler.getBuyersWithStaleEncoders(expirationInstant));
167 
168         // Union of two sets with revoked buyers and buyers with stale encoders
169         buyersWithStaleEncoders.addAll(buyersWithConsentRevoked);
170         mEncoderLogicHandler.deleteEncodersForBuyers(buyersWithStaleEncoders);
171     }
172 
173     @VisibleForTesting
clearInvalidEncodedPayloads(Instant expirationInstant)174     void clearInvalidEncodedPayloads(Instant expirationInstant) {
175 
176         if (mFlags.getDisableFledgeEnrollmentCheck()) {
177             sLogger.v(
178                     "FLEDGE enrollment check disabled; skipping disallowed buyer encoded payload"
179                             + " maintenance");
180         } else {
181             sLogger.v("Gathering buyers with consent revoked");
182             List<AdTechIdentifier> buyersWithEncodedPayloads =
183                     mEncodedPayloadDao.getAllBuyersWithEncodedPayloads();
184             Set<AdTechIdentifier> buyersWithConsentRevoked =
185                     getBuyersWithRevokedConsent(new HashSet<>(buyersWithEncodedPayloads));
186             for (AdTechIdentifier revokedBuyer : buyersWithConsentRevoked) {
187                 mEncodedPayloadDao.deleteEncodedPayload(revokedBuyer);
188             }
189         }
190 
191         sLogger.v("Clearing expired encodings older than %s", expirationInstant);
192         mEncodedPayloadDao.deleteEncodedPayloadsBeforeTime(expirationInstant);
193     }
194 
getBuyersWithRevokedConsent(Set<AdTechIdentifier> buyers)195     private Set<AdTechIdentifier> getBuyersWithRevokedConsent(Set<AdTechIdentifier> buyers) {
196         Set<AdTechIdentifier> enrolledAdTechs = mEnrollmentDao.getAllFledgeEnrolledAdTechs();
197         buyers.removeAll(enrolledAdTechs);
198         return buyers;
199     }
200 }
201