platform_system_core/init/Android.bp
Tom Cherry de09d52328 init: introduce Result<T> for return values and error handling
init tries to propagate error information up to build context before
logging errors.  This is a good thing, however too often init has the
overly verbose paradigm for error handling, below:

bool CalculateResult(const T& input, U* output, std::string* err)

bool CalculateAndUseResult(const T& input, std::string* err) {
  U output;
  std::string calculate_result_err;
  if (!CalculateResult(input, &output, &calculate_result_err)) {
    *err = "CalculateResult " + input + " failed: " +
      calculate_result_err;
      return false;
  }
  UseResult(output);
  return true;
}

Even more common are functions that return only true/false but also
require passing a std::string* err in order to see the error message.

This change introduces a Result<T> that is use to either hold a
successful return value of type T or to hold an error message as a
std::string.  If the functional only returns success or a failure with
an error message, Result<Success> may be used.  The classes Error and
ErrnoError are used to indicate a failed Result<T>.

A successful Result<T> is constructed implicitly from any type that
can be implicitly converted to T or from the constructor arguments for
T.  This allows you to return a type T directly from a function that
returns Result<T>.

Error and ErrnoError are used to construct a Result<T> has
failed. Each of these classes take an ostream as an input and are
implicitly cast to a Result<T> containing that failure.  ErrnoError()
additionally appends ": " + strerror(errno) to the end of  the failure
string to aid in interacting with C APIs.

The end result is that the above code snippet is turned into the much
clearer example below:

Result<U> CalculateResult(const T& input);

Result<Success> CalculateAndUseResult(const T& input) {
  auto output = CalculateResult(input);
  if (!output) {
    return Error() << "CalculateResult " << input << " failed: "
                   << output.error();
  }
  UseResult(*output);
  return Success();
}

This change also makes this conversion for some of the util.cpp
functions that used the old paradigm.

Test: boot bullhead, init unit tests
Change-Id: I1e7d3a8820a79362245041251057fbeed2f7979b
2017-08-14 10:25:14 -07:00

178 lines
4.2 KiB
Text

//
// Copyright (C) 2017 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.
//
cc_defaults {
name: "init_defaults",
cpp_std: "experimental",
sanitize: {
misc_undefined: ["signed-integer-overflow"],
},
cppflags: [
"-DLOG_UEVENTS=0",
"-Wall",
"-Wextra",
"-Wno-unused-parameter",
"-Werror",
"-DALLOW_LOCAL_PROP_OVERRIDE=0",
"-DALLOW_PERMISSIVE_SELINUX=0",
"-DREBOOT_BOOTLOADER_ON_PANIC=0",
"-DWORLD_WRITABLE_KMSG=0",
"-DDUMP_ON_UMOUNT_FAILURE=0",
"-DSHUTDOWN_ZERO_TIMEOUT=0",
],
product_variables: {
debuggable: {
cppflags: [
"-UALLOW_LOCAL_PROP_OVERRIDE",
"-DALLOW_LOCAL_PROP_OVERRIDE=1",
"-UALLOW_PERMISSIVE_SELINUX",
"-DALLOW_PERMISSIVE_SELINUX=1",
"-UREBOOT_BOOTLOADER_ON_PANIC",
"-DREBOOT_BOOTLOADER_ON_PANIC=1",
"-UWORLD_WRITABLE_KMSG",
"-DWORLD_WRITABLE_KMSG=1",
"-UDUMP_ON_UMOUNT_FAILURE",
"-DDUMP_ON_UMOUNT_FAILURE=1",
],
},
eng: {
cppflags: [
"-USHUTDOWN_ZERO_TIMEOUT",
"-DSHUTDOWN_ZERO_TIMEOUT=1",
],
},
},
}
cc_library_static {
name: "libinit",
defaults: ["init_defaults"],
srcs: [
"action.cpp",
"capabilities.cpp",
"descriptors.cpp",
"devices.cpp",
"firmware_handler.cpp",
"import_parser.cpp",
"log.cpp",
"parser.cpp",
"property_service.cpp",
"security.cpp",
"selinux.cpp",
"service.cpp",
"tokenizer.cpp",
"uevent_listener.cpp",
"ueventd_parser.cpp",
"util.cpp",
],
whole_static_libs: ["libcap"],
static_libs: [
"libbase",
"libselinux",
"liblog",
"libprocessgroup",
"libfs_mgr",
],
include_dirs: [
"system/core/mkbootimg",
],
}
/*
This is not yet ready, see the below TODOs for what is missing
cc_binary {
// TODO: Missing,
//LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
//LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
name: "init",
defaults: ["init_defaults"],
required: [
"e2fsdroid",
"mke2fs",
],
static_executable: true,
srcs: [
"bootchart.cpp",
"builtins.cpp",
"init.cpp",
"init_first_stage.cpp",
"keychords.cpp",
"reboot.cpp",
"signal_handler.cpp",
"ueventd.cpp",
"watchdogd.cpp",
],
static_libs: [
"libinit",
"libbootloader_message",
"libfs_mgr",
"libfec",
"libfec_rs",
"libsquashfs_utils",
"liblogwrap",
"libext4_utils",
"libcutils",
"libbase",
"libc",
"libselinux",
"liblog",
"libcrypto_utils",
"libcrypto",
"libc++_static",
"libdl",
"libsparse",
"libz",
"libprocessgroup",
"libavb",
"libkeyutils",
],
symlinks: [
"sbin/ueventd",
"sbin/watchdogd",
],
}
*/
// Tests
// ------------------------------------------------------------------------------
cc_test {
name: "init_tests",
defaults: ["init_defaults"],
srcs: [
"devices_test.cpp",
"init_test.cpp",
"property_service_test.cpp",
"result_test.cpp",
"service_test.cpp",
"ueventd_test.cpp",
"util_test.cpp",
],
shared_libs: [
"libbase",
"libcutils",
],
static_libs: [
"libinit",
"libselinux",
"libcrypto",
],
}
subdirs = ["*"]