• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.ondevicepersonalization.services.util;
18 
19 import android.adservices.ondevicepersonalization.Constants;
20 import android.adservices.ondevicepersonalization.EventLogRecord;
21 import android.adservices.ondevicepersonalization.RequestLogRecord;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.ComponentName;
25 import android.content.ContentValues;
26 import android.content.Context;
27 import android.os.SystemClock;
28 
29 import com.android.odp.module.common.PackageUtils;
30 import com.android.ondevicepersonalization.internal.util.LoggerFactory;
31 import com.android.ondevicepersonalization.services.OnDevicePersonalizationApplication;
32 import com.android.ondevicepersonalization.services.data.DbUtils;
33 import com.android.ondevicepersonalization.services.data.events.Event;
34 import com.android.ondevicepersonalization.services.data.events.EventsDao;
35 import com.android.ondevicepersonalization.services.data.events.Query;
36 import com.android.ondevicepersonalization.services.statsd.OdpStatsdLogger;
37 
38 import com.google.common.util.concurrent.Futures;
39 import com.google.common.util.concurrent.ListenableFuture;
40 
41 import java.util.ArrayList;
42 import java.util.List;
43 
44 /** Utilities for logging */
45 public class LogUtils {
46     private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger();
47     private static final String TAG = "LogUtils";
48 
49     /** Writes the provided records to the REQUESTS and EVENTS tables. */
writeLogRecords( int taskType, @NonNull Context context, @NonNull String appPackageName, @NonNull ComponentName service, @Nullable RequestLogRecord requestLogRecord, @Nullable List<EventLogRecord> eventLogRecords)50     public static ListenableFuture<Long> writeLogRecords(
51             int taskType,
52             @NonNull Context context,
53             @NonNull String appPackageName,
54             @NonNull ComponentName service,
55             @Nullable RequestLogRecord requestLogRecord,
56             @Nullable List<EventLogRecord> eventLogRecords) {
57         long logStartedTimeMills = SystemClock.elapsedRealtime();
58         sLogger.d(TAG + ": writeLogRecords() started.");
59         try {
60             String serviceName = DbUtils.toTableValue(service);
61             String certDigest =
62                     PackageUtils.getCertDigest(
63                             OnDevicePersonalizationApplication.getAppContext(),
64                             service.getPackageName());
65             EventsDao eventsDao = EventsDao.getInstance(context);
66             // Insert query
67             long queryId = -1;
68             if (requestLogRecord != null) {
69                 List<ContentValues> rows = requestLogRecord.getRows();
70                 if (rows.isEmpty()) {
71                     rows = List.of(new ContentValues());
72                     logTraceEventStats(
73                             taskType,
74                             Constants.EVENT_TYPE_WRITE_REQUEST_LOG,
75                             Constants.STATUS_REQUEST_LOG_IS_EMPTY,
76                             SystemClock.elapsedRealtime() - logStartedTimeMills,
77                             service.getPackageName());
78                 }
79                 byte[] queryData = OnDevicePersonalizationFlatbufferUtils.createQueryData(
80                         serviceName, certDigest, rows);
81                 Query query = new Query.Builder(
82                         System.currentTimeMillis(),
83                         appPackageName,
84                         service,
85                         certDigest,
86                         queryData).build();
87                 queryId = eventsDao.insertQuery(query);
88                 if (queryId == -1) {
89                     logTraceEventStats(
90                             taskType,
91                             Constants.EVENT_TYPE_WRITE_REQUEST_LOG,
92                             Constants.STATUS_LOG_DB_FAILURE,
93                             SystemClock.elapsedRealtime() - logStartedTimeMills,
94                             service.getPackageName());
95                     return Futures.immediateFailedFuture(
96                             new RuntimeException("Failed to insert request log record."));
97                 } else {
98                     logTraceEventStats(
99                             taskType,
100                             Constants.EVENT_TYPE_WRITE_REQUEST_LOG,
101                             Constants.STATUS_REQUEST_LOG_DB_SUCCESS,
102                             SystemClock.elapsedRealtime() - logStartedTimeMills,
103                             service.getPackageName());
104                 }
105             } else {
106                 logTraceEventStats(
107                         taskType,
108                         Constants.EVENT_TYPE_WRITE_REQUEST_LOG,
109                         Constants.STATUS_REQUEST_LOG_IS_NULL,
110                         SystemClock.elapsedRealtime() - logStartedTimeMills,
111                         service.getPackageName());
112             }
113 
114             // Insert events
115             if (eventLogRecords == null || eventLogRecords.size() == 0) {
116                 logTraceEventStats(
117                         taskType,
118                         Constants.EVENT_TYPE_WRITE_EVENT_LOG,
119                         Constants.STATUS_EVENT_LOG_IS_NULL,
120                         SystemClock.elapsedRealtime() - logStartedTimeMills,
121                         service.getPackageName());
122                 return Futures.immediateFuture(queryId);
123             }
124             List<Event> events = new ArrayList<>();
125             for (EventLogRecord eventLogRecord : eventLogRecords) {
126                 RequestLogRecord parent;
127                 long parentRequestId;
128                 if (eventLogRecord.getRequestLogRecord() != null) {
129                     parent = eventLogRecord.getRequestLogRecord();
130                     parentRequestId = parent.getRequestId();
131                 } else {
132                     parent = requestLogRecord;
133                     parentRequestId = queryId;
134                 }
135                 // Verify requestLogRecord exists and has the corresponding rowIndex
136                 if (parent == null || parentRequestId <= 0
137                         || eventLogRecord.getRowIndex() >= parent.getRows().size()) {
138                     logTraceEventStats(
139                             taskType,
140                             Constants.EVENT_TYPE_WRITE_EVENT_LOG,
141                             Constants.STATUS_EVENT_LOG_NOT_EXIST,
142                             SystemClock.elapsedRealtime() - logStartedTimeMills,
143                             service.getPackageName());
144                     continue;
145                 }
146                 // Make sure query exists for package in QUERY table and
147                 // rowIndex <= written row count.
148                 Query queryRow = eventsDao.readSingleQueryRow(parentRequestId, service);
149                 if (queryRow == null || eventLogRecord.getRowIndex()
150                         >= OnDevicePersonalizationFlatbufferUtils
151                                 .getContentValuesLengthFromQueryData(
152                                         queryRow.getQueryData())) {
153                     logTraceEventStats(
154                             taskType,
155                             Constants.EVENT_TYPE_WRITE_EVENT_LOG,
156                             Constants.STATUS_EVENT_LOG_QUERY_NOT_EXIST,
157                             SystemClock.elapsedRealtime() - logStartedTimeMills,
158                             service.getPackageName());
159                     continue;
160                 }
161                 Event event = new Event.Builder()
162                         .setEventData(OnDevicePersonalizationFlatbufferUtils.createEventData(
163                                 eventLogRecord.getData()))
164                         .setQueryId(parentRequestId)
165                         .setRowIndex(eventLogRecord.getRowIndex())
166                         .setService(service)
167                         .setTimeMillis(System.currentTimeMillis())
168                         .setType(eventLogRecord.getType())
169                         .build();
170                 events.add(event);
171             }
172             if (!eventsDao.insertEvents(events)) {
173                 logTraceEventStats(
174                         taskType,
175                         Constants.EVENT_TYPE_WRITE_EVENT_LOG,
176                         Constants.STATUS_LOG_DB_FAILURE,
177                         SystemClock.elapsedRealtime() - logStartedTimeMills,
178                         service.getPackageName());
179                 return Futures.immediateFailedFuture(
180                         new RuntimeException("Failed to insert events log record."));
181             } else {
182                 logTraceEventStats(
183                         taskType,
184                         Constants.EVENT_TYPE_WRITE_EVENT_LOG,
185                         Constants.STATUS_EVENT_LOG_DB_SUCCESS,
186                         SystemClock.elapsedRealtime() - logStartedTimeMills,
187                         service.getPackageName());
188             }
189             return Futures.immediateFuture(queryId);
190         } catch (Exception e) {
191             logTraceEventStats(
192                     taskType,
193                     Constants.EVENT_TYPE_UNKNOWN,
194                     Constants.STATUS_LOG_EXCEPTION,
195                     SystemClock.elapsedRealtime() - logStartedTimeMills,
196                     service.getPackageName());
197             return Futures.immediateFailedFuture(e);
198         }
199     }
200 
logTraceEventStats(int taskType, int eventType, int status, long latencyMillis, String servicePackageName)201     private static void logTraceEventStats(int taskType, int eventType, int status,
202             long latencyMillis, String servicePackageName) {
203         OdpStatsdLogger.getInstance()
204                 .logTraceEventStats(taskType, eventType, status, latencyMillis, servicePackageName);
205     }
206 
LogUtils()207     private LogUtils() {}
208 }
209