blob: 4b92cf7af811b78334be8538c49895ef79e737b4 [file] [log] [blame]
/*
* 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