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