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 #define STATSD_DEBUG false  // STOPSHIP if true
18 
19 #include "Log.h"
20 
21 #include "utils/DbUtils.h"
22 
23 #include <android/api-level.h>
24 
25 #include "FieldValue.h"
26 #include "android-base/properties.h"
27 #include "android-base/stringprintf.h"
28 #include "stats_log_util.h"
29 #include "storage/StorageManager.h"
30 
31 namespace android {
32 namespace os {
33 namespace statsd {
34 namespace dbutils {
35 
36 using ::android::os::statsd::FLOAT;
37 using ::android::os::statsd::INT;
38 using ::android::os::statsd::LONG;
39 using ::android::os::statsd::StorageManager;
40 using ::android::os::statsd::STRING;
41 using base::GetProperty;
42 using base::StringPrintf;
43 
44 const string TABLE_NAME_PREFIX = "metric_";
45 const string COLUMN_NAME_ATOM_TAG = "atomId";
46 const string COLUMN_NAME_EVENT_ELAPSED_CLOCK_NS = "elapsedTimestampNs";
47 const string COLUMN_NAME_EVENT_WALL_CLOCK_NS = "wallTimestampNs";
48 
49 const string COLUMN_NAME_SDK_VERSION = "sdkVersion";
50 const string COLUMN_NAME_MODEL = "model";
51 const string COLUMN_NAME_PRODUCT = "product";
52 const string COLUMN_NAME_HARDWARE = "hardware";
53 const string COLUMN_NAME_DEVICE = "device";
54 const string COLUMN_NAME_BUILD = "osBuild";
55 const string COLUMN_NAME_FINGERPRINT = "fingerprint";
56 const string COLUMN_NAME_BRAND = "brand";
57 const string COLUMN_NAME_MANUFACTURER = "manufacturer";
58 const string COLUMN_NAME_BOARD = "board";
59 
getExpectedTableSchema(const LogEvent & logEvent)60 static std::vector<std::string> getExpectedTableSchema(const LogEvent& logEvent) {
61     vector<std::string> result;
62     for (const FieldValue& fieldValue : logEvent.getValues()) {
63         if (fieldValue.mField.getDepth() > 0) {
64             // Repeated fields are not supported.
65             continue;
66         }
67         switch (fieldValue.mValue.getType()) {
68             case INT:
69             case LONG:
70                 result.push_back("INTEGER");
71                 break;
72             case STRING:
73                 result.push_back("TEXT");
74                 break;
75             case FLOAT:
76                 result.push_back("REAL");
77                 break;
78             default:
79                 // Byte array fields are not supported.
80                 break;
81         }
82     }
83     return result;
84 }
85 
integrityCheckCallback(void *,int colCount,char ** queryResults,char **)86 static int integrityCheckCallback(void*, int colCount, char** queryResults, char**) {
87     if (colCount == 0 || strcmp(queryResults[0], "ok") != 0) {
88         // Returning 1 is an error code that causes exec to stop and error.
89         return 1;
90     }
91     return 0;
92 }
93 
getDbName(const ConfigKey & key)94 string getDbName(const ConfigKey& key) {
95     return StringPrintf("%s/%d_%lld.db", STATS_RESTRICTED_DATA_DIR, key.GetUid(),
96                         (long long)key.GetId());
97 }
98 
getCreateSqlString(const int64_t metricId,const LogEvent & event)99 static string getCreateSqlString(const int64_t metricId, const LogEvent& event) {
100     string result = StringPrintf("CREATE TABLE IF NOT EXISTS %s%s", TABLE_NAME_PREFIX.c_str(),
101                                  reformatMetricId(metricId).c_str());
102     result += StringPrintf("(%s INTEGER,%s INTEGER,%s INTEGER,", COLUMN_NAME_ATOM_TAG.c_str(),
103                            COLUMN_NAME_EVENT_ELAPSED_CLOCK_NS.c_str(),
104                            COLUMN_NAME_EVENT_WALL_CLOCK_NS.c_str());
105     for (size_t fieldId = 1; fieldId <= event.getValues().size(); ++fieldId) {
106         const FieldValue& fieldValue = event.getValues()[fieldId - 1];
107         if (fieldValue.mField.getDepth() > 0) {
108             // Repeated fields are not supported.
109             continue;
110         }
111         switch (fieldValue.mValue.getType()) {
112             case INT:
113             case LONG:
114                 result += StringPrintf("field_%d INTEGER,", fieldValue.mField.getPosAtDepth(0));
115                 break;
116             case STRING:
117                 result += StringPrintf("field_%d TEXT,", fieldValue.mField.getPosAtDepth(0));
118                 break;
119             case FLOAT:
120                 result += StringPrintf("field_%d REAL,", fieldValue.mField.getPosAtDepth(0));
121                 break;
122             default:
123                 // Byte array fields are not supported.
124                 break;
125         }
126     }
127     result.pop_back();
128     result += ") STRICT;";
129     return result;
130 }
131 
reformatMetricId(const int64_t metricId)132 string reformatMetricId(const int64_t metricId) {
133     return metricId < 0 ? StringPrintf("n%lld", (long long)metricId * -1)
134                         : StringPrintf("%lld", (long long)metricId);
135 }
136 
createTableIfNeeded(const ConfigKey & key,const int64_t metricId,const LogEvent & event)137 bool createTableIfNeeded(const ConfigKey& key, const int64_t metricId, const LogEvent& event) {
138     const string dbName = getDbName(key);
139     sqlite3* db;
140     if (sqlite3_open(dbName.c_str(), &db) != SQLITE_OK) {
141         sqlite3_close(db);
142         return false;
143     }
144 
145     char* error = nullptr;
146     string zSql = getCreateSqlString(metricId, event);
147     sqlite3_exec(db, zSql.c_str(), nullptr, nullptr, &error);
148     sqlite3_close(db);
149     if (error) {
150         ALOGW("Failed to create table to db: %s", error);
151         return false;
152     }
153     return true;
154 }
155 
isEventCompatible(const ConfigKey & key,const int64_t metricId,const LogEvent & event)156 bool isEventCompatible(const ConfigKey& key, const int64_t metricId, const LogEvent& event) {
157     const string dbName = getDbName(key);
158     sqlite3* db;
159     if (sqlite3_open(dbName.c_str(), &db) != SQLITE_OK) {
160         sqlite3_close(db);
161         return false;
162     }
163     string zSql = StringPrintf("PRAGMA table_info(metric_%s);", reformatMetricId(metricId).c_str());
164     string err;
165     std::vector<int32_t> columnTypes;
166     std::vector<string> columnNames;
167     std::vector<std::vector<std::string>> rows;
168     if (!query(key, zSql, rows, columnTypes, columnNames, err)) {
169         ALOGE("Failed to check table schema for metric %lld: %s", (long long)metricId, err.c_str());
170         sqlite3_close(db);
171         return false;
172     }
173     // Sample query result
174     // cid  name               type     notnull  dflt_value  pk
175     // ---  -----------------  -------  -------  ----------  --
176     // 0    atomId             INTEGER  0        (null)      0
177     // 1    elapsedTimestampNs INTEGER  0        (null)      0
178     // 2    wallTimestampNs    INTEGER  0        (null)      0
179     // 3    field_1            INTEGER  0        (null)      0
180     // 4    field_2            TEXT     0        (null)      0
181     std::vector<string> tableSchema;
182     for (size_t i = 3; i < rows.size(); ++i) {  // Atom fields start at the third row
183         tableSchema.push_back(rows[i][2]);  // The third column stores the data type for the column
184     }
185     sqlite3_close(db);
186     // An empty rows vector implies the table has not yet been created.
187     return rows.size() == 0 || getExpectedTableSchema(event) == tableSchema;
188 }
189 
deleteTable(const ConfigKey & key,const int64_t metricId)190 bool deleteTable(const ConfigKey& key, const int64_t metricId) {
191     const string dbName = getDbName(key);
192     sqlite3* db;
193     if (sqlite3_open(dbName.c_str(), &db) != SQLITE_OK) {
194         sqlite3_close(db);
195         return false;
196     }
197     string zSql = StringPrintf("DROP TABLE metric_%s", reformatMetricId(metricId).c_str());
198     char* error = nullptr;
199     sqlite3_exec(db, zSql.c_str(), nullptr, nullptr, &error);
200     sqlite3_close(db);
201     if (error) {
202         ALOGW("Failed to drop table from db: %s", error);
203         return false;
204     }
205     return true;
206 }
207 
deleteDb(const ConfigKey & key)208 void deleteDb(const ConfigKey& key) {
209     const string dbName = getDbName(key);
210     StorageManager::deleteFile(dbName.c_str());
211 }
212 
getDb(const ConfigKey & key)213 sqlite3* getDb(const ConfigKey& key) {
214     const string dbName = getDbName(key);
215     sqlite3* db;
216     if (sqlite3_open(dbName.c_str(), &db) == SQLITE_OK) {
217         return db;
218     }
219     return nullptr;
220 }
221 
closeDb(sqlite3 * db)222 void closeDb(sqlite3* db) {
223     sqlite3_close(db);
224 }
225 
getInsertSqlStmt(sqlite3 * db,sqlite3_stmt ** stmt,const int64_t metricId,const vector<LogEvent> & events,string & err)226 static bool getInsertSqlStmt(sqlite3* db, sqlite3_stmt** stmt, const int64_t metricId,
227                              const vector<LogEvent>& events, string& err) {
228     string result =
229             StringPrintf("INSERT INTO metric_%s VALUES", reformatMetricId(metricId).c_str());
230     for (auto& logEvent : events) {
231         result += StringPrintf("(%d, %lld, %lld,", logEvent.GetTagId(),
232                                (long long)logEvent.GetElapsedTimestampNs(),
233                                (long long)logEvent.GetLogdTimestampNs());
234         for (auto& fieldValue : logEvent.getValues()) {
235             if (fieldValue.mField.getDepth() > 0 || fieldValue.mValue.getType() == STORAGE) {
236                 // Repeated fields and byte fields are not supported.
237                 continue;
238             }
239             result += "?,";
240         }
241         result.pop_back();
242         result += "),";
243     }
244     result.pop_back();
245     result += ";";
246     if (sqlite3_prepare_v2(db, result.c_str(), -1, stmt, nullptr) != SQLITE_OK) {
247         err = sqlite3_errmsg(db);
248         return false;
249     }
250     // ? parameters start with an index of 1 from start of query string to the
251     // end.
252     int32_t index = 1;
253     for (auto& logEvent : events) {
254         for (auto& fieldValue : logEvent.getValues()) {
255             if (fieldValue.mField.getDepth() > 0 || fieldValue.mValue.getType() == STORAGE) {
256                 // Repeated fields and byte fields are not supported.
257                 continue;
258             }
259             switch (fieldValue.mValue.getType()) {
260                 case INT:
261                     sqlite3_bind_int(*stmt, index, fieldValue.mValue.int_value);
262                     break;
263                 case LONG:
264                     sqlite3_bind_int64(*stmt, index, fieldValue.mValue.long_value);
265                     break;
266                 case STRING:
267                     sqlite3_bind_text(*stmt, index, fieldValue.mValue.str_value.c_str(), -1,
268                                       SQLITE_STATIC);
269                     break;
270                 case FLOAT:
271                     sqlite3_bind_double(*stmt, index, fieldValue.mValue.float_value);
272                     break;
273                 default:
274                     // Byte array fields are not supported.
275                     break;
276             }
277             ++index;
278         }
279     }
280     return true;
281 }
282 
insert(const ConfigKey & key,const int64_t metricId,const vector<LogEvent> & events,string & error)283 bool insert(const ConfigKey& key, const int64_t metricId, const vector<LogEvent>& events,
284             string& error) {
285     const string dbName = getDbName(key);
286     sqlite3* db;
287     if (sqlite3_open(dbName.c_str(), &db) != SQLITE_OK) {
288         error = sqlite3_errmsg(db);
289         sqlite3_close(db);
290         return false;
291     }
292     bool success = insert(db, metricId, events, error);
293     sqlite3_close(db);
294     return success;
295 }
296 
insert(sqlite3 * db,const int64_t metricId,const vector<LogEvent> & events,string & error)297 bool insert(sqlite3* db, const int64_t metricId, const vector<LogEvent>& events, string& error) {
298     sqlite3_stmt* stmt = nullptr;
299     if (!getInsertSqlStmt(db, &stmt, metricId, events, error)) {
300         ALOGW("Failed to generate prepared sql insert query %s", error.c_str());
301         sqlite3_finalize(stmt);
302         return false;
303     }
304     if (sqlite3_step(stmt) != SQLITE_DONE) {
305         error = sqlite3_errmsg(db);
306         ALOGW("Failed to insert data to db: %s", error.c_str());
307         sqlite3_finalize(stmt);
308         return false;
309     }
310     sqlite3_finalize(stmt);
311     return true;
312 }
313 
query(const ConfigKey & key,const string & zSql,vector<vector<string>> & rows,vector<int32_t> & columnTypes,vector<string> & columnNames,string & err)314 bool query(const ConfigKey& key, const string& zSql, vector<vector<string>>& rows,
315            vector<int32_t>& columnTypes, vector<string>& columnNames, string& err) {
316     const string dbName = getDbName(key);
317     sqlite3* db;
318     if (sqlite3_open_v2(dbName.c_str(), &db, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) {
319         err = sqlite3_errmsg(db);
320         sqlite3_close(db);
321         return false;
322     }
323     sqlite3_stmt* stmt;
324     if (sqlite3_prepare_v2(db, zSql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
325         err = sqlite3_errmsg(db);
326         sqlite3_finalize(stmt);
327         sqlite3_close(db);
328         return false;
329     }
330     int result = sqlite3_step(stmt);
331     bool firstIter = true;
332     while (result == SQLITE_ROW) {
333         int colCount = sqlite3_column_count(stmt);
334         vector<string> rowData(colCount);
335         for (int i = 0; i < colCount; ++i) {
336             if (firstIter) {
337                 int32_t columnType = sqlite3_column_type(stmt, i);
338                 // Needed to convert to java compatible cursor types. See AbstractCursor#getType()
339                 if (columnType == 5) {
340                     columnType = 0;  // Remap 5 (null type) to 0 for java cursor
341                 }
342                 columnTypes.push_back(columnType);
343                 columnNames.push_back(reinterpret_cast<const char*>(sqlite3_column_name(stmt, i)));
344             }
345             const unsigned char* textResult = sqlite3_column_text(stmt, i);
346             string colData =
347                     textResult != nullptr ? string(reinterpret_cast<const char*>(textResult)) : "";
348             rowData[i] = std::move(colData);
349         }
350         rows.push_back(std::move(rowData));
351         firstIter = false;
352         result = sqlite3_step(stmt);
353     }
354     sqlite3_finalize(stmt);
355     if (result != SQLITE_DONE) {
356         err = sqlite3_errmsg(db);
357         sqlite3_close(db);
358         return false;
359     }
360     sqlite3_close(db);
361     return true;
362 }
363 
flushTtl(sqlite3 * db,const int64_t metricId,const int64_t ttlWallClockNs)364 bool flushTtl(sqlite3* db, const int64_t metricId, const int64_t ttlWallClockNs) {
365     string zSql = StringPrintf("DELETE FROM %s%s WHERE %s <= %lld", TABLE_NAME_PREFIX.c_str(),
366                                reformatMetricId(metricId).c_str(),
367                                COLUMN_NAME_EVENT_WALL_CLOCK_NS.c_str(), (long long)ttlWallClockNs);
368 
369     char* error = nullptr;
370     sqlite3_exec(db, zSql.c_str(), nullptr, nullptr, &error);
371     if (error) {
372         ALOGW("Failed to enforce ttl: %s", error);
373         return false;
374     }
375     return true;
376 }
377 
verifyIntegrityAndDeleteIfNecessary(const ConfigKey & configKey)378 void verifyIntegrityAndDeleteIfNecessary(const ConfigKey& configKey) {
379     const string dbName = getDbName(configKey);
380     sqlite3* db;
381     if (sqlite3_open(dbName.c_str(), &db) != SQLITE_OK) {
382         sqlite3_close(db);
383         return;
384     }
385     string zSql = "PRAGMA integrity_check";
386 
387     char* error = nullptr;
388     sqlite3_exec(db, zSql.c_str(), integrityCheckCallback, nullptr, &error);
389     if (error) {
390         StatsdStats::getInstance().noteDbCorrupted(configKey);
391         ALOGW("Integrity Check failed %s", error);
392         sqlite3_close(db);
393         deleteDb(configKey);
394         return;
395     }
396     sqlite3_close(db);
397 }
398 
getDeviceInfoInsertStmt(sqlite3 * db,sqlite3_stmt ** stmt,string error)399 static bool getDeviceInfoInsertStmt(sqlite3* db, sqlite3_stmt** stmt, string error) {
400     string insertSql = StringPrintf("INSERT INTO device_info VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
401     if (sqlite3_prepare_v2(db, insertSql.c_str(), -1, stmt, nullptr) != SQLITE_OK) {
402         error = sqlite3_errmsg(db);
403         return false;
404     }
405 
406     // ? parameters start with an index of 1 from start of query string to the end.
407     int32_t index = 1;
408 
409     int32_t sdkVersion = android_get_device_api_level();
410     sqlite3_bind_int(*stmt, index, sdkVersion);
411     ++index;
412 
413     string model = GetProperty("ro.product.model", "(unknown)");
414     sqlite3_bind_text(*stmt, index, model.c_str(), -1, SQLITE_TRANSIENT);
415     ++index;
416 
417     string product = GetProperty("ro.product.name", "(unknown)");
418     sqlite3_bind_text(*stmt, index, product.c_str(), -1, SQLITE_TRANSIENT);
419     ++index;
420 
421     string hardware = GetProperty("ro.hardware", "(unknown)");
422     sqlite3_bind_text(*stmt, index, hardware.c_str(), -1, SQLITE_TRANSIENT);
423     ++index;
424 
425     string device = GetProperty("ro.product.device", "(unknown)");
426     sqlite3_bind_text(*stmt, index, device.c_str(), -1, SQLITE_TRANSIENT);
427     ++index;
428 
429     string osBuild = GetProperty("ro.build.id", "(unknown)");
430     sqlite3_bind_text(*stmt, index, osBuild.c_str(), -1, SQLITE_TRANSIENT);
431     ++index;
432 
433     string fingerprint = GetProperty("ro.build.fingerprint", "(unknown)");
434     sqlite3_bind_text(*stmt, index, fingerprint.c_str(), -1, SQLITE_TRANSIENT);
435     ++index;
436 
437     string brand = GetProperty("ro.product.brand", "(unknown)");
438     sqlite3_bind_text(*stmt, index, brand.c_str(), -1, SQLITE_TRANSIENT);
439     ++index;
440 
441     string manufacturer = GetProperty("ro.product.manufacturer", "(unknown)");
442     sqlite3_bind_text(*stmt, index, manufacturer.c_str(), -1, SQLITE_TRANSIENT);
443     ++index;
444 
445     string board = GetProperty("ro.product.board", "(unknown)");
446     sqlite3_bind_text(*stmt, index, board.c_str(), -1, SQLITE_TRANSIENT);
447     ++index;
448 
449     return true;
450 }
451 
updateDeviceInfoTable(const ConfigKey & key,string & error)452 bool updateDeviceInfoTable(const ConfigKey& key, string& error) {
453     const string dbName = getDbName(key);
454     sqlite3* db;
455     if (sqlite3_open(dbName.c_str(), &db) != SQLITE_OK) {
456         error = sqlite3_errmsg(db);
457         sqlite3_close(db);
458         return false;
459     }
460 
461     string dropTableSql = "DROP TABLE device_info";
462     // Ignore possible error result code if table has not yet been created.
463     sqlite3_exec(db, dropTableSql.c_str(), nullptr, nullptr, nullptr);
464 
465     string createTableSql = StringPrintf(
466             "CREATE TABLE device_info(%s INTEGER, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s "
467             "TEXT, %s TEXT, %s TEXT, %s TEXT) "
468             "STRICT",
469             COLUMN_NAME_SDK_VERSION.c_str(), COLUMN_NAME_MODEL.c_str(), COLUMN_NAME_PRODUCT.c_str(),
470             COLUMN_NAME_HARDWARE.c_str(), COLUMN_NAME_DEVICE.c_str(), COLUMN_NAME_BUILD.c_str(),
471             COLUMN_NAME_FINGERPRINT.c_str(), COLUMN_NAME_BRAND.c_str(),
472             COLUMN_NAME_MANUFACTURER.c_str(), COLUMN_NAME_BOARD.c_str());
473     if (sqlite3_exec(db, createTableSql.c_str(), nullptr, nullptr, nullptr) != SQLITE_OK) {
474         error = sqlite3_errmsg(db);
475         ALOGW("Failed to create device info table %s", error.c_str());
476         sqlite3_close(db);
477         return false;
478     }
479 
480     sqlite3_stmt* stmt = nullptr;
481     if (!getDeviceInfoInsertStmt(db, &stmt, error)) {
482         ALOGW("Failed to generate device info prepared sql insert query %s", error.c_str());
483         sqlite3_finalize(stmt);
484         sqlite3_close(db);
485         return false;
486     }
487 
488     if (sqlite3_step(stmt) != SQLITE_DONE) {
489         error = sqlite3_errmsg(db);
490         ALOGW("Failed to insert data to device info table: %s", error.c_str());
491         sqlite3_finalize(stmt);
492         sqlite3_close(db);
493         return false;
494     }
495     sqlite3_finalize(stmt);
496     sqlite3_close(db);
497     return true;
498 }
499 }  // namespace dbutils
500 }  // namespace statsd
501 }  // namespace os
502 }  // namespace android
503