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.data.signals; 18 19 import android.adservices.common.AdTechIdentifier; 20 import android.content.pm.PackageManager; 21 22 import androidx.annotation.NonNull; 23 import androidx.room.Dao; 24 import androidx.room.Delete; 25 import androidx.room.Insert; 26 import androidx.room.OnConflictStrategy; 27 import androidx.room.Query; 28 import androidx.room.Transaction; 29 30 import com.android.adservices.data.common.CleanupUtils; 31 import com.android.adservices.data.enrollment.EnrollmentDao; 32 import com.android.adservices.service.Flags; 33 import com.android.internal.annotations.VisibleForTesting; 34 35 import java.time.Instant; 36 import java.util.Arrays; 37 import java.util.List; 38 import java.util.Objects; 39 import java.util.Set; 40 41 /** 42 * DAO abstract class used to access ProtectedSignal storage 43 * 44 * <p>Annotations will generate Room-based SQLite Dao impl. 45 */ 46 @Dao 47 public abstract class ProtectedSignalsDao { 48 49 /** 50 * Returns a list of all signals owned by the given buyer. 51 * 52 * @param buyer The buyer to retrieve signals for. 53 * @return A list of all protected signals owned by the input buyer. 54 */ 55 @Query("SELECT * FROM protected_signals WHERE buyer = :buyer") getSignalsByBuyer(AdTechIdentifier buyer)56 public abstract List<DBProtectedSignal> getSignalsByBuyer(AdTechIdentifier buyer); 57 58 /** 59 * Inserts signals into the database. 60 * 61 * @param signals The signals to insert. 62 */ 63 @Insert insertSignals(@onNull List<DBProtectedSignal> signals)64 public abstract void insertSignals(@NonNull List<DBProtectedSignal> signals); 65 66 /** 67 * Deletes signals from the database. 68 * 69 * @param signals The signals to delete. 70 */ 71 @Delete deleteSignals(@onNull List<DBProtectedSignal> signals)72 public abstract void deleteSignals(@NonNull List<DBProtectedSignal> signals); 73 74 /** 75 * Inserts and deletes signals in a single transaction. 76 * 77 * @param signalsToInsert The signals to insert. 78 * @param signalsToDelete The signals to delete. 79 */ 80 @Transaction insertAndDelete( @onNull AdTechIdentifier buyer, @NonNull Instant now, @NonNull List<DBProtectedSignal> signalsToInsert, @NonNull List<DBProtectedSignal> signalsToDelete)81 public void insertAndDelete( 82 @NonNull AdTechIdentifier buyer, 83 @NonNull Instant now, 84 @NonNull List<DBProtectedSignal> signalsToInsert, 85 @NonNull List<DBProtectedSignal> signalsToDelete) { 86 insertSignals(signalsToInsert); 87 deleteSignals(signalsToDelete); 88 persistSignalsUpdateMetadata( 89 DBSignalsUpdateMetadata.builder() 90 .setBuyer(buyer) 91 .setLastSignalsUpdatedTime(now) 92 .build()); 93 } 94 95 /** 96 * Deletes all signals {@code expiryTime}. 97 * 98 * @return the number of deleted signals 99 */ 100 @Query("DELETE FROM protected_signals WHERE creationTime < :expiryTime") deleteSignalsBeforeTime(@onNull Instant expiryTime)101 protected abstract int deleteSignalsBeforeTime(@NonNull Instant expiryTime); 102 103 /** Returns buyers with expired signals. */ 104 @Query("SELECT DISTINCT buyer FROM protected_signals WHERE creationTime < :expiryTime") getBuyersWithExpiredSignals( @onNull Instant expiryTime)105 protected abstract List<AdTechIdentifier> getBuyersWithExpiredSignals( 106 @NonNull Instant expiryTime); 107 108 /** 109 * Deletes expired signals and updates buyer metadata. 110 * 111 * @return the number of deleted signals 112 */ 113 @Transaction deleteExpiredSignalsAndUpdateSignalsUpdateMetadata( @onNull Instant expiryTime, @NonNull Instant now)114 public int deleteExpiredSignalsAndUpdateSignalsUpdateMetadata( 115 @NonNull Instant expiryTime, @NonNull Instant now) { 116 List<AdTechIdentifier> buyers = getBuyersWithExpiredSignals(expiryTime); 117 for (AdTechIdentifier buyer : buyers) { 118 persistSignalsUpdateMetadata( 119 DBSignalsUpdateMetadata.builder() 120 .setBuyer(buyer) 121 .setLastSignalsUpdatedTime(now) 122 .build()); 123 } 124 return deleteSignalsBeforeTime(expiryTime); 125 } 126 127 /** 128 * Deletes all signals belonging to disallowed buyer ad techs in a single transaction, where the 129 * buyer ad techs cannot be found in the enrollment database. 130 * 131 * @return the number of deleted signals 132 */ 133 @Transaction deleteDisallowedBuyerSignals(@onNull EnrollmentDao enrollmentDao)134 public int deleteDisallowedBuyerSignals(@NonNull EnrollmentDao enrollmentDao) { 135 Objects.requireNonNull(enrollmentDao); 136 137 List<AdTechIdentifier> buyersToRemove = getAllBuyers(); 138 if (buyersToRemove.isEmpty()) { 139 return 0; 140 } 141 142 Set<AdTechIdentifier> enrolledAdTechs = enrollmentDao.getAllFledgeEnrolledAdTechs(); 143 buyersToRemove.removeAll(enrolledAdTechs); 144 145 int numDeletedEvents = 0; 146 if (!buyersToRemove.isEmpty()) { 147 numDeletedEvents = deleteByBuyers(buyersToRemove); 148 for (AdTechIdentifier buyer : buyersToRemove) { 149 deleteSignalsUpdateMetadata(buyer); 150 } 151 } 152 153 return numDeletedEvents; 154 } 155 156 /** 157 * Helper method for {@link #deleteDisallowedBuyerSignals} 158 * 159 * @return All buyers with signals in the DB. 160 */ 161 @Query("SELECT DISTINCT buyer FROM protected_signals") getAllBuyers()162 protected abstract List<AdTechIdentifier> getAllBuyers(); 163 164 /** 165 * Deletes all signals for the list of buyers. Helper method for {@link 166 * #deleteDisallowedBuyerSignals} 167 * 168 * @return Number of buyers deleted. 169 */ 170 @Query("DELETE FROM protected_signals where buyer in (:buyers)") deleteByBuyers(@onNull List<AdTechIdentifier> buyers)171 protected abstract int deleteByBuyers(@NonNull List<AdTechIdentifier> buyers); 172 173 /** 174 * Deletes all signals belonging to disallowed source apps in a single transaction, where the 175 * source apps cannot be found in the app package name allowlist or are not installed on the 176 * device. 177 * 178 * @return the number of deleted signals 179 */ 180 @Transaction deleteAllDisallowedPackageSignalsAndUpdateSignalUpdateMetadata( @onNull PackageManager packageManager, @NonNull Flags flags, @NonNull Instant now)181 public int deleteAllDisallowedPackageSignalsAndUpdateSignalUpdateMetadata( 182 @NonNull PackageManager packageManager, @NonNull Flags flags, @NonNull Instant now) { 183 Objects.requireNonNull(packageManager); 184 Objects.requireNonNull(flags); 185 Objects.requireNonNull(now); 186 187 List<String> sourceAppsToRemove = getAllPackages(); 188 if (sourceAppsToRemove.isEmpty()) { 189 return 0; 190 } 191 192 CleanupUtils.removeAllowedPackages( 193 sourceAppsToRemove, packageManager, Arrays.asList(flags.getPasAppAllowList())); 194 195 int numDeletedEvents = 0; 196 if (!sourceAppsToRemove.isEmpty()) { 197 List<AdTechIdentifier> buyers = getBuyersForPackages(sourceAppsToRemove); 198 for (AdTechIdentifier buyer : buyers) { 199 persistSignalsUpdateMetadata( 200 DBSignalsUpdateMetadata.builder() 201 .setBuyer(buyer) 202 .setLastSignalsUpdatedTime(now) 203 .build()); 204 } 205 numDeletedEvents = deleteSignalsByPackage(sourceAppsToRemove); 206 // TODO(b/300661099): Collect and send telemetry on signal deletion 207 } 208 return numDeletedEvents; 209 } 210 211 /** 212 * Returns the list of all unique packages in the signals table. 213 * 214 * <p>This method is not meant to be called externally, but is a helper for {@link 215 * #deleteAllDisallowedPackageSignalsAndUpdateSignalUpdateMetadata(PackageManager, Flags, 216 * Instant)} 217 */ 218 @Query("SELECT DISTINCT packageName FROM protected_signals") getAllPackages()219 protected abstract List<String> getAllPackages(); 220 221 /** 222 * Deletes all signals generated from the given packages. 223 * 224 * @return the number of deleted signals 225 */ 226 @Query("DELETE FROM protected_signals WHERE packageName in (:packages)") deleteSignalsByPackage(@onNull List<String> packages)227 public abstract int deleteSignalsByPackage(@NonNull List<String> packages); 228 229 /** Deletes all signals */ 230 @Query("DELETE FROM protected_signals") deleteAllSignals()231 public abstract int deleteAllSignals(); 232 233 /** Returns all buyers for the given packages. */ 234 @Query("SELECT DISTINCT buyer FROM protected_signals WHERE packageName in (:packages)") getBuyersForPackages(@onNull List<String> packages)235 protected abstract List<AdTechIdentifier> getBuyersForPackages(@NonNull List<String> packages); 236 237 /** Create or update a buyer metadata entry. */ 238 @Insert(entity = DBSignalsUpdateMetadata.class, onConflict = OnConflictStrategy.REPLACE) 239 @VisibleForTesting persistSignalsUpdateMetadata( DBSignalsUpdateMetadata dbSignalsUpdateMetadata)240 protected abstract long persistSignalsUpdateMetadata( 241 DBSignalsUpdateMetadata dbSignalsUpdateMetadata); 242 243 /** Returns a metadata entry according to the buyer. */ 244 @Query("SELECT * FROM signals_update_metadata WHERE buyer=:buyer") getSignalsUpdateMetadata(AdTechIdentifier buyer)245 public abstract DBSignalsUpdateMetadata getSignalsUpdateMetadata(AdTechIdentifier buyer); 246 247 /** Delete the metadata for the buyer. */ 248 @Query("DELETE FROM signals_update_metadata WHERE buyer=:buyer") deleteSignalsUpdateMetadata(AdTechIdentifier buyer)249 public abstract void deleteSignalsUpdateMetadata(AdTechIdentifier buyer); 250 251 /** Delete all metadata in the storage. */ 252 @Query("DELETE FROM signals_update_metadata") deleteAllSignalsUpdateMetadata()253 public abstract void deleteAllSignalsUpdateMetadata(); 254 } 255