1 /*
2 * Copyright (C) 2019 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 #include "firmware_handler.h"
18
19 #include <stdlib.h>
20 #include <iostream>
21
22 #include <android-base/file.h>
23 #include <gtest/gtest.h>
24
25 #include "uevent.h"
26
27 using android::base::GetExecutablePath;
28 using namespace std::literals;
29
30 namespace android {
31 namespace init {
32
FirmwareTestWithExternalHandler(const std::string & test_name,bool expect_new_firmware)33 void FirmwareTestWithExternalHandler(const std::string& test_name, bool expect_new_firmware) {
34 auto test_path = GetExecutablePath() + " firmware " + test_name;
35 auto external_firmware_handler = ExternalFirmwareHandler(
36 "/devices/led/firmware/test_firmware001.bin", getuid(), test_path);
37
38 auto firmware_handler = FirmwareHandler({"/test"}, {external_firmware_handler});
39
40 auto uevent = Uevent{
41 .path = "/devices/led/firmware/test_firmware001.bin",
42 .firmware = "test_firmware001.bin",
43 };
44
45 if (expect_new_firmware) {
46 EXPECT_EQ("other_firmware001.bin", firmware_handler.GetFirmwarePath(uevent));
47 } else {
48 EXPECT_EQ("test_firmware001.bin", firmware_handler.GetFirmwarePath(uevent));
49 }
50
51 // Always test the base case that the handler isn't invoked if the devpath doesn't match.
52 auto uevent_different_path = Uevent{
53 .path = "/devices/led/not/mine",
54 .firmware = "test_firmware001.bin",
55 };
56 EXPECT_EQ("test_firmware001.bin", firmware_handler.GetFirmwarePath(uevent_different_path));
57 }
58
TEST(firmware_handler,HandleChange)59 TEST(firmware_handler, HandleChange) {
60 FirmwareTestWithExternalHandler("HandleChange", true);
61 }
62
HandleChange(int argc,char ** argv)63 int HandleChange(int argc, char** argv) {
64 // Assert that the environment is set up correctly.
65 if (getenv("DEVPATH") != "/devices/led/firmware/test_firmware001.bin"s) {
66 std::cerr << "$DEVPATH not set correctly" << std::endl;
67 return EXIT_FAILURE;
68 }
69 if (getenv("FIRMWARE") != "test_firmware001.bin"s) {
70 std::cerr << "$FIRMWARE not set correctly" << std::endl;
71 return EXIT_FAILURE;
72 }
73 std::cout << "other_firmware001.bin" << std::endl;
74 return 0;
75 }
76
TEST(firmware_handler,HandleAbort)77 TEST(firmware_handler, HandleAbort) {
78 FirmwareTestWithExternalHandler("HandleAbort", false);
79 }
80
HandleAbort(int argc,char ** argv)81 int HandleAbort(int argc, char** argv) {
82 // Since this is an expected failure, disable debuggerd to not generate a tombstone.
83 signal(SIGABRT, SIG_DFL);
84 abort();
85 return 0;
86 }
87
TEST(firmware_handler,HandleFailure)88 TEST(firmware_handler, HandleFailure) {
89 FirmwareTestWithExternalHandler("HandleFailure", false);
90 }
91
HandleFailure(int argc,char ** argv)92 int HandleFailure(int argc, char** argv) {
93 std::cerr << "Failed" << std::endl;
94 return EXIT_FAILURE;
95 }
96
TEST(firmware_handler,HandleBadPath)97 TEST(firmware_handler, HandleBadPath) {
98 FirmwareTestWithExternalHandler("HandleBadPath", false);
99 }
100
HandleBadPath(int argc,char ** argv)101 int HandleBadPath(int argc, char** argv) {
102 std::cout << "../firmware.bin";
103 return 0;
104 }
105
TEST(firmware_handler,Matching)106 TEST(firmware_handler, Matching) {
107 ExternalFirmwareHandler h("/dev/path/a.bin", getuid(), "/test");
108 ASSERT_TRUE(h.match("/dev/path/a.bin"));
109 ASSERT_FALSE(h.match("/dev/path/a.bi"));
110
111 h = ExternalFirmwareHandler("/dev/path/a.*", getuid(), "/test");
112 ASSERT_TRUE(h.match("/dev/path/a.bin"));
113 ASSERT_TRUE(h.match("/dev/path/a.bix"));
114 ASSERT_FALSE(h.match("/dev/path/b.bin"));
115
116 h = ExternalFirmwareHandler("/dev/*/a.bin", getuid(), "/test");
117 ASSERT_TRUE(h.match("/dev/path/a.bin"));
118 ASSERT_TRUE(h.match("/dev/other/a.bin"));
119 ASSERT_FALSE(h.match("/dev/other/c.bin"));
120 ASSERT_FALSE(h.match("/dev/path/b.bin"));
121 }
122
123 } // namespace init
124 } // namespace android
125
126 // init_test.cpp contains the main entry point for all init tests.
FirmwareTestChildMain(int argc,char ** argv)127 int FirmwareTestChildMain(int argc, char** argv) {
128 if (argc < 3) {
129 return 1;
130 }
131
132 #define RunTest(testname) \
133 if (argv[2] == std::string(#testname)) { \
134 return android::init::testname(argc, argv); \
135 }
136
137 RunTest(HandleChange);
138 RunTest(HandleAbort);
139 RunTest(HandleFailure);
140 RunTest(HandleBadPath);
141
142 #undef RunTest
143 return 1;
144 }
145