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.adselection; 18 19 import android.adservices.adselection.ReportEventRequest; 20 import android.adservices.common.AdSelectionSignals; 21 import android.adservices.common.AdTechIdentifier; 22 import android.net.Uri; 23 24 import androidx.annotation.NonNull; 25 import androidx.annotation.Nullable; 26 import androidx.room.Dao; 27 import androidx.room.Insert; 28 import androidx.room.OnConflictStrategy; 29 import androidx.room.Query; 30 import androidx.room.Transaction; 31 32 import com.android.adservices.LoggerFactory; 33 import com.android.adservices.data.adselection.datahandlers.AdSelectionInitialization; 34 import com.android.adservices.data.adselection.datahandlers.AdSelectionResultBidAndUri; 35 import com.android.adservices.data.adselection.datahandlers.DBValidator; 36 import com.android.adservices.data.adselection.datahandlers.RegisteredAdInteraction; 37 import com.android.adservices.data.adselection.datahandlers.ReportingComputationData; 38 import com.android.adservices.data.adselection.datahandlers.ReportingData; 39 import com.android.adservices.data.adselection.datahandlers.WinningCustomAudience; 40 41 import java.time.Instant; 42 import java.util.List; 43 import java.util.Objects; 44 import java.util.stream.Collectors; 45 46 /** 47 * Data Access Object interface for access to the local AdSelection data storage. 48 * 49 * <p>Annotation will generate Room based SQLite Dao implementation. 50 */ 51 @Dao 52 public abstract class AdSelectionEntryDao { 53 private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger(); 54 /** 55 * Add a new successful ad selection entry into the table ad_selection. 56 * 57 * @param adSelection is the AdSelection to add to the table ad_selection if the ad_selection_id 58 * not exists. 59 */ 60 // TODO(b/230568647): retry adSelectionId generation in case of collision 61 @Insert(onConflict = OnConflictStrategy.ABORT) persistAdSelection(DBAdSelection adSelection)62 public abstract void persistAdSelection(DBAdSelection adSelection); 63 64 /** 65 * Write a buyer decision logic entry into the table buyer_decision_logic. 66 * 67 * @param buyerDecisionLogic is the BuyerDecisionLogic to write to table buyer_decision_logic. 68 */ 69 @Insert(onConflict = OnConflictStrategy.REPLACE) persistBuyerDecisionLogic(DBBuyerDecisionLogic buyerDecisionLogic)70 public abstract void persistBuyerDecisionLogic(DBBuyerDecisionLogic buyerDecisionLogic); 71 72 /** 73 * Add an ad selection override into the table ad_selection_overrides 74 * 75 * @param adSelectionOverride is the AdSelectionOverride to add to table ad_selection_overrides. 76 * If a {@link DBAdSelectionOverride} object with the {@code adSelectionConfigId} already 77 * exists, this will replace the existing object. 78 */ 79 @Insert(onConflict = OnConflictStrategy.REPLACE) persistAdSelectionOverride(DBAdSelectionOverride adSelectionOverride)80 public abstract void persistAdSelectionOverride(DBAdSelectionOverride adSelectionOverride); 81 82 /** 83 * Add an ad selection override for Buyers' decision logic 84 * 85 * @param perBuyerDecisionLogicOverride is an override for the 86 * ad_selection_buyer_logic_overrides. If a {@link DBBuyerDecisionOverride} object with the 87 * {@code adSelectionConfigId} already exists, this will replace the existing object. 88 */ 89 @Insert(onConflict = OnConflictStrategy.REPLACE) persistPerBuyerDecisionLogicOverride( List<DBBuyerDecisionOverride> perBuyerDecisionLogicOverride)90 public abstract void persistPerBuyerDecisionLogicOverride( 91 List<DBBuyerDecisionOverride> perBuyerDecisionLogicOverride); 92 93 /** 94 * Adds a list of registered ad interactions to the table registered_ad_interactions 95 * 96 * <p>This method is not meant to be used on its own, since it doesn't take into account the 97 * maximum size of {@code registered_ad_interactions}. Use {@link 98 * #safelyInsertRegisteredAdInteractions(long, List, long, long, int)} instead. 99 * 100 * @param registeredAdInteractions is the list of {@link DBRegisteredAdInteraction} objects to 101 * write to the table registered_ad_interactions. 102 */ 103 @Insert(onConflict = OnConflictStrategy.REPLACE) persistDBRegisteredAdInteractions( List<DBRegisteredAdInteraction> registeredAdInteractions)104 protected abstract void persistDBRegisteredAdInteractions( 105 List<DBRegisteredAdInteraction> registeredAdInteractions); 106 107 /** 108 * Checks if there is a row in the ad selection data with the unique key ad_selection_id in on 109 * device auction tables 110 * 111 * @param adSelectionId which is the key to query the corresponding ad selection data. 112 * @return true if row exists, false otherwise 113 */ 114 @Query( 115 "SELECT EXISTS(SELECT 1 FROM ad_selection WHERE ad_selection_id = :adSelectionId LIMIT" 116 + " 1)") doesAdSelectionIdExist(long adSelectionId)117 public abstract boolean doesAdSelectionIdExist(long adSelectionId); 118 119 /** 120 * Checks if there is a row in the buyer decision logic data with the unique key 121 * bidding_logic_uri 122 * 123 * @param biddingLogicUri which is the key to query the corresponding buyer decision logic data. 124 * @return true if row exists, false otherwise 125 */ 126 @Query( 127 "SELECT EXISTS(SELECT 1 FROM buyer_decision_logic WHERE bidding_logic_uri =" 128 + " :biddingLogicUri LIMIT 1)") doesBuyerDecisionLogicExist(Uri biddingLogicUri)129 public abstract boolean doesBuyerDecisionLogicExist(Uri biddingLogicUri); 130 131 /** 132 * Checks if there is a row in the ad selection override data with the unique key 133 * ad_selection_config_id 134 * 135 * @param adSelectionConfigId which is the key to query the corresponding ad selection override 136 * data. 137 * @return true if row exists, false otherwise 138 */ 139 @Query( 140 "SELECT EXISTS(SELECT 1 FROM ad_selection_overrides WHERE ad_selection_config_id =" 141 + " :adSelectionConfigId AND app_package_name = :appPackageName LIMIT 1)") doesAdSelectionOverrideExistForPackageName( String adSelectionConfigId, String appPackageName)142 public abstract boolean doesAdSelectionOverrideExistForPackageName( 143 String adSelectionConfigId, String appPackageName); 144 145 /** 146 * Checks if there is a row in the {@link DBReportingComputationInfo} table with the unique key 147 * ad_selection_id in on device auction tables 148 * 149 * @param adSelectionId which is the key to query the corresponding ad selection data. 150 * @return true if row exists, false otherwise 151 */ 152 @Query( 153 "SELECT EXISTS(SELECT 1 FROM reporting_computation_info WHERE ad_selection_id =" 154 + " :adSelectionId LIMIT 1)") doesReportingComputationInfoExist(long adSelectionId)155 public abstract boolean doesReportingComputationInfoExist(long adSelectionId); 156 157 /** 158 * Checks if there is a row in the registered_ad_interactions table that matches the primary key 159 * combination of adSelectionId, interactionKey, and destination 160 * 161 * @param adSelectionId serves as the primary key denoting the ad selection process this entry 162 * id associated with 163 * @param interactionKey the interaction key 164 * @param destination denotes buyer, seller, etc. 165 */ 166 @Query( 167 "SELECT EXISTS(SELECT 1 FROM registered_ad_interactions WHERE ad_selection_id =" 168 + " :adSelectionId AND interaction_key = :interactionKey AND destination" 169 + " = :destination LIMIT 1)") doesRegisteredAdInteractionExist( long adSelectionId, String interactionKey, @ReportEventRequest.ReportingDestination int destination)170 public abstract boolean doesRegisteredAdInteractionExist( 171 long adSelectionId, 172 String interactionKey, 173 @ReportEventRequest.ReportingDestination int destination); 174 175 /** 176 * Get the ad selection entry by its unique key ad_selection_id. 177 * 178 * @param adSelectionId which is the key to query the corresponding ad selection entry. 179 * @return an {@link DBAdSelectionEntry} if exists. 180 */ 181 @Query( 182 "SELECT ad_selection.ad_selection_id as ad_selection_id," 183 + " ad_selection.custom_audience_signals_owner as custom_audience_signals_owner," 184 + " ad_selection.custom_audience_signals_buyer as custom_audience_signals_buyer," 185 + " ad_selection.custom_audience_signals_name as custom_audience_signals_name," 186 + " ad_selection.custom_audience_signals_activation_time as" 187 + " custom_audience_signals_activation_time," 188 + " ad_selection.custom_audience_signals_expiration_time as" 189 + " custom_audience_signals_expiration_time," 190 + " ad_selection.custom_audience_signals_user_bidding_signals as" 191 + " custom_audience_signals_user_bidding_signals, ad_selection.contextual_signals" 192 + " as contextual_signals,ad_selection.winning_ad_render_uri as" 193 + " winning_ad_render_uri,ad_selection.winning_ad_bid as" 194 + " winning_ad_bid,ad_selection.creation_timestamp as" 195 + " creation_timestamp,buyer_decision_logic.buyer_decision_logic_js as" 196 + " buyer_decision_logic_js, ad_selection.bidding_logic_uri as bidding_logic_uri," 197 + " ad_selection.seller_contextual_signals as seller_contextual_signals FROM" 198 + " ad_selection LEFT JOIN buyer_decision_logic ON ad_selection.bidding_logic_uri =" 199 + " buyer_decision_logic.bidding_logic_uri WHERE ad_selection.ad_selection_id =" 200 + " :adSelectionId") getAdSelectionEntityById(long adSelectionId)201 public abstract DBAdSelectionEntry getAdSelectionEntityById(long adSelectionId); 202 203 /** 204 * Get the {@link DBReportingComputationInfo} by its unique key ad_selection_id. 205 * 206 * @param adSelectionId which is the key to query the corresponding ad selection entry. 207 * @return an {@link DBReportingComputationInfo} if exists. 208 */ 209 @Query( 210 "SELECT reporting_computation_info.ad_selection_id as ad_selection_id," 211 + " reporting_computation_info.bidding_logic_uri as bidding_logic_uri," 212 + " reporting_computation_info.buyer_decision_logic_js as buyer_decision_logic_js," 213 + " reporting_computation_info.seller_contextual_signals as" 214 + " seller_contextual_signals, reporting_computation_info.buyer_contextual_signals" 215 + " as buyer_contextual_signals," 216 + " reporting_computation_info.custom_audience_signals_owner as" 217 + " custom_audience_signals_owner," 218 + " reporting_computation_info.custom_audience_signals_buyer as" 219 + " custom_audience_signals_buyer," 220 + " reporting_computation_info.custom_audience_signals_name as" 221 + " custom_audience_signals_name," 222 + " reporting_computation_info.custom_audience_signals_activation_time as" 223 + " custom_audience_signals_activation_time," 224 + " reporting_computation_info.custom_audience_signals_expiration_time as" 225 + " custom_audience_signals_expiration_time," 226 + " reporting_computation_info.custom_audience_signals_user_bidding_signals as" 227 + " custom_audience_signals_user_bidding_signals," 228 + " reporting_computation_info.winning_ad_bid as winning_ad_bid," 229 + " reporting_computation_info.winning_ad_render_uri as winning_ad_render_uri FROM" 230 + " reporting_computation_info WHERE reporting_computation_info.ad_selection_id =" 231 + " :adSelectionId") getReportingComputationInfoById(long adSelectionId)232 public abstract DBReportingComputationInfo getReportingComputationInfoById(long adSelectionId); 233 /** 234 * Get the ad selection entries with a batch of ad_selection_ids. 235 * 236 * @param adSelectionIds are the list of keys to query the corresponding ad selection entries. 237 * @return ad selection entries if exists. 238 */ 239 @Query( 240 "SELECT ad_selection.ad_selection_id AS" 241 + " ad_selection_id,ad_selection.custom_audience_signals_owner as" 242 + " custom_audience_signals_owner, ad_selection.custom_audience_signals_buyer as" 243 + " custom_audience_signals_buyer, ad_selection.custom_audience_signals_name as" 244 + " custom_audience_signals_name," 245 + " ad_selection.custom_audience_signals_activation_time as" 246 + " custom_audience_signals_activation_time," 247 + " ad_selection.custom_audience_signals_expiration_time as" 248 + " custom_audience_signals_expiration_time," 249 + " ad_selection.custom_audience_signals_user_bidding_signals as" 250 + " custom_audience_signals_user_bidding_signals, ad_selection.contextual_signals" 251 + " AS contextual_signals,ad_selection.winning_ad_render_uri AS" 252 + " winning_ad_render_uri,ad_selection.winning_ad_bid AS winning_ad_bid," 253 + " ad_selection.creation_timestamp as creation_timestamp," 254 + " buyer_decision_logic.buyer_decision_logic_js AS buyer_decision_logic_js," 255 + " ad_selection.bidding_logic_uri AS bidding_logic_uri," 256 + " ad_selection.seller_contextual_signals as seller_contextual_signals FROM" 257 + " ad_selection LEFT JOIN buyer_decision_logic ON ad_selection.bidding_logic_uri =" 258 + " buyer_decision_logic.bidding_logic_uri WHERE ad_selection.ad_selection_id IN" 259 + " (:adSelectionIds) ") getAdSelectionEntities(List<Long> adSelectionIds)260 public abstract List<DBAdSelectionEntry> getAdSelectionEntities(List<Long> adSelectionIds); 261 262 /** 263 * Get the ad selection entries with a batch of ad_selection_ids. 264 * 265 * @param adSelectionIds are the list of keys to query the corresponding ad selection entries. 266 * @return ad selection entries if exists. 267 */ 268 @Query( 269 "SELECT ad_selection.ad_selection_id AS" 270 + " ad_selection_id,ad_selection.custom_audience_signals_owner as" 271 + " custom_audience_signals_owner, ad_selection.custom_audience_signals_buyer as" 272 + " custom_audience_signals_buyer, ad_selection.custom_audience_signals_name as" 273 + " custom_audience_signals_name," 274 + " ad_selection.custom_audience_signals_activation_time as" 275 + " custom_audience_signals_activation_time," 276 + " ad_selection.custom_audience_signals_expiration_time as" 277 + " custom_audience_signals_expiration_time," 278 + " ad_selection.custom_audience_signals_user_bidding_signals as" 279 + " custom_audience_signals_user_bidding_signals, ad_selection.contextual_signals" 280 + " AS contextual_signals,ad_selection.winning_ad_render_uri AS" 281 + " winning_ad_render_uri,ad_selection.winning_ad_bid AS winning_ad_bid," 282 + " ad_selection.creation_timestamp as creation_timestamp," 283 + " buyer_decision_logic.buyer_decision_logic_js AS buyer_decision_logic_js," 284 + " ad_selection.bidding_logic_uri AS bidding_logic_uri," 285 + " ad_selection.seller_contextual_signals as seller_contextual_signals FROM" 286 + " ad_selection LEFT JOIN buyer_decision_logic ON ad_selection.bidding_logic_uri =" 287 + " buyer_decision_logic.bidding_logic_uri WHERE ad_selection.ad_selection_id IN" 288 + " (:adSelectionIds) AND ad_selection.caller_package_name = :callerPackageName") getAdSelectionEntities( List<Long> adSelectionIds, String callerPackageName)289 public abstract List<DBAdSelectionEntry> getAdSelectionEntities( 290 List<Long> adSelectionIds, String callerPackageName); 291 292 /** 293 * Get ad selection JS override by its unique key and the package name of the app that created 294 * the override. 295 * 296 * @return ad selection override result if exists. 297 */ 298 @Query( 299 "SELECT decision_logic FROM ad_selection_overrides WHERE ad_selection_config_id =" 300 + " :adSelectionConfigId AND app_package_name = :appPackageName") 301 @Nullable getDecisionLogicOverride( String adSelectionConfigId, String appPackageName)302 public abstract String getDecisionLogicOverride( 303 String adSelectionConfigId, String appPackageName); 304 305 /** 306 * Get ad selection trusted scoring signals override by its unique key and the package name of 307 * the app that created the override. 308 * 309 * @return ad selection override result if exists. 310 */ 311 @Query( 312 "SELECT trusted_scoring_signals FROM ad_selection_overrides WHERE" 313 + " ad_selection_config_id = :adSelectionConfigId AND app_package_name =" 314 + " :appPackageName") 315 @Nullable getTrustedScoringSignalsOverride( String adSelectionConfigId, String appPackageName)316 public abstract String getTrustedScoringSignalsOverride( 317 String adSelectionConfigId, String appPackageName); 318 319 /** 320 * Get ad selection buyer decision logic override by its unique key and the package name of the 321 * app that created the override. 322 * 323 * @return ad selection override result if exists. 324 */ 325 @Query( 326 "SELECT * FROM ad_selection_buyer_logic_overrides WHERE" 327 + " ad_selection_config_id = :adSelectionConfigId AND app_package_name =" 328 + " :appPackageName") 329 @Nullable getPerBuyerDecisionLogicOverride( String adSelectionConfigId, String appPackageName)330 public abstract List<DBBuyerDecisionOverride> getPerBuyerDecisionLogicOverride( 331 String adSelectionConfigId, String appPackageName); 332 333 /** 334 * Gets the interaction reporting uri that was registered with the primary key combination of 335 * {@code adSelectionId}, {@code interactionKey}, and {@code destination}. 336 * 337 * @return interaction reporting uri if exists. 338 */ 339 @Query( 340 "SELECT interaction_reporting_uri FROM registered_ad_interactions WHERE" 341 + " ad_selection_id = :adSelectionId AND interaction_key = :interactionKey AND" 342 + " destination = :destination") 343 @Nullable getRegisteredAdInteractionUri( long adSelectionId, String interactionKey, @ReportEventRequest.ReportingDestination int destination)344 public abstract Uri getRegisteredAdInteractionUri( 345 long adSelectionId, 346 String interactionKey, 347 @ReportEventRequest.ReportingDestination int destination); 348 349 /** 350 * Gets the {@link DBAdSelectionHistogramInfo} representing the histogram information associated 351 * with a given ad selection for on device. 352 * 353 * @return a {@link DBAdSelectionHistogramInfo} containing the histogram info associated with 354 * the ad selection, or {@code null} if no match is found 355 */ 356 @Query( 357 "SELECT custom_audience_signals_buyer, ad_counter_int_keys FROM ad_selection " 358 + "WHERE ad_selection_id = :adSelectionId " 359 + "AND caller_package_name = :callerPackageName") 360 @Nullable getAdSelectionHistogramInfoInOnDeviceTable( long adSelectionId, @NonNull String callerPackageName)361 public abstract DBAdSelectionHistogramInfo getAdSelectionHistogramInfoInOnDeviceTable( 362 long adSelectionId, @NonNull String callerPackageName); 363 364 /** 365 * Gets the {@link DBAdSelectionHistogramInfo} representing the histogram information associated 366 * with a given ad selection for server auction. 367 * 368 * @return a {@link DBAdSelectionHistogramInfo} containing the histogram info associated with 369 * the ad selection, or {@code null} if no match is found 370 */ 371 @Query( 372 "SELECT custom_audience_signals_buyer, ad_counter_int_keys " 373 + "FROM ad_selection " 374 + "WHERE ad_selection_id = :adSelectionId " 375 + "AND caller_package_name = :callerPackageName " 376 + "UNION ALL " 377 + "SELECT winning_buyer AS custom_audience_signals_buyer, " 378 + "winning_custom_audience_ad_counter_int_keys AS ad_counter_int_keys " 379 + "FROM ad_selection_result results " 380 + "JOIN ad_selection_initialization init " 381 + "ON results.ad_selection_id = init.ad_selection_id " 382 + "WHERE init.ad_selection_id = :adSelectionId " 383 + "AND init.caller_package_name = :callerPackageName") 384 @Nullable getAdSelectionHistogramInfo( long adSelectionId, @NonNull String callerPackageName)385 public abstract DBAdSelectionHistogramInfo getAdSelectionHistogramInfo( 386 long adSelectionId, @NonNull String callerPackageName); 387 388 /** 389 * Gets the {@link DBAdSelectionHistogramInfo} representing the histogram information associated 390 * with a given ad selection. Only fetches data from the unified tables, not {@code 391 * ad_selection} 392 * 393 * @return a {@link DBAdSelectionHistogramInfo} containing the histogram info associated with 394 * the ad selection, or {@code null} if no match is found 395 */ 396 @Query( 397 "SELECT winning_buyer AS custom_audience_signals_buyer, " 398 + "winning_custom_audience_ad_counter_int_keys AS ad_counter_int_keys " 399 + "FROM ad_selection_result results " 400 + "JOIN ad_selection_initialization init " 401 + "ON results.ad_selection_id = init.ad_selection_id " 402 + "WHERE init.ad_selection_id = :adSelectionId " 403 + "AND init.caller_package_name = :callerPackageName") 404 @Nullable getAdSelectionHistogramInfoFromUnifiedTable( long adSelectionId, @NonNull String callerPackageName)405 public abstract DBAdSelectionHistogramInfo getAdSelectionHistogramInfoFromUnifiedTable( 406 long adSelectionId, @NonNull String callerPackageName); 407 408 /** 409 * Clean up expired adSelection entries if it is older than the given timestamp. If 410 * creation_timestamp < expirationTime, the ad selection entry will be removed from the 411 * ad_selection table. 412 * 413 * @param expirationTime is the cutoff time to expire the AdSelectionEntry. 414 */ 415 @Query("DELETE FROM ad_selection WHERE creation_timestamp < :expirationTime") removeExpiredAdSelection(Instant expirationTime)416 public abstract void removeExpiredAdSelection(Instant expirationTime); 417 418 /** 419 * Clean up expired ad selection initialization entries if it is older than the given timestamp. 420 * If creation_instant < expirationTime, the ad selection initialization will be removed from 421 * the ad_selection_initialization table. It will also remove the entries from the other table 422 * with ad_selection_id as the foreign key because onDelete cascade is set. 423 * 424 * @param expirationTime is the cutoff time to expire the AdSelectionEntry. 425 */ 426 @Query("DELETE FROM ad_selection_initialization WHERE creation_instant < :expirationTime") removeExpiredAdSelectionInitializations(Instant expirationTime)427 public abstract void removeExpiredAdSelectionInitializations(Instant expirationTime); 428 429 /** 430 * Clean up selected ad selection data entry data in batch by their ad_selection_ids. 431 * 432 * @param adSelectionIds is the list of adSelectionIds to identify the data entries to be 433 * removed from ad_selection and buyer_decision_logic tables. 434 */ 435 @Query("DELETE FROM ad_selection WHERE ad_selection_id IN (:adSelectionIds)") removeAdSelectionEntriesByIds(List<Long> adSelectionIds)436 public abstract void removeAdSelectionEntriesByIds(List<Long> adSelectionIds); 437 438 /** 439 * Clean up selected ad selection override data by its {@code adSelectionConfigId} 440 * 441 * @param adSelectionConfigId is the {@code adSelectionConfigId} to identify the data entries to 442 * be removed from the ad_selection_overrides table. 443 */ 444 @Query( 445 "DELETE FROM ad_selection_overrides WHERE ad_selection_config_id = :adSelectionConfigId" 446 + " AND app_package_name = :appPackageName") removeAdSelectionOverrideByIdAndPackageName( String adSelectionConfigId, String appPackageName)447 public abstract void removeAdSelectionOverrideByIdAndPackageName( 448 String adSelectionConfigId, String appPackageName); 449 450 /** 451 * Clean up buyer decision logic override data by its {@code adSelectionConfigId} 452 * 453 * @param adSelectionConfigId is the {@code adSelectionConfigId} to identify the data entries to 454 * be removed from the ad_selection_overrides table. 455 */ 456 @Query( 457 "DELETE FROM ad_selection_buyer_logic_overrides WHERE ad_selection_config_id = " 458 + ":adSelectionConfigId AND app_package_name = :appPackageName") removeBuyerDecisionLogicOverrideByIdAndPackageName( String adSelectionConfigId, String appPackageName)459 public abstract void removeBuyerDecisionLogicOverrideByIdAndPackageName( 460 String adSelectionConfigId, String appPackageName); 461 462 /** 463 * Clean up buyer_decision_logic entries in batch if the bidding_logic_uri no longer exists in 464 * the table ad_selection. 465 */ 466 @Query( 467 "DELETE FROM buyer_decision_logic WHERE bidding_logic_uri NOT IN " 468 + "( SELECT DISTINCT bidding_logic_uri " 469 + "FROM ad_selection " 470 + "WHERE bidding_logic_uri is NOT NULL)") removeExpiredBuyerDecisionLogic()471 public abstract void removeExpiredBuyerDecisionLogic(); 472 473 /** Clean up all ad selection override data */ 474 @Query("DELETE FROM ad_selection_overrides WHERE app_package_name = :appPackageName") removeAllAdSelectionOverrides(String appPackageName)475 public abstract void removeAllAdSelectionOverrides(String appPackageName); 476 477 /** Clean up all buyers' decision logic data */ 478 @Query( 479 "DELETE FROM ad_selection_buyer_logic_overrides WHERE app_package_name =" 480 + " :appPackageName") removeAllBuyerDecisionOverrides(String appPackageName)481 public abstract void removeAllBuyerDecisionOverrides(String appPackageName); 482 483 /** 484 * Checks if there is a row in the ad selection data with the unique combination of 485 * ad_selection_id and caller_package_name 486 * 487 * @param adSelectionId which is the key to query the corresponding ad selection data. 488 * @param callerPackageName the caller's package name, to be verified against the 489 * calling_package_name that exists in the ad_selection_entry 490 * @return true if row exists, false otherwise 491 */ 492 @Query( 493 "SELECT EXISTS(SELECT 1 FROM ad_selection WHERE ad_selection_id = :adSelectionId" 494 + " AND caller_package_name = :callerPackageName LIMIT" 495 + " 1)") doesAdSelectionMatchingCallerPackageNameExistInOnDeviceTable( long adSelectionId, String callerPackageName)496 public abstract boolean doesAdSelectionMatchingCallerPackageNameExistInOnDeviceTable( 497 long adSelectionId, String callerPackageName); 498 499 /** 500 * Checks if there is a row in the ad selection initizalization table with the unique 501 * combination of ad_selection_id and caller_package_name 502 * 503 * @param adSelectionId which is the key to query the corresponding ad selection data. 504 * @param callerPackageName the caller's package name, to be verified against the 505 * calling_package_name that exists in the ad_selection_entry 506 * @return true if row exists, false otherwise 507 */ 508 @Query( 509 "SELECT EXISTS(SELECT 1 FROM ad_selection_initialization WHERE ad_selection_id =" 510 + " :adSelectionId AND caller_package_name = :callerPackageName LIMIT 1)") doesAdSelectionMatchingCallerPackageNameExistInServerAuctionTable( long adSelectionId, String callerPackageName)511 public abstract boolean doesAdSelectionMatchingCallerPackageNameExistInServerAuctionTable( 512 long adSelectionId, String callerPackageName); 513 514 /** 515 * Checks if there is a row in either of the ad selection tables with the unique combination of 516 * ad_selection_id and caller_package_name 517 */ 518 @Transaction doesAdSelectionIdAndCallerPackageNameExists( long adSelectionId, String callerPackageName)519 public boolean doesAdSelectionIdAndCallerPackageNameExists( 520 long adSelectionId, String callerPackageName) { 521 return doesAdSelectionMatchingCallerPackageNameExistInOnDeviceTable( 522 adSelectionId, callerPackageName) 523 || doesAdSelectionMatchingCallerPackageNameExistInServerAuctionTable( 524 adSelectionId, callerPackageName); 525 } 526 527 /** 528 * Add an ad selection from outcomes override into the table 529 * ad_selection_from_outcomes_overrides 530 * 531 * @param adSelectionFromOutcomesOverride is the AdSelectionFromOutcomesOverride to add to table 532 * ad_selection_overrides. If a {@link DBAdSelectionFromOutcomesOverride} object with the 533 * {@code adSelectionConfigFromOutcomesId} already exists, this will replace the existing 534 * object. 535 */ 536 @Insert(onConflict = OnConflictStrategy.REPLACE) persistAdSelectionFromOutcomesOverride( DBAdSelectionFromOutcomesOverride adSelectionFromOutcomesOverride)537 public abstract void persistAdSelectionFromOutcomesOverride( 538 DBAdSelectionFromOutcomesOverride adSelectionFromOutcomesOverride); 539 540 /** 541 * Checks if there is a row in the ad selection override data with the unique key 542 * ad_selection_from_outcomes_config_id 543 * 544 * @param adSelectionFromOutcomesConfigId which is the key to query the corresponding ad 545 * selection override data. 546 * @return true if row exists, false otherwise 547 */ 548 @Query( 549 "SELECT EXISTS(SELECT 1 FROM ad_selection_from_outcomes_overrides WHERE " 550 + "ad_selection_from_outcomes_config_id = " 551 + ":adSelectionFromOutcomesConfigId AND app_package_name = :appPackageName " 552 + "LIMIT 1)") doesAdSelectionFromOutcomesOverrideExistForPackageName( String adSelectionFromOutcomesConfigId, String appPackageName)553 public abstract boolean doesAdSelectionFromOutcomesOverrideExistForPackageName( 554 String adSelectionFromOutcomesConfigId, String appPackageName); 555 556 /** 557 * Get ad selection from outcomes selection logic JS override by its unique key and the package 558 * name of the app that created the override. 559 * 560 * @return ad selection override result if exists. 561 */ 562 @Query( 563 "SELECT selection_logic_js FROM ad_selection_from_outcomes_overrides WHERE " 564 + "ad_selection_from_outcomes_config_id = :adSelectionFromOutcomesConfigId " 565 + "AND app_package_name = :appPackageName") 566 @Nullable getSelectionLogicOverride( String adSelectionFromOutcomesConfigId, String appPackageName)567 public abstract String getSelectionLogicOverride( 568 String adSelectionFromOutcomesConfigId, String appPackageName); 569 570 /** 571 * Get ad selection from outcomes signals override by its unique key and the package name of the 572 * app that created the override. 573 * 574 * @return ad selection from outcomes override result if exists. 575 */ 576 @Query( 577 "SELECT selection_signals FROM ad_selection_from_outcomes_overrides WHERE" 578 + " ad_selection_from_outcomes_config_id = :adSelectionFromOutcomesConfigId " 579 + "AND app_package_name = :appPackageName") 580 @Nullable getSelectionSignalsOverride( String adSelectionFromOutcomesConfigId, String appPackageName)581 public abstract String getSelectionSignalsOverride( 582 String adSelectionFromOutcomesConfigId, String appPackageName); 583 584 /** 585 * Clean up selected ad selection from outcomes override data by its {@code 586 * adSelectionFromOutcomesConfigId} 587 * 588 * @param adSelectionFromOutcomesConfigId is to identify the data entries to be removed from the 589 * ad_selection_overrides table. 590 */ 591 @Query( 592 "DELETE FROM ad_selection_from_outcomes_overrides WHERE " 593 + "ad_selection_from_outcomes_config_id = :adSelectionFromOutcomesConfigId AND " 594 + "app_package_name = :appPackageName") removeAdSelectionFromOutcomesOverrideByIdAndPackageName( String adSelectionFromOutcomesConfigId, String appPackageName)595 public abstract void removeAdSelectionFromOutcomesOverrideByIdAndPackageName( 596 String adSelectionFromOutcomesConfigId, String appPackageName); 597 598 /** Clean up all ad selection from outcomes override data */ 599 @Query( 600 "DELETE FROM ad_selection_from_outcomes_overrides WHERE app_package_name = " 601 + ":appPackageName") removeAllAdSelectionFromOutcomesOverrides(String appPackageName)602 public abstract void removeAllAdSelectionFromOutcomesOverrides(String appPackageName); 603 604 /** 605 * Clean up registered_ad_interaction entries in batch if the {@code adSelectionId} no longer 606 * exists in the table ad_selection. 607 */ 608 @Query( 609 "DELETE FROM registered_ad_interactions WHERE ad_selection_id NOT IN " 610 + "( SELECT DISTINCT ad_selection_id " 611 + "FROM ad_selection " 612 + "WHERE ad_selection_id is NOT NULL)") removeExpiredRegisteredAdInteractions()613 public abstract void removeExpiredRegisteredAdInteractions(); 614 615 /** 616 * Clean up registered_ad_interaction entries in batch if the {@code adSelectionId} no longer 617 * exists in the table ad_selection_initialization. 618 */ 619 @Query( 620 "DELETE FROM registered_ad_interactions WHERE ad_selection_id NOT IN " 621 + "( SELECT DISTINCT ad_selection_id " 622 + "FROM ad_selection_initialization " 623 + "WHERE ad_selection_id is NOT NULL)") removeExpiredRegisteredAdInteractionsFromUnifiedTable()624 public abstract void removeExpiredRegisteredAdInteractionsFromUnifiedTable(); 625 626 /** Returns total size of the {@code registered_ad_interaction} table. */ 627 @Query("SELECT COUNT(*) FROM registered_ad_interactions") getTotalNumRegisteredAdInteractions()628 public abstract long getTotalNumRegisteredAdInteractions(); 629 630 /** 631 * Returns total number of the {@code registered_ad_interaction}s that match a given {@code 632 * adSelectionId} and {@code reportingDestination}. 633 */ 634 @Query( 635 "SELECT COUNT(*) FROM registered_ad_interactions WHERE ad_selection_id =" 636 + " :adSelectionId AND destination = :reportingDestination") getNumRegisteredAdInteractionsPerAdSelectionAndDestination( long adSelectionId, @ReportEventRequest.ReportingDestination int reportingDestination)637 public abstract long getNumRegisteredAdInteractionsPerAdSelectionAndDestination( 638 long adSelectionId, @ReportEventRequest.ReportingDestination int reportingDestination); 639 640 /** 641 * Inserts a list of {@link DBRegisteredAdInteraction}s into the database, enforcing these 642 * limitations: 643 * 644 * <p>We will not allow the total size of the {@code registered_ad_interaction} to exceed {@code 645 * maxTotalNumRegisteredInteractions} 646 * 647 * <p>We will not allow the number of registered ad interactions {@code adSelectionId} and 648 * {@code reportingDestination} to exceed {@code maxPerDestinationNumRegisteredInteractions}. 649 * 650 * <p>This transaction is separate in order to minimize the critical region while locking the 651 * database. 652 */ 653 @Transaction safelyInsertRegisteredAdInteractions( long adSelectionId, @NonNull List<DBRegisteredAdInteraction> registeredAdInteractions, long maxTotalNumRegisteredInteractions, long maxPerDestinationNumRegisteredInteractions, int reportingDestination)654 public void safelyInsertRegisteredAdInteractions( 655 long adSelectionId, 656 @NonNull List<DBRegisteredAdInteraction> registeredAdInteractions, 657 long maxTotalNumRegisteredInteractions, 658 long maxPerDestinationNumRegisteredInteractions, 659 int reportingDestination) { 660 long currentNumRegisteredInteractions = getTotalNumRegisteredAdInteractions(); 661 662 if (currentNumRegisteredInteractions >= maxTotalNumRegisteredInteractions) { 663 sLogger.v("Registered Ad Interaction max table size reached! Skipping entire list."); 664 return; 665 } 666 667 long currentNumRegisteredInteractionsPerDestination = 668 getNumRegisteredAdInteractionsPerAdSelectionAndDestination( 669 adSelectionId, reportingDestination); 670 671 if (currentNumRegisteredInteractionsPerDestination 672 >= maxPerDestinationNumRegisteredInteractions) { 673 sLogger.v( 674 "Maximum number of Registered Ad Interactions for this adSelectionId and" 675 + " reportingDestination reached! Skipping entire list."); 676 return; 677 } 678 679 long numAvailableRowsInTable = 680 Math.max(0, maxTotalNumRegisteredInteractions - currentNumRegisteredInteractions); 681 682 long numAvailableRowsInTablePerAdSelectionIdAndDestination = 683 Math.max( 684 0, 685 maxPerDestinationNumRegisteredInteractions 686 - currentNumRegisteredInteractionsPerDestination); 687 688 int numEntriesToCommit = 689 (int) 690 Math.min( 691 numAvailableRowsInTablePerAdSelectionIdAndDestination, 692 Math.min(registeredAdInteractions.size(), numAvailableRowsInTable)); 693 List<DBRegisteredAdInteraction> registeredAdInteractionsToCommit = 694 registeredAdInteractions.subList(0, numEntriesToCommit); 695 696 persistDBRegisteredAdInteractions(registeredAdInteractionsToCommit); 697 } 698 699 /** Checks if adSelectionId exists in {@link DBAdSelectionInitialization}. */ 700 @Query( 701 "SELECT EXISTS(SELECT 1 FROM ad_selection_initialization " 702 + "WHERE ad_selection_id = :adSelectionId)") doesAdSelectionIdExistInInitializationTable(long adSelectionId)703 public abstract boolean doesAdSelectionIdExistInInitializationTable(long adSelectionId); 704 705 /** 706 * Checks if adSelectionId exists in {@link DBAdSelectionInitialization} or in {@link 707 * DBAdSelection}, depending on the flag. 708 */ 709 @Transaction doesAdSelectionIdExistUponFlag( long adSelectionId, boolean shouldCheckUnifiedTable)710 public boolean doesAdSelectionIdExistUponFlag( 711 long adSelectionId, boolean shouldCheckUnifiedTable) { 712 if (shouldCheckUnifiedTable) { 713 return doesAdSelectionIdExistInInitializationTable(adSelectionId); 714 } 715 return doesAdSelectionIdExist(adSelectionId); 716 } 717 718 /** 719 * Checks if there is a row in the ad selection with the unique key ad_selection_id and caller 720 * package name. 721 * 722 * @param adSelectionIds which is the key to query the corresponding ad selection data. 723 * @param callerPackageName package name which initiated the auction run 724 * @return true if row exists, false otherwise 725 */ 726 @Query( 727 "SELECT ad_selection_id FROM ad_selection WHERE ad_selection_id IN (:adSelectionIds)" 728 + " AND caller_package_name = :callerPackageName") getAdSelectionIdsWithCallerPackageNameInOnDeviceTable( List<Long> adSelectionIds, String callerPackageName)729 public abstract List<Long> getAdSelectionIdsWithCallerPackageNameInOnDeviceTable( 730 List<Long> adSelectionIds, String callerPackageName); 731 732 /** 733 * Checks if there is a row in the ad selection and ad_selection_initialization with the unique 734 * key ad_selection_id and caller package name. 735 * 736 * @param adSelectionIds which is the key to query the corresponding ad selection data. 737 * @param callerPackageName package name which initiated the auction run 738 * @return true if row exists, false otherwise 739 */ 740 @Query( 741 "SELECT ad_selection_id FROM ad_selection WHERE" 742 + " ad_selection_id IN (:adSelectionIds)" 743 + " AND caller_package_name = :callerPackageName " 744 + " UNION" 745 + " SELECT ad_selection_id FROM ad_selection_initialization " 746 + " WHERE ad_selection_id IN (:adSelectionIds) " 747 + " AND caller_package_name = :callerPackageName ") getAdSelectionIdsWithCallerPackageName( List<Long> adSelectionIds, String callerPackageName)748 public abstract List<Long> getAdSelectionIdsWithCallerPackageName( 749 List<Long> adSelectionIds, String callerPackageName); 750 751 /** 752 * Checks if there is a row in the ad_selection_initialization table with the unique key 753 * ad_selection_id and caller package name. 754 * 755 * @param adSelectionIds which is the key to query the corresponding ad selection data. 756 * @param callerPackageName package name which initiated the auction run 757 * @return true if row exists, false otherwise 758 */ 759 @Query( 760 " SELECT ad_selection_id FROM ad_selection_initialization " 761 + " WHERE ad_selection_id IN (:adSelectionIds) " 762 + " AND caller_package_name = :callerPackageName ") getAdSelectionIdsWithCallerPackageNameFromUnifiedTable( List<Long> adSelectionIds, String callerPackageName)763 public abstract List<Long> getAdSelectionIdsWithCallerPackageNameFromUnifiedTable( 764 List<Long> adSelectionIds, String callerPackageName); 765 766 /** 767 * Method used to create an AdSelectionId record in ad selection initialization. 768 * 769 * @return true if row was created in DBAdSelectionInitialization, false otherwise 770 */ 771 @Transaction persistAdSelectionInitialization( long adSelectionId, AdSelectionInitialization adSelectionInitialization)772 public boolean persistAdSelectionInitialization( 773 long adSelectionId, AdSelectionInitialization adSelectionInitialization) { 774 if (doesAdSelectionIdExistInInitializationTable(adSelectionId) 775 || doesAdSelectionIdExist(adSelectionId)) { 776 return false; 777 } 778 DBAdSelectionInitialization dbAdSelectionInitialization = 779 DBAdSelectionInitialization.builder() 780 .setAdSelectionId(adSelectionId) 781 .setCallerPackageName(adSelectionInitialization.getCallerPackageName()) 782 .setSeller(adSelectionInitialization.getSeller()) 783 .setCreationInstant(adSelectionInitialization.getCreationInstant()) 784 .build(); 785 insertDBAdSelectionInitialization(dbAdSelectionInitialization); 786 return true; 787 } 788 789 /** Inserts AdSelectionResult data to {@link DBAdSelectionResult}. */ persistAdSelectionResultForCustomAudience( long adSelectionId, AdSelectionResultBidAndUri adSelectionResult, AdTechIdentifier winningAdBuyer, WinningCustomAudience winningCustomAudience)790 public void persistAdSelectionResultForCustomAudience( 791 long adSelectionId, 792 AdSelectionResultBidAndUri adSelectionResult, 793 AdTechIdentifier winningAdBuyer, 794 WinningCustomAudience winningCustomAudience) { 795 DBWinningCustomAudience dbWinningCustomAudience = 796 DBWinningCustomAudience.builder() 797 .setName(winningCustomAudience.getName()) 798 .setOwner(winningCustomAudience.getOwner()) 799 .setAdCounterIntKeys(winningCustomAudience.getAdCounterKeys()) 800 .build(); 801 802 DBAdSelectionResult dbAdSelectionResult = 803 DBAdSelectionResult.builder() 804 .setAdSelectionId(adSelectionId) 805 .setWinningAdBid(adSelectionResult.getWinningAdBid()) 806 .setWinningAdRenderUri(adSelectionResult.getWinningAdRenderUri()) 807 .setWinningBuyer(winningAdBuyer) 808 .setWinningCustomAudience(dbWinningCustomAudience) 809 .build(); 810 811 insertDBAdSelectionResult(dbAdSelectionResult); 812 } 813 814 /** 815 * Inserts the reporting data to DBReportingData corresponding to the ad selection run with 816 * adselectionId. 817 */ persistReportingData(long adSelectionId, ReportingData reportingData)818 public void persistReportingData(long adSelectionId, ReportingData reportingData) { 819 DBValidator.validateReportingData(reportingData); 820 821 DBReportingData dbReportingData = 822 DBReportingData.builder() 823 .setAdSelectionId(adSelectionId) 824 .setBuyerReportingUri(reportingData.getBuyerWinReportingUri()) 825 .setSellerReportingUri(reportingData.getSellerWinReportingUri()) 826 .build(); 827 828 insertDBReportingData(dbReportingData); 829 } 830 831 /** Reads ReportingData from DB associated with the given adSelectionId. */ getReportingDataForId(long adSelectionId, boolean shouldUseUnifiedTables)832 public ReportingData getReportingDataForId(long adSelectionId, boolean shouldUseUnifiedTables) { 833 if (doesAdSelectionIdExistInInitializationTable(adSelectionId)) { 834 ReportingData uris = getReportingUris(adSelectionId); 835 if (!Objects.isNull(uris)) { 836 // Only return if Uris are found, otherwise try to compute if unified flag is on 837 return uris; 838 } else if (shouldUseUnifiedTables) { 839 DBReportingComputationInfo reportingComputationInfoById = 840 getReportingComputationInfoById(adSelectionId); 841 ReportingComputationData reportingComputationData = 842 ReportingComputationData.builder() 843 .setBuyerDecisionLogicJs( 844 reportingComputationInfoById.getBuyerDecisionLogicJs()) 845 .setBuyerDecisionLogicUri( 846 reportingComputationInfoById.getBiddingLogicUri()) 847 .setSellerContextualSignals( 848 parseAdSelectionSignalsOrEmpty( 849 reportingComputationInfoById 850 .getSellerContextualSignals())) 851 .setBuyerContextualSignals( 852 parseAdSelectionSignalsOrEmpty( 853 reportingComputationInfoById 854 .getBuyerContextualSignals())) 855 .setWinningCustomAudienceSignals( 856 reportingComputationInfoById.getCustomAudienceSignals()) 857 .setWinningRenderUri( 858 reportingComputationInfoById.getWinningAdRenderUri()) 859 .setWinningBid(reportingComputationInfoById.getWinningAdBid()) 860 .build(); 861 return ReportingData.builder() 862 .setReportingComputationData(reportingComputationData) 863 .build(); 864 } 865 } else if (!shouldUseUnifiedTables && doesAdSelectionIdExist(adSelectionId)) { 866 // only look in old tables if unified tables flag is off 867 DBAdSelectionEntry adSelectionEntry = getAdSelectionEntityById(adSelectionId); 868 ReportingComputationData reportingComputationData = 869 ReportingComputationData.builder() 870 .setBuyerDecisionLogicJs(adSelectionEntry.getBuyerDecisionLogicJs()) 871 .setBuyerDecisionLogicUri(adSelectionEntry.getBiddingLogicUri()) 872 .setSellerContextualSignals( 873 parseAdSelectionSignalsOrEmpty( 874 adSelectionEntry.getSellerContextualSignals())) 875 .setBuyerContextualSignals( 876 parseAdSelectionSignalsOrEmpty( 877 adSelectionEntry.getBuyerContextualSignals())) 878 .setWinningCustomAudienceSignals( 879 adSelectionEntry.getCustomAudienceSignals()) 880 .setWinningRenderUri(adSelectionEntry.getWinningAdRenderUri()) 881 .setWinningBid(adSelectionEntry.getWinningAdBid()) 882 .build(); 883 return ReportingData.builder() 884 .setReportingComputationData(reportingComputationData) 885 .build(); 886 } 887 // no reporting Info for this ad selection id 888 return null; 889 } 890 891 /** 892 * Inserts a list of interaction Uri and interaction keys into the database, enforcing these 893 * limitations: 894 * 895 * <p>We will not allow the total size of the {@code registered_ad_interaction} to exceed {@code 896 * maxTotalNumRegisteredInteractions} 897 * 898 * <p>We will not allow the number of registered ad interactions {@code adSelectionId} and 899 * {@code reportingDestination} to exceed {@code maxPerDestinationNumRegisteredInteractions}. 900 */ safelyInsertRegisteredAdInteractionsForDestination( long adSelectionId, @ReportEventRequest.ReportingDestination int reportingDestination, List<RegisteredAdInteraction> adInteractions, long maxTotalNumRegisteredInteractions, long maxPerDestinationNumRegisteredInteractions)901 public void safelyInsertRegisteredAdInteractionsForDestination( 902 long adSelectionId, 903 @ReportEventRequest.ReportingDestination int reportingDestination, 904 List<RegisteredAdInteraction> adInteractions, 905 long maxTotalNumRegisteredInteractions, 906 long maxPerDestinationNumRegisteredInteractions) { 907 List<DBRegisteredAdInteraction> interactions = 908 adInteractions.stream() 909 .map( 910 adInteraction -> 911 DBRegisteredAdInteraction.builder() 912 .setAdSelectionId(adSelectionId) 913 .setDestination(reportingDestination) 914 .setInteractionKey( 915 adInteraction.getInteractionKey()) 916 .setInteractionReportingUri( 917 adInteraction.getInteractionReportingUri()) 918 .build()) 919 .collect(Collectors.toList()); 920 921 safelyInsertRegisteredAdInteractions( 922 adSelectionId, 923 interactions, 924 maxTotalNumRegisteredInteractions, 925 maxPerDestinationNumRegisteredInteractions, 926 reportingDestination); 927 } 928 929 /** Query reporting URI records from DBReportingData if adSelectionId exists. */ 930 @Query( 931 "SELECT buyer_reporting_uri AS buyerWinReportingUri, " 932 + "seller_reporting_uri AS sellerWinReportingUri " 933 + "FROM reporting_data WHERE ad_selection_id = :adSelectionId") getReportingUris(long adSelectionId)934 public abstract ReportingData getReportingUris(long adSelectionId); 935 936 /** Query to fetch caller package name and seller which initialized the ad selection run. */ 937 @Query( 938 "SELECT seller, " 939 + "caller_package_name AS callerPackageName, " 940 + "creation_instant AS creationInstant " 941 + "FROM ad_selection_initialization WHERE ad_selection_id = :adSelectionId") getAdSelectionInitializationForId(long adSelectionId)942 public abstract AdSelectionInitialization getAdSelectionInitializationForId(long adSelectionId); 943 944 /** Query to fetch winning buyer of ad selection run identified by adSelectionId. */ 945 @Query("SELECT winning_buyer FROM ad_selection_result WHERE ad_selection_id = :adSelectionId") getWinningBuyerForId(long adSelectionId)946 public abstract AdTechIdentifier getWinningBuyerForId(long adSelectionId); 947 948 /** Query winning custom audience data of an ad selection run identified by adSelectionId. */ 949 @Query( 950 "SELECT winning_custom_audience_name AS name ," 951 + "winning_custom_audience_owner AS owner, " 952 + "winning_custom_audience_ad_counter_int_keys AS adCounterKeys " 953 + "FROM ad_selection_result " 954 + "WHERE ad_selection_id = :adSelectionId") getWinningCustomAudienceDataForId(long adSelectionId)955 public abstract WinningCustomAudience getWinningCustomAudienceDataForId(long adSelectionId); 956 957 /** Query to get winning ad data of ad selection run identified by adSelectionId. */ 958 @Query( 959 "SELECT ad_selection_id AS adSelectionId, winning_ad_bid AS winningAdBid, " 960 + "winning_ad_render_uri AS winningAdRenderUri FROM ad_selection_result " 961 + "WHERE ad_selection_id = :adSelectionId") getWinningBidAndUriForId(long adSelectionId)962 public abstract AdSelectionResultBidAndUri getWinningBidAndUriForId(long adSelectionId); 963 964 /** Query to get winning ad data of ad selection run identified by adSelectionId. */ 965 @Query( 966 "SELECT ad_selection_id AS adSelectionId, " 967 + "winning_ad_bid AS winningAdBid, " 968 + "winning_ad_render_uri AS winningAdRenderUri " 969 + "FROM ad_selection_result WHERE ad_selection_id IN (:adSelectionIds) " 970 + "UNION " 971 + "SELECT ad_selection_id AS adSelectionId, " 972 + "winning_ad_bid AS winningAdBid, " 973 + "winning_ad_render_uri AS winningAdRenderUri " 974 + "FROM ad_selection WHERE ad_selection_id IN (:adSelectionIds)") getWinningBidAndUriForIds( List<Long> adSelectionIds)975 public abstract List<AdSelectionResultBidAndUri> getWinningBidAndUriForIds( 976 List<Long> adSelectionIds); 977 978 /** 979 * Query the unified table to get winning ad data of ad selection run identified by 980 * adSelectionId. 981 */ 982 @Query( 983 "SELECT ad_selection_id AS adSelectionId, " 984 + "winning_ad_bid AS winningAdBid, " 985 + "winning_ad_render_uri AS winningAdRenderUri " 986 + "FROM ad_selection_result WHERE ad_selection_id IN (:adSelectionIds)") getWinningBidAndUriForIdsUnifiedTables( List<Long> adSelectionIds)987 public abstract List<AdSelectionResultBidAndUri> getWinningBidAndUriForIdsUnifiedTables( 988 List<Long> adSelectionIds); 989 990 /** 991 * Insert new ad selection initialization record. Aborts if adselectionId already exists. 992 * 993 * @param dbAdSelectionInitialization the record keyed by adSelectionId to insert. 994 */ 995 @Insert(onConflict = OnConflictStrategy.ABORT) insertDBAdSelectionInitialization( DBAdSelectionInitialization dbAdSelectionInitialization)996 abstract void insertDBAdSelectionInitialization( 997 DBAdSelectionInitialization dbAdSelectionInitialization); 998 999 /** 1000 * Insert new ad selection result record. Aborts if adselectionId already exists. 1001 * 1002 * @param dbAdSelectionResult the record keyed by adSelectionId to insert. 1003 */ 1004 @Insert(onConflict = OnConflictStrategy.ABORT) insertDBAdSelectionResult(DBAdSelectionResult dbAdSelectionResult)1005 abstract void insertDBAdSelectionResult(DBAdSelectionResult dbAdSelectionResult); 1006 1007 /** Insert new {@link DBReportingComputationInfo} record. */ 1008 @Insert(onConflict = OnConflictStrategy.ABORT) insertDBReportingComputationInfo( DBReportingComputationInfo dbAdSelectionResult)1009 public abstract void insertDBReportingComputationInfo( 1010 DBReportingComputationInfo dbAdSelectionResult); 1011 1012 /** 1013 * Insert a reporting URI record. Aborts if adselectionId already exists. 1014 * 1015 * @param dbReportingData the record keyed by adSelectionId to insert. 1016 */ 1017 @Insert(onConflict = OnConflictStrategy.ABORT) insertDBReportingData(DBReportingData dbReportingData)1018 abstract void insertDBReportingData(DBReportingData dbReportingData); 1019 1020 /** Query to get DBAdSelectionInitialization for the given adSelectionId. */ 1021 @Query("SELECT * FROM ad_selection_initialization WHERE ad_selection_id = :adSelectionId") getDBAdSelectionInitializationForId(long adSelectionId)1022 abstract DBAdSelectionInitialization getDBAdSelectionInitializationForId(long adSelectionId); 1023 1024 /** Query to get DBAdSelectionResult for the given adSelectionId. */ 1025 @Query("SELECT * FROM ad_selection_result WHERE ad_selection_id = :adSelectionId") getDBAdSelectionResultForId(long adSelectionId)1026 abstract DBAdSelectionResult getDBAdSelectionResultForId(long adSelectionId); 1027 1028 /** Query to get DBReportingData for the given adSelectionId. */ 1029 @Query("SELECT * FROM reporting_data WHERE ad_selection_id = :adSelectionId") getDBReportingDataForId(long adSelectionId)1030 abstract DBReportingData getDBReportingDataForId(long adSelectionId); 1031 parseAdSelectionSignalsOrEmpty(String signals)1032 private AdSelectionSignals parseAdSelectionSignalsOrEmpty(String signals) { 1033 return Objects.isNull(signals) 1034 ? AdSelectionSignals.EMPTY 1035 : AdSelectionSignals.fromString(signals); 1036 } 1037 } 1038