/* * Copyright (C) 2023 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. */ #include "utils/DbUtils.h" #include #include "android-base/stringprintf.h" #include "storage/StorageManager.h" #include "tests/statsd_test_util.h" #ifdef __ANDROID__ using namespace std; namespace android { namespace os { namespace statsd { namespace dbutils { using base::StringPrintf; namespace { const ConfigKey key = ConfigKey(111, 222); const int64_t metricId = 111; const int32_t tagId = 1; AStatsEvent* makeAStatsEvent(int32_t atomId, int64_t timestampNs) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); return statsEvent; } LogEvent makeLogEvent(AStatsEvent* statsEvent) { LogEvent event(/*uid=*/0, /*pid=*/0); parseStatsEventToLogEvent(statsEvent, &event); return event; } class DbUtilsTest : public ::testing::Test { public: void SetUp() override { if (!isAtLeastU()) { GTEST_SKIP(); } } void TearDown() override { if (!isAtLeastU()) { GTEST_SKIP(); } deleteDb(key); } }; } // Anonymous namespace. TEST_F(DbUtilsTest, TestInsertString) { int64_t eventElapsedTimeNs = 10000000000; AStatsEvent* statsEvent = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeString(statsEvent, "test_string"); LogEvent logEvent = makeLogEvent(statsEvent); vector events{logEvent}; EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent)); string err; EXPECT_TRUE(insert(key, metricId, events, err)); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM metric_111 ORDER BY elapsedTimestampNs"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_THAT(rows[0], ElementsAre("1", to_string(eventElapsedTimeNs + 10), _, "test_string")); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_TEXT)); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); } TEST_F(DbUtilsTest, TestMaliciousString) { int64_t eventElapsedTimeNs = 10000000000; AStatsEvent* statsEvent = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeString(statsEvent, "111); DROP TABLE metric_111;--"); LogEvent logEvent = makeLogEvent(statsEvent); vector events{logEvent}; EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent)); string err; EXPECT_TRUE(insert(key, metricId, events, err)); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM metric_111 ORDER BY elapsedTimestampNs"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_THAT(rows[0], ElementsAre("1", to_string(eventElapsedTimeNs + 10), _, "111); DROP TABLE metric_111;--")); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_TEXT)); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); } TEST_F(DbUtilsTest, TestInsertStringNegativeMetricId) { int64_t eventElapsedTimeNs = 10000000000; int64_t metricId2 = -111; AStatsEvent* statsEvent = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeString(statsEvent, "111"); LogEvent logEvent = makeLogEvent(statsEvent); vector events{logEvent}; EXPECT_TRUE(createTableIfNeeded(key, metricId2, logEvent)); string err; EXPECT_TRUE(insert(key, metricId2, events, err)); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM metric_n111 ORDER BY elapsedTimestampNs"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_THAT(rows[0], ElementsAre("1", to_string(eventElapsedTimeNs + 10), _, "111")); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_TEXT)); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); } TEST_F(DbUtilsTest, TestInsertInteger) { int64_t eventElapsedTimeNs = 10000000000; AStatsEvent* statsEvent = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeInt32(statsEvent, 11); AStatsEvent_writeInt64(statsEvent, 111); LogEvent logEvent = makeLogEvent(statsEvent); vector events{logEvent}; EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent)); string err; EXPECT_TRUE(insert(key, metricId, events, err)); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM metric_111 ORDER BY elapsedTimestampNs"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_THAT(rows[0], ElementsAre("1", to_string(eventElapsedTimeNs + 10), _, "11", "111")); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER)); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1", "field_2")); } TEST_F(DbUtilsTest, TestInsertFloat) { int64_t eventElapsedTimeNs = 10000000000; AStatsEvent* statsEvent = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeFloat(statsEvent, 11.0); LogEvent logEvent = makeLogEvent(statsEvent); vector events{logEvent}; EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent)); string err; EXPECT_TRUE(insert(key, metricId, events, err)); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM metric_111 ORDER BY elapsedTimestampNs"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_THAT(rows[0], ElementsAre("1", to_string(eventElapsedTimeNs + 10), _, _)); EXPECT_FLOAT_EQ(/*field1=*/std::stof(rows[0][3]), 11.0); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_FLOAT)); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); } TEST_F(DbUtilsTest, TestInsertTwoEvents) { int64_t eventElapsedTimeNs = 10000000000; AStatsEvent* statsEvent1 = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeString(statsEvent1, "111"); LogEvent logEvent1 = makeLogEvent(statsEvent1); AStatsEvent* statsEvent2 = makeAStatsEvent(tagId, eventElapsedTimeNs + 20); AStatsEvent_writeString(statsEvent2, "222"); LogEvent logEvent2 = makeLogEvent(statsEvent2); vector events{logEvent1, logEvent2}; EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent1)); string err; EXPECT_TRUE(insert(key, metricId, events, err)); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM metric_111 ORDER BY elapsedTimestampNs"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 2); EXPECT_THAT(rows[0], ElementsAre("1", to_string(eventElapsedTimeNs + 10), _, "111")); EXPECT_THAT(rows[1], ElementsAre("1", to_string(eventElapsedTimeNs + 20), _, "222")); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_TEXT)); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); } TEST_F(DbUtilsTest, TestInsertTwoEventsEnforceTtl) { int64_t eventElapsedTimeNs = 10000000000; int64_t eventWallClockNs = 50000000000; AStatsEvent* statsEvent1 = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeString(statsEvent1, "111"); LogEvent logEvent1 = makeLogEvent(statsEvent1); logEvent1.setLogdWallClockTimestampNs(eventWallClockNs); AStatsEvent* statsEvent2 = makeAStatsEvent(tagId, eventElapsedTimeNs + 20); AStatsEvent_writeString(statsEvent2, "222"); LogEvent logEvent2 = makeLogEvent(statsEvent2); logEvent2.setLogdWallClockTimestampNs(eventWallClockNs + eventElapsedTimeNs); vector events{logEvent1, logEvent2}; EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent1)); sqlite3* db = getDb(key); string err; EXPECT_TRUE(insert(db, metricId, events, err)); EXPECT_TRUE(flushTtl(db, metricId, eventWallClockNs)); closeDb(db); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM metric_111 ORDER BY elapsedTimestampNs"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_THAT(rows[0], ElementsAre("1", to_string(eventElapsedTimeNs + 20), _, "222")); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_TEXT)); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); } TEST_F(DbUtilsTest, TestMaliciousQuery) { int64_t eventElapsedTimeNs = 10000000000; AStatsEvent* statsEvent = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeString(statsEvent, "111"); LogEvent logEvent = makeLogEvent(statsEvent); vector events{logEvent}; EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent)); string err; EXPECT_TRUE(insert(key, metricId, events, err)); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "DROP TABLE metric_111"; EXPECT_FALSE(query(key, zSql, rows, columnTypes, columnNames, err)); EXPECT_THAT(err, StartsWith("attempt to write a readonly database")); } TEST_F(DbUtilsTest, TestInsertStringIntegrityCheckPasses) { int64_t eventElapsedTimeNs = 10000000000; AStatsEvent* statsEvent = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeString(statsEvent, "111"); LogEvent logEvent = makeLogEvent(statsEvent); vector events{logEvent}; EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent)); string err; EXPECT_TRUE(insert(key, metricId, events, err)); verifyIntegrityAndDeleteIfNecessary(key); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM metric_111 ORDER BY elapsedTimestampNs"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_THAT(rows[0], ElementsAre("1", to_string(eventElapsedTimeNs + 10), _, "111")); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_TEXT)); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); } TEST_F(DbUtilsTest, TestInsertStringIntegrityCheckFails) { int64_t eventElapsedTimeNs = 10000000000; AStatsEvent* statsEvent = makeAStatsEvent(tagId, eventElapsedTimeNs + 10); AStatsEvent_writeString(statsEvent, "111"); LogEvent logEvent = makeLogEvent(statsEvent); vector events{logEvent}; EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent)); string err; EXPECT_TRUE(insert(key, metricId, events, err)); string randomData("1232hasha14125ashfas21512sh31321"); string fileName = StringPrintf("%s/%d_%lld.db", STATS_RESTRICTED_DATA_DIR, key.GetUid(), (long long)key.GetId()); StorageManager::writeFile(fileName.c_str(), randomData.data(), randomData.size()); EXPECT_TRUE(StorageManager::hasFile(fileName.c_str())); verifyIntegrityAndDeleteIfNecessary(key); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM metric_111 ORDER BY elapsedTimestampNs"; EXPECT_FALSE(query(key, zSql, rows, columnTypes, columnNames, err)); EXPECT_THAT(err, StartsWith("unable to open database file")); EXPECT_FALSE(StorageManager::hasFile(fileName.c_str())); } TEST_F(DbUtilsTest, TestEventCompatibilityEventMatchesTable) { AStatsEvent* statsEvent = makeAStatsEvent(tagId, /*eventElapsedTime=*/10000000000); AStatsEvent_writeString(statsEvent, "111"); AStatsEvent_writeFloat(statsEvent, 111.0); AStatsEvent_writeInt32(statsEvent, 23); LogEvent logEvent = makeLogEvent(statsEvent); EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent)); EXPECT_TRUE(isEventCompatible(key, metricId, logEvent)); } TEST_F(DbUtilsTest, TestEventCompatibilityEventDoesNotMatchesTable) { AStatsEvent* statsEvent = makeAStatsEvent(tagId, /*eventElapsedTime=*/10000000000); AStatsEvent_writeString(statsEvent, "111"); AStatsEvent_writeFloat(statsEvent, 111.0); AStatsEvent_writeInt32(statsEvent, 23); LogEvent logEvent = makeLogEvent(statsEvent); AStatsEvent* statsEvent2 = makeAStatsEvent(tagId, /*eventElapsedTime=*/10000000000); AStatsEvent_writeString(statsEvent2, "111"); AStatsEvent_writeFloat(statsEvent2, 111.0); AStatsEvent_writeInt32(statsEvent2, 23); AStatsEvent_writeInt32(statsEvent2, 25); LogEvent logEvent2 = makeLogEvent(statsEvent2); EXPECT_TRUE(createTableIfNeeded(key, metricId, logEvent)); EXPECT_FALSE(isEventCompatible(key, metricId, logEvent2)); } TEST_F(DbUtilsTest, TestEventCompatibilityTableNotCreated) { AStatsEvent* statsEvent = makeAStatsEvent(tagId, /*eventElapsedTime=*/10000000000); AStatsEvent_writeString(statsEvent, "111"); AStatsEvent_writeFloat(statsEvent, 111.0); AStatsEvent_writeInt32(statsEvent, 23); LogEvent logEvent = makeLogEvent(statsEvent); EXPECT_TRUE(isEventCompatible(key, metricId, logEvent)); } TEST_F(DbUtilsTest, TestUpdateDeviceInfoTable) { string err; updateDeviceInfoTable(key, err); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM device_info"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_THAT(rows[0], ElementsAre(_, _, _, _, _, _, _, _, _, _)); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT)); EXPECT_THAT(columnNames, ElementsAre("sdkVersion", "model", "product", "hardware", "device", "osBuild", "fingerprint", "brand", "manufacturer", "board")); } TEST_F(DbUtilsTest, TestUpdateDeviceInfoTableInvokeTwice) { string err; updateDeviceInfoTable(key, err); updateDeviceInfoTable(key, err); std::vector columnTypes; std::vector columnNames; std::vector> rows; string zSql = "SELECT * FROM device_info"; EXPECT_TRUE(query(key, zSql, rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_THAT(rows[0], ElementsAre(_, _, _, _, _, _, _, _, _, _)); EXPECT_THAT(columnTypes, ElementsAre(SQLITE_INTEGER, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT, SQLITE_TEXT)); EXPECT_THAT(columnNames, ElementsAre("sdkVersion", "model", "product", "hardware", "device", "osBuild", "fingerprint", "brand", "manufacturer", "board")); } } // namespace dbutils } // namespace statsd } // namespace os } // namespace android #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif