summaryrefslogtreecommitdiff
path: root/adservices/service-core/java/com/android/adservices/data/adselection/AdSelectionEntryDao.java
blob: 03aa50f5e026d4801c9afbe458f8eb4d641b545f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.adservices.data.adselection;

import android.net.Uri;

import androidx.annotation.Nullable;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;

import java.time.Instant;
import java.util.List;

/**
 * Data Access Object interface for access to the local AdSelection data storage.
 *
 * <p>Annotation will generate Room based SQLite Dao implementation.
 */
@Dao
public interface AdSelectionEntryDao {
    /**
     * Add a new successful ad selection entry into the table ad_selection.
     *
     * @param adSelection is the AdSelection to add to the table ad_selection if the ad_selection_id
     *     not exists.
     */
    // TODO(b/230568647): retry adSelectionId generation in case of collision
    @Insert(onConflict = OnConflictStrategy.ABORT)
    void persistAdSelection(DBAdSelection adSelection);

    /**
     * Write a buyer decision logic entry into the table buyer_decision_logic.
     *
     * @param buyerDecisionLogic is the BuyerDecisionLogic to write to table buyer_decision_logic.
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void persistBuyerDecisionLogic(DBBuyerDecisionLogic buyerDecisionLogic);

    /**
     * Add an ad selection override into the table ad_selection_overrides
     *
     * @param adSelectionOverride is the AdSelectionOverride to add to table ad_selection_overrides.
     *     If a {@link DBAdSelectionOverride} object with the {@code adSelectionConfigId} already
     *     exists, this will replace the existing object.
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void persistAdSelectionOverride(DBAdSelectionOverride adSelectionOverride);

    /**
     * Checks if there is a row in the ad selection data with the unique key ad_selection_id
     *
     * @param adSelectionId which is the key to query the corresponding ad selection data.
     * @return true if row exists, false otherwise
     */
    @Query(
            "SELECT EXISTS(SELECT 1 FROM ad_selection WHERE ad_selection_id = :adSelectionId LIMIT"
                    + " 1)")
    boolean doesAdSelectionIdExist(long adSelectionId);

    /**
     * Checks if there is a row in the buyer decision logic data with the unique key
     * bidding_logic_uri
     *
     * @param biddingLogicUri which is the key to query the corresponding buyer decision logic data.
     * @return true if row exists, false otherwise
     */
    @Query(
            "SELECT EXISTS(SELECT 1 FROM buyer_decision_logic WHERE bidding_logic_uri ="
                    + " :biddingLogicUri LIMIT 1)")
    boolean doesBuyerDecisionLogicExist(Uri biddingLogicUri);

    /**
     * Checks if there is a row in the ad selection override data with the unique key
     * ad_selection_config_id
     *
     * @param adSelectionConfigId which is the key to query the corresponding ad selection override
     *     data.
     * @return true if row exists, false otherwise
     */
    @Query(
            "SELECT EXISTS(SELECT 1 FROM ad_selection_overrides WHERE ad_selection_config_id ="
                    + " :adSelectionConfigId AND app_package_name = :appPackageName LIMIT 1)")
    boolean doesAdSelectionOverrideExistForPackageName(
            String adSelectionConfigId, String appPackageName);

    /**
     * Get the ad selection entry by its unique key ad_selection_id.
     *
     * @param adSelectionId which is the key to query the corresponding ad selection entry.
     * @return an {@link DBAdSelectionEntry} if exists.
     */
    @Query(
            "SELECT ad_selection.ad_selection_id as ad_selection_id,"
                + " ad_selection.custom_audience_signals_owner as custom_audience_signals_owner,"
                + " ad_selection.custom_audience_signals_buyer as custom_audience_signals_buyer,"
                + " ad_selection.custom_audience_signals_name as custom_audience_signals_name,"
                + " ad_selection.custom_audience_signals_activation_time as"
                + " custom_audience_signals_activation_time,"
                + " ad_selection.custom_audience_signals_expiration_time as"
                + " custom_audience_signals_expiration_time,"
                + " ad_selection.custom_audience_signals_user_bidding_signals as"
                + " custom_audience_signals_user_bidding_signals, ad_selection.contextual_signals"
                + " as contextual_signals,ad_selection.winning_ad_render_uri as"
                + " winning_ad_render_uri,ad_selection.winning_ad_bid as"
                + " winning_ad_bid,ad_selection.creation_timestamp as"
                + " creation_timestamp,buyer_decision_logic.buyer_decision_logic_js as"
                + " buyer_decision_logic_js FROM ad_selection LEFT JOIN buyer_decision_logic ON"
                + " ad_selection.bidding_logic_uri = buyer_decision_logic.bidding_logic_uri WHERE"
                + " ad_selection.ad_selection_id = :adSelectionId")
    DBAdSelectionEntry getAdSelectionEntityById(long adSelectionId);

