Add a sample service for testing init.
I find myself using something like this every time I add functionality to init. I cannot possibly be the only one doing this. On the other hand, if this hasn't been added for so long, maybe there's a reason for that. The advantage of using a test service versus modifying an existing service is that the test service doesn't *require* any permissions or privileges, so you can add and/or remove whatever you need to test without breaking the service. I found it useful to have the service check its own /proc/<pid>/status from command-line arguments, so that's what the service does. This CL also adds a .clang-format file for init. Bug: None Test: Service runs and exits successfully. Change-Id: I3e7841a7283158e10c0bf55e0103c03902afb1f0
This commit is contained in:
parent
23f4e6b0a5
commit
28e980b59c
6 changed files with 174 additions and 0 deletions
14
init/.clang-format
Normal file
14
init/.clang-format
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
ColumnLimit: 100
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
IndentWidth: 4
|
||||
Standard: Auto
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
...
|
|
@ -134,3 +134,8 @@ LOCAL_SANITIZE := integer
|
|||
LOCAL_CLANG := true
|
||||
LOCAL_CPPFLAGS := -Wall -Wextra -Werror
|
||||
include $(BUILD_NATIVE_TEST)
|
||||
|
||||
|
||||
# Include targets in subdirs.
|
||||
# =========================================================
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||
|
|
27
init/test_service/Android.mk
Normal file
27
init/test_service/Android.mk
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Copyright (C) 2016 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.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# Sample service for testing.
|
||||
# =========================================================
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := test_service
|
||||
LOCAL_SRC_FILES := test_service.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += libbase
|
||||
|
||||
LOCAL_INIT_RC := test_service.rc
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
43
init/test_service/README.md
Normal file
43
init/test_service/README.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Sample service for testing
|
||||
This is a sample service that can be used for testing init.
|
||||
|
||||
## Design
|
||||
The service includes a `.rc` file that allows starting it from init.
|
||||
|
||||
service test_service /system/bin/test_service CapAmb 0000000000003000
|
||||
class main
|
||||
user system
|
||||
group system
|
||||
capabilities NET_ADMIN NET_RAW
|
||||
disabled
|
||||
oneshot
|
||||
|
||||
The service accepts any even number of arguments on the command line
|
||||
(i.e. any number of pairs of arguments.)
|
||||
It will attempt to find the first element of each pair of arguments in
|
||||
`/proc/self/status`, and attempt to exactly match the second element of the pair
|
||||
to the relevant line of `proc/self/status`.
|
||||
|
||||
### Example
|
||||
In the above case, the service will look for lines containing `CapAmb`:
|
||||
|
||||
cat /proc/self/status
|
||||
...
|
||||
CapAmb: 0000000000003000
|
||||
|
||||
And then attempt to exactly match the token after `:`, `0000000000003000`,
|
||||
with the command-line argument.
|
||||
If they match, the service exits successfully. If not, the service will exit
|
||||
with an error.
|
||||
|
||||
## Usage
|
||||
mmma -j <jobs> system/core/init/testservice
|
||||
adb root
|
||||
adb remount
|
||||
adb sync
|
||||
adb reboot
|
||||
adb root
|
||||
adb shell start test_service
|
||||
adb logcat -b all -d | grep test_service
|
||||
|
||||
Look for an exit status of 0.
|
78
init/test_service/test_service.cpp
Normal file
78
init/test_service/test_service.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Copyright (C) 2016 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 <unistd.h>
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
void Usage(char* argv[]) {
|
||||
printf("Usage: %s <status field> <value> [<status field> <value>]*\n", argv[0]);
|
||||
printf("E.g.: $ %s Uid \"1000 1000 1000 1000\"\n", argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
Usage(argv);
|
||||
LOG(FATAL) << "no status field requested";
|
||||
}
|
||||
if (argc % 2 == 0) {
|
||||
// Since |argc| counts argv[0], if |argc| is odd, then the number of
|
||||
// command-line arguments is even.
|
||||
Usage(argv);
|
||||
LOG(FATAL) << "need even number of command-line arguments";
|
||||
}
|
||||
|
||||
std::string status;
|
||||
bool res = android::base::ReadFileToString("/proc/self/status", &status, true);
|
||||
if (!res) {
|
||||
PLOG(FATAL) << "could not read /proc/self/status";
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> fields;
|
||||
std::vector<std::string> lines = android::base::Split(status, "\n");
|
||||
for (const auto& line : lines) {
|
||||
std::vector<std::string> tokens = android::base::Split(line, ":");
|
||||
if (tokens.size() >= 2) {
|
||||
std::string field = tokens[0];
|
||||
std::string value = android::base::Trim(tokens[1]);
|
||||
if (field.length() > 0) {
|
||||
fields[field] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool test_fails = false;
|
||||
size_t uargc = static_cast<size_t>(argc); // |argc| >= 3.
|
||||
for (size_t i = 1; i < static_cast<size_t>(argc); i = i + 2) {
|
||||
std::string expected_value = argv[i + 1];
|
||||
auto f = fields.find(argv[i]);
|
||||
if (f != fields.end()) {
|
||||
if (f->second != expected_value) {
|
||||
LOG(ERROR) << "field '" << argv[i] << "' expected '" << expected_value
|
||||
<< "', actual '" << f->second << "'";
|
||||
test_fails = true;
|
||||
}
|
||||
} else {
|
||||
LOG(WARNING) << "could not find field '" << argv[i] << "'";
|
||||
}
|
||||
}
|
||||
|
||||
return test_fails ? 1 : 0;
|
||||
}
|
7
init/test_service/test_service.rc
Normal file
7
init/test_service/test_service.rc
Normal file
|
@ -0,0 +1,7 @@
|
|||
service test_service /system/bin/test_service CapAmb 0000000000003000
|
||||
class main
|
||||
user system
|
||||
group system
|
||||
capabilities NET_ADMIN NET_RAW
|
||||
disabled
|
||||
oneshot
|
Loading…
Reference in a new issue