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