Only the exact same devpath uevent can launch external handler specified in ueventd.rc. So, you should specify all possible devpaths, even firmware with different filenames on the same device. Pattern mactching can be used to simplify this. Test: atest CtsInitTestCases Signed-off-by: Suchang Woo <suchang.woo@samsung.com> Change-Id: If3b7a2cabb8055bf4b768d928f0fc0012da3c177
353 lines
12 KiB
C++
353 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2018 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 "ueventd_parser.h"
|
|
|
|
#include <android-base/file.h>
|
|
#include <gtest/gtest.h>
|
|
#include <private/android_filesystem_config.h>
|
|
|
|
#include "firmware_handler.h"
|
|
|
|
namespace android {
|
|
namespace init {
|
|
|
|
void TestSubsystems(const Subsystem& expected, const Subsystem& test) {
|
|
EXPECT_EQ(expected.name_, test.name_);
|
|
EXPECT_EQ(expected.devname_source_, test.devname_source_) << expected.name_;
|
|
EXPECT_EQ(expected.dir_name_, test.dir_name_) << expected.name_;
|
|
}
|
|
|
|
void TestPermissions(const Permissions& expected, const Permissions& test) {
|
|
EXPECT_EQ(expected.name_, test.name_);
|
|
EXPECT_EQ(expected.perm_, test.perm_) << expected.name_;
|
|
EXPECT_EQ(expected.uid_, test.uid_) << expected.name_;
|
|
EXPECT_EQ(expected.gid_, test.gid_) << expected.name_;
|
|
EXPECT_EQ(expected.prefix_, test.prefix_) << expected.name_;
|
|
EXPECT_EQ(expected.wildcard_, test.wildcard_) << expected.name_;
|
|
}
|
|
|
|
void TestSysfsPermissions(const SysfsPermissions& expected, const SysfsPermissions& test) {
|
|
TestPermissions(expected, test);
|
|
EXPECT_EQ(expected.attribute_, test.attribute_);
|
|
}
|
|
|
|
void TestExternalFirmwareHandler(const ExternalFirmwareHandler& expected,
|
|
const ExternalFirmwareHandler& test) {
|
|
EXPECT_EQ(expected.devpath, test.devpath) << expected.devpath;
|
|
EXPECT_EQ(expected.uid, test.uid) << expected.uid;
|
|
EXPECT_EQ(expected.handler_path, test.handler_path) << expected.handler_path;
|
|
}
|
|
|
|
template <typename T, typename F>
|
|
void TestVector(const T& expected, const T& test, F function) {
|
|
ASSERT_EQ(expected.size(), test.size());
|
|
auto expected_it = expected.begin();
|
|
auto test_it = test.begin();
|
|
|
|
for (; expected_it != expected.end(); ++expected_it, ++test_it) {
|
|
function(*expected_it, *test_it);
|
|
}
|
|
}
|
|
|
|
void TestUeventdFile(const std::string& content, const UeventdConfiguration& expected) {
|
|
TemporaryFile tf;
|
|
ASSERT_TRUE(tf.fd != -1);
|
|
ASSERT_TRUE(android::base::WriteStringToFd(content, tf.fd));
|
|
|
|
auto result = ParseConfig({tf.path});
|
|
|
|
TestVector(expected.subsystems, result.subsystems, TestSubsystems);
|
|
TestVector(expected.sysfs_permissions, result.sysfs_permissions, TestSysfsPermissions);
|
|
TestVector(expected.dev_permissions, result.dev_permissions, TestPermissions);
|
|
EXPECT_EQ(expected.firmware_directories, result.firmware_directories);
|
|
TestVector(expected.external_firmware_handlers, result.external_firmware_handlers,
|
|
TestExternalFirmwareHandler);
|
|
}
|
|
|
|
TEST(ueventd_parser, EmptyFile) {
|
|
TestUeventdFile("", {});
|
|
}
|
|
|
|
TEST(ueventd_parser, Subsystems) {
|
|
auto ueventd_file = R"(
|
|
subsystem test_devname
|
|
devname uevent_devname
|
|
|
|
subsystem test_devpath_no_dirname
|
|
devname uevent_devpath
|
|
|
|
subsystem test_devname2
|
|
devname uevent_devname
|
|
|
|
subsystem test_devpath_dirname
|
|
devname uevent_devpath
|
|
dirname /dev/graphics
|
|
)";
|
|
|
|
auto subsystems = std::vector<Subsystem>{
|
|
{"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
|
|
{"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"},
|
|
{"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
|
|
{"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};
|
|
|
|
TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}, {}});
|
|
}
|
|
|
|
TEST(ueventd_parser, Permissions) {
|
|
auto ueventd_file = R"(
|
|
/dev/rtc0 0640 system system
|
|
/dev/graphics/* 0660 root graphics
|
|
/dev/*/test 0660 root system
|
|
|
|
/sys/devices/platform/trusty.* trusty_version 0440 root log
|
|
/sys/devices/virtual/input/input enable 0660 root input
|
|
/sys/devices/virtual/*/input poll_delay 0660 root input no_fnm_pathname
|
|
)";
|
|
|
|
auto permissions = std::vector<Permissions>{
|
|
{"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM, false},
|
|
{"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS, false},
|
|
{"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM, false},
|
|
};
|
|
|
|
auto sysfs_permissions = std::vector<SysfsPermissions>{
|
|
{"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG, false},
|
|
{"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT, false},
|
|
{"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT, true},
|
|
};
|
|
|
|
TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}, {}});
|
|
}
|
|
|
|
TEST(ueventd_parser, FirmwareDirectories) {
|
|
auto ueventd_file = R"(
|
|
firmware_directories /first/ /second /third
|
|
firmware_directories /more
|
|
)";
|
|
|
|
auto firmware_directories = std::vector<std::string>{
|
|
"/first/",
|
|
"/second",
|
|
"/third",
|
|
"/more",
|
|
};
|
|
|
|
TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories, {}});
|
|
}
|
|
|
|
TEST(ueventd_parser, ExternalFirmwareHandlers) {
|
|
auto ueventd_file = R"(
|
|
external_firmware_handler devpath root handler_path
|
|
external_firmware_handler /devices/path/firmware/something001.bin system /vendor/bin/firmware_handler.sh
|
|
external_firmware_handler /devices/path/firmware/something002.bin radio "/vendor/bin/firmware_handler.sh --has --arguments"
|
|
external_firmware_handler /devices/path/firmware/* root "/vendor/bin/firmware_handler.sh"
|
|
external_firmware_handler /devices/path/firmware/something* system "/vendor/bin/firmware_handler.sh"
|
|
external_firmware_handler /devices/path/*/firmware/something*.bin radio "/vendor/bin/firmware_handler.sh"
|
|
)";
|
|
|
|
auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
|
|
{
|
|
"devpath",
|
|
AID_ROOT,
|
|
"handler_path",
|
|
},
|
|
{
|
|
"/devices/path/firmware/something001.bin",
|
|
AID_SYSTEM,
|
|
"/vendor/bin/firmware_handler.sh",
|
|
},
|
|
{
|
|
"/devices/path/firmware/something002.bin",
|
|
AID_RADIO,
|
|
"/vendor/bin/firmware_handler.sh --has --arguments",
|
|
},
|
|
{
|
|
"/devices/path/firmware/",
|
|
AID_ROOT,
|
|
"/vendor/bin/firmware_handler.sh",
|
|
},
|
|
{
|
|
"/devices/path/firmware/something",
|
|
AID_SYSTEM,
|
|
"/vendor/bin/firmware_handler.sh",
|
|
},
|
|
{
|
|
"/devices/path/*/firmware/something*.bin",
|
|
AID_RADIO,
|
|
"/vendor/bin/firmware_handler.sh",
|
|
},
|
|
};
|
|
|
|
TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});
|
|
}
|
|
|
|
TEST(ueventd_parser, ExternalFirmwareHandlersDuplicate) {
|
|
auto ueventd_file = R"(
|
|
external_firmware_handler devpath root handler_path
|
|
external_firmware_handler devpath root handler_path2
|
|
)";
|
|
|
|
auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
|
|
{
|
|
"devpath",
|
|
AID_ROOT,
|
|
"handler_path",
|
|
},
|
|
};
|
|
|
|
TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});
|
|
}
|
|
|
|
TEST(ueventd_parser, UeventSocketRcvbufSize) {
|
|
auto ueventd_file = R"(
|
|
uevent_socket_rcvbuf_size 8k
|
|
uevent_socket_rcvbuf_size 8M
|
|
)";
|
|
|
|
TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, false, 8 * 1024 * 1024});
|
|
}
|
|
|
|
TEST(ueventd_parser, EnabledDisabledLines) {
|
|
auto ueventd_file = R"(
|
|
modalias_handling enabled
|
|
parallel_restorecon enabled
|
|
modalias_handling disabled
|
|
)";
|
|
|
|
TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, false, 0, true});
|
|
|
|
auto ueventd_file2 = R"(
|
|
parallel_restorecon enabled
|
|
modalias_handling enabled
|
|
parallel_restorecon disabled
|
|
)";
|
|
|
|
TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, {}, true, 0, false});
|
|
}
|
|
|
|
TEST(ueventd_parser, AllTogether) {
|
|
auto ueventd_file = R"(
|
|
|
|
/dev/rtc0 0640 system system
|
|
firmware_directories /first/ /second /third
|
|
/sys/devices/platform/trusty.* trusty_version 0440 root log
|
|
|
|
subsystem test_devname
|
|
devname uevent_devname
|
|
|
|
/dev/graphics/* 0660 root graphics
|
|
|
|
subsystem test_devpath_no_dirname
|
|
devname uevent_devpath
|
|
|
|
/sys/devices/virtual/input/input enable 0660 root input
|
|
|
|
## this is a comment
|
|
|
|
subsystem test_devname2
|
|
## another comment
|
|
devname uevent_devname
|
|
|
|
subsystem test_devpath_dirname
|
|
devname uevent_devpath
|
|
dirname /dev/graphics
|
|
|
|
/dev/*/test 0660 root system
|
|
/sys/devices/virtual/*/input poll_delay 0660 root input no_fnm_pathname
|
|
firmware_directories /more
|
|
|
|
external_firmware_handler /devices/path/firmware/firmware001.bin root /vendor/bin/touch.sh
|
|
|
|
uevent_socket_rcvbuf_size 6M
|
|
modalias_handling enabled
|
|
parallel_restorecon enabled
|
|
|
|
#ending comment
|
|
)";
|
|
|
|
auto subsystems = std::vector<Subsystem>{
|
|
{"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
|
|
{"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"},
|
|
{"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
|
|
{"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};
|
|
|
|
auto permissions = std::vector<Permissions>{
|
|
{"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM, false},
|
|
{"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS, false},
|
|
{"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM, false},
|
|
};
|
|
|
|
auto sysfs_permissions = std::vector<SysfsPermissions>{
|
|
{"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG, false},
|
|
{"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT, false},
|
|
{"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT, true},
|
|
};
|
|
|
|
auto firmware_directories = std::vector<std::string>{
|
|
"/first/",
|
|
"/second",
|
|
"/third",
|
|
"/more",
|
|
};
|
|
|
|
auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
|
|
{"/devices/path/firmware/firmware001.bin", AID_ROOT, "/vendor/bin/touch.sh"},
|
|
};
|
|
|
|
size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024;
|
|
|
|
TestUeventdFile(ueventd_file,
|
|
{subsystems, sysfs_permissions, permissions, firmware_directories,
|
|
external_firmware_handlers, true, uevent_socket_rcvbuf_size, true});
|
|
}
|
|
|
|
// All of these lines are ill-formed, so test that there is 0 output.
|
|
TEST(ueventd_parser, ParseErrors) {
|
|
auto ueventd_file = R"(
|
|
|
|
/dev/rtc0 badmode baduidbad system
|
|
/dev/rtc0 0640 baduidbad system
|
|
/dev/rtc0 0640 system baduidbad
|
|
firmware_directories #no directory listed
|
|
/sys/devices/platform/trusty.* trusty_version badmode root log
|
|
/sys/devices/platform/trusty.* trusty_version 0440 baduidbad log
|
|
/sys/devices/platform/trusty.* trusty_version 0440 root baduidbad
|
|
/sys/devices/platform/trusty.* trusty_version 0440 root root bad_option
|
|
|
|
uevent_socket_rcvbuf_size blah
|
|
|
|
subsystem #no name
|
|
|
|
modalias_handling
|
|
modalias_handling enabled enabled
|
|
modalias_handling blah
|
|
|
|
parallel_restorecon
|
|
parallel_restorecon enabled enabled
|
|
parallel_restorecon blah
|
|
|
|
external_firmware_handler
|
|
external_firmware_handler blah blah
|
|
external_firmware_handler blah blah blah blah
|
|
|
|
)";
|
|
|
|
TestUeventdFile(ueventd_file, {});
|
|
}
|
|
|
|
} // namespace init
|
|
} // namespace android
|