    /**
     * Get the ad selection entries with a batch of ad_selection_ids.
     *
     * @param adSelectionIds are the list of keys to query the corresponding ad selection entries.
     * @return ad selection entries if exists.
     */
    @Query(
            "SELECT ad_selection.ad_selection_id AS"
                + " ad_selection_id,ad_selection.custom_audience_signals_owner as"
                + " custom_audience_signals_owner, ad_selection.custom_audience_signals_buyer as"
                + " custom_audience_signals_buyer, ad_selection.custom_audience_signals_name as"
                + " custom_audience_signals_name,"
                + " ad_selection.custom_audience_signals_activation_time as"
                + " custom_audience_signals_activation_time,"
                + " ad_selection.custom_audience_signals_expiration_time as"
                + " custom_audience_signals_expiration_time,"
                + " ad_selection.custom_audience_signals_user_bidding_signals as"
                + " custom_audience_signals_user_bidding_signals, ad_selection.contextual_signals"
                + " AS contextual_signals,ad_selection.winning_ad_render_uri AS"
                + " winning_ad_render_uri,ad_selection.winning_ad_bid AS winning_ad_bid,"
                + " ad_selection.creation_timestamp as creation_timestamp,"
                + " buyer_decision_logic.buyer_decision_logic_js AS buyer_decision_logic_js FROM"
                + " ad_selection LEFT JOIN buyer_decision_logic ON ad_selection.bidding_logic_uri"
                + " = buyer_decision_logic.bidding_logic_uri WHERE ad_selection.ad_selection_id IN"
                + " (:adSelectionIds) ")
    List<DBAdSelectionEntry> getAdSelectionEntities(List<Long> adSelectionIds);

    /**
     * Get ad selection JS override by its unique key and the package name of the app that created
     * the override.
     *
     * @return ad selection override result if exists.
     */
    @Query(
            "SELECT decision_logic FROM ad_selection_overrides WHERE ad_selection_config_id ="
                    + " :adSelectionConfigId AND app_package_name = :appPackageName")
    @Nullable
    String getDecisionLogicOverride(String adSelectionConfigId, String appPackageName);

    /**
     * Get ad selection trusted scoring signals override by its unique key and the package name of
     * the app that created the override.
     *
     * @return ad selection override result if exists.
     */
    @Query(
            "SELECT trusted_scoring_signals FROM ad_selection_overrides WHERE"
                    + " ad_selection_config_id = :adSelectionConfigId AND app_package_name ="
                    + " :appPackageName")
    @Nullable
    String getTrustedScoringSignalsOverride(String adSelectionConfigId, String appPackageName);

    /**
     * Clean up expired adSelection entries if it is older than the given timestamp. If
     * creation_timestamp < expirationTime, the ad selection entry will be removed from the
     * ad_selection table.
     *
     * @param expirationTime is the cutoff time to expire the AdSelectionEntry.
     */
    @Query("DELETE FROM ad_selection WHERE creation_timestamp < :expirationTime")
    void removeExpiredAdSelection(Instant expirationTime);

    /**
     * Clean up selected ad selection data entry data in batch by their ad_selection_ids.
     *
     * @param adSelectionIds is the list of adSelectionIds to identify the data entries to be
     *     removed from ad_selection and buyer_decision_logic tables.
     */
    @Query("DELETE FROM ad_selection WHERE ad_selection_id IN (:adSelectionIds)")
    void removeAdSelectionEntriesByIds(List<Long> adSelectionIds);

    /**
     * Clean up selected ad selection override data by its {@code adSelectionConfigId}
     *
     * @param adSelectionConfigId is the {@code adSelectionConfigId} to identify the data entries to
     *     be removed from the ad_selection_overrides table.
     */
    @Query(
            "DELETE FROM ad_selection_overrides WHERE ad_selection_config_id = :adSelectionConfigId"
                    + " AND app_package_name = :appPackageName")
    void removeAdSelectionOverrideByIdAndPackageName(
            String adSelectionConfigId, String appPackageName);

    /**
     * Clean up buyer_decision_logic entries in batch if the bidding_logic_uri no longer exists in
     * the table ad_selection.
     */
    @Query(
            "DELETE FROM buyer_decision_logic WHERE bidding_logic_uri NOT IN "
                    + "( SELECT DISTINCT bidding_logic_uri "
                    + "FROM ad_selection "
                    + "WHERE bidding_logic_uri is NOT NULL)")
    void removeExpiredBuyerDecisionLogic();

    /** Clean up all ad selection override data */
    @Query("DELETE FROM ad_selection_overrides WHERE  app_package_name = :appPackageName")
    void removeAllAdSelectionOverrides(String appPackageName);

    /**
     * Checks if there is a row in the ad selection data with the unique combination of
     * ad_selection_id and caller_package_name
     *
     * @param adSelectionId which is the key to query the corresponding ad selection data.
     * @param callerPackageName the caller's package name, to be verified against the
     *     calling_package_name that exists in the ad_selection_entry
     * @return true if row exists, false otherwise
     */
    @Query(
            "SELECT EXISTS(SELECT 1 FROM ad_selection WHERE ad_selection_id = :adSelectionId"
                    + " AND caller_package_name = :callerPackageName LIMIT"
                    + " 1)")
    boolean doesAdSelectionMatchingCallerPackageNameExist(
            long adSelectionId, String callerPackageName);
}