| /* |
| * Copyright (C) 2019 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 "common/debug.h" |
| #include "maintenance/controller.h" |
| |
| #include "db/file_models.h" |
| #include "db/models.h" |
| |
| #include <cstdio> |
| #include <filesystem> |
| #include <fstream> |
| #include <string> |
| #include <vector> |
| |
| #include <android-base/file.h> |
| #include <gtest/gtest.h> |
| #include <gmock/gmock.h> |
| |
| using ::testing::Return; |
| using ::testing::_; |
| using ::testing::SaveArg; |
| using ::testing::SaveArgPointee; |
| |
| namespace iorap::maintenance { |
| |
| static std::string GetTestDataPath(const std::string& fn) { |
| static std::string exec_dir = android::base::GetExecutableDirectory(); |
| return exec_dir + "/tests/src/maintenance/testdata/" + fn; |
| } |
| |
| class MockExec : public IExec { |
| public: |
| MOCK_METHOD(int, |
| Execve, |
| (const std::string& pathname, std::vector<std::string>& argv_vec, char *const envp[]), |
| (override)); |
| |
| MOCK_METHOD(pid_t, Fork, (), (override)); |
| }; |
| |
| class ControllerTest: public ::testing::Test { |
| protected: |
| void SetUp() override { |
| // The db is a fake db with the following tables: |
| // |
| // packages: |
| // id, name, version |
| // 1, com.android.settings, 1 |
| // 2, com.yawanng, 1 |
| // |
| // activities: |
| // id, name |
| // 1, Setting |
| // 2, yawanng |
| // |
| // app_launch_histories: |
| // id, activity_id, temperature, trace_enabled, readahead_enabled, intent_start_ns, total_time_ns, report_fully_drawn_ns |
| // 1, 1, 1, 1, 1, 1, 2, NULL |
| // 2, 1, 1, 1, 1, NULL, 4, 5 |
| // 3, 1, 1, 1, 1, 3, NULL, NULL |
| // 4, 1, 1, 1, 1, 3, 7, 8 |
| // 5, 1, 1, 0, 1, 4, 9, 10 |
| // 6, 1, 2, 1, 1, 5, 11, 12 |
| // 7, 2, 1, 1, 1, 6, 21, 22 |
| // 8, 2, 1, 1, 1, 7, 22, 23 |
| // |
| // raw_traces: |
| // id, history_id, file_path |
| // 1, 1, 1.txt |
| // 2, 3, 3.txt |
| // 3, 4, 4.txt |
| // 4, 5, 5.txt |
| // 5, 6, 6.txt |
| // 6, 7, 7.txt |
| // 7, 8, 8.txt |
| db_path = GetTestDataPath("test_sqlite.db"); |
| } |
| |
| std::string db_path; |
| TemporaryDir root_path; |
| }; |
| |
| MATCHER_P(AreArgsExpected, compiled_trace_path, "") { |
| std::vector<std::string> expect = |
| { "1.txt", |
| "3.txt", |
| "4.txt", |
| "--timestamp_limit_ns", "2", |
| "--timestamp_limit_ns", "18446744073709551615", |
| "--timestamp_limit_ns", "8", |
| "--pid", |
| "1", |
| "--pid", |
| "3", |
| "--pid", |
| "4", |
| "--output-text", |
| "--output-proto", compiled_trace_path, |
| "--verbose" }; |
| return arg == expect; |
| } |
| |
| MATCHER_P(AreArgsExpectedNoDex, compiled_trace_path, "") { |
| std::vector<std::string> expect = |
| { "1.txt", |
| "3.txt", |
| "4.txt", |
| "--timestamp_limit_ns", "2", |
| "--timestamp_limit_ns", "18446744073709551615", |
| "--timestamp_limit_ns", "8", |
| "--pid", |
| "1", |
| "--pid", |
| "3", |
| "--pid", |
| "4", |
| "--output-text", |
| "--output-proto", compiled_trace_path, |
| "--verbose", |
| "--denylist-filter", |
| "[.](art|oat|odex|vdex|dex)$"}; |
| return arg == expect; |
| } |
| |
| TEST_F(ControllerTest, CompilationController) { |
| auto mock_exec = std::make_shared<MockExec>(); |
| iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path); |
| db::DbHandle db{db_schema.db()}; |
| |
| setenv("IORAPD_ROOT_DIR", root_path.path ,1); |
| std::string compiled_trace_path = std::string(root_path.path) + |
| "/com.android.settings/1/Setting/compiled_traces/compiled_trace.pb"; |
| |
| // No recompile |
| ControllerParameters params{ |
| /*output_text=*/true, |
| /*inode_textcache=*/std::nullopt, |
| /*verbose=*/true, |
| /*recompile=*/false, |
| /*min_traces=*/3, |
| mock_exec, |
| /*exclude_dex_files=*/false}; |
| |
| ON_CALL(*mock_exec, Fork()) |
| .WillByDefault(Return(-2)); |
| |
| EXPECT_CALL(*mock_exec, |
| Execve("/system/bin/iorap.cmd.compiler", |
| AreArgsExpected(compiled_trace_path), |
| nullptr)) |
| .Times(2); |
| |
| CompileAppsOnDevice(db, params); |
| |
| // Recompile |
| ControllerParameters params2{ |
| /*output_text=*/true, |
| /*inode_textcache=*/std::nullopt, |
| /*verbose=*/true, |
| /*recompile=*/true, |
| /*min_traces=*/3, |
| mock_exec, |
| /*exclude_dex_files=*/false}; |
| |
| // Create a fake compiled trace file to test recompile. |
| std::ofstream tmp_file; |
| tmp_file.open(compiled_trace_path); |
| tmp_file.close(); |
| |
| CompileAppsOnDevice(db, params2); |
| |
| // Recompile |
| ControllerParameters params3{ |
| /*output_text=*/true, |
| /*inode_textcache=*/std::nullopt, |
| /*verbose=*/true, |
| /*recompile=*/true, |
| /*min_traces=*/3, |
| mock_exec, |
| /*exclude_dex_files=*/true}; |
| |
| EXPECT_CALL(*mock_exec, |
| Execve("/system/bin/iorap.cmd.compiler", |
| AreArgsExpectedNoDex(compiled_trace_path), |
| nullptr)) |
| .Times(1); |
| |
| CompileAppsOnDevice(db, params3); |
| } |
| |
| } // namespace iorap::maintenance |