Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7716e351 authored by Yifan Hong's avatar Yifan Hong Committed by Gerrit Code Review
Browse files

Merge "Implement host service manager"

parents 68aa2552 f7760016
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -151,6 +151,7 @@ cc_library {
                "libbase",
            ],
            srcs: [
                "ServiceManagerHost.cpp",
                "UtilsHost.cpp",
            ],
        },
+50 −3
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@

#ifdef __ANDROID__
#include <cutils/properties.h>
#else
#include "ServiceManagerHost.h"
#endif

#include "Static.h"
@@ -84,8 +86,19 @@ public:
    IBinder* onAsBinder() override {
        return IInterface::asBinder(mTheRealServiceManager).get();
    }
private:

protected:
    sp<AidlServiceManager> mTheRealServiceManager;

    // Directly get the service in a way that, for lazy services, requests the service to be started
    // if it is not currently started. This way, calls directly to ServiceManagerShim::getService
    // will still have the 5s delay that is expected by a large amount of Android code.
    //
    // When implementing ServiceManagerShim, use realGetService instead of
    // mTheRealServiceManager->getService so that it can be overridden in ServiceManagerHostShim.
    virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
        return mTheRealServiceManager->getService(name, _aidl_return);
    }
};

[[clang::no_destroy]] static std::once_flag gSmOnce;
@@ -319,7 +332,7 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
    const std::string name = String8(name16).c_str();

    sp<IBinder> out;
    if (Status status = mTheRealServiceManager->getService(name, &out); !status.isOk()) {
    if (Status status = realGetService(name, &out); !status.isOk()) {
        ALOGW("Failed to getService in waitForService for %s: %s", name.c_str(),
              status.toString8().c_str());
        return nullptr;
@@ -363,7 +376,7 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
        // - init gets death signal, but doesn't know it needs to restart
        //   the service
        // - we need to request service again to get it to start
        if (Status status = mTheRealServiceManager->getService(name, &out); !status.isOk()) {
        if (Status status = realGetService(name, &out); !status.isOk()) {
            ALOGW("Failed to getService in waitForService on later try for %s: %s", name.c_str(),
                  status.toString8().c_str());
            return nullptr;
@@ -412,4 +425,38 @@ std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& nam
    return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
}

#ifndef __ANDROID__
// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
// The internal implementation of the AIDL interface android::os::IServiceManager calls into
// on-device service manager.
class ServiceManagerHostShim : public ServiceManagerShim {
public:
    using ServiceManagerShim::ServiceManagerShim;
    // ServiceManagerShim::getService is based on checkService, so no need to override it.
    sp<IBinder> checkService(const String16& name) const override {
        return getDeviceService({String8(name).c_str()});
    }

protected:
    // Override realGetService for ServiceManagerShim::waitForService.
    Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
        *_aidl_return = getDeviceService({"-g", name});
        return Status::ok();
    }
};
sp<IServiceManager> createRpcDelegateServiceManager() {
    auto binder = getDeviceService({"manager"});
    if (binder == nullptr) {
        ALOGE("getDeviceService(\"manager\") returns null");
        return nullptr;
    }
    auto interface = AidlServiceManager::asInterface(binder);
    if (interface == nullptr) {
        ALOGE("getDeviceService(\"manager\") returns non service manager");
        return nullptr;
    }
    return sp<ServiceManagerHostShim>::make(interface);
}
#endif

} // namespace android
+176 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 "ServiceManagerHost.h"

#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <binder/IServiceManager.h>
#include <binder/RpcSession.h>

#include "UtilsHost.h"

namespace android {

namespace {

const void* kDeviceServiceExtraId = "DeviceServiceExtra";

// Parse stdout of program execution to string. If any error, return 0.
unsigned int parsePortNumber(const std::string& out, const std::string& what) {
    auto trimmed = android::base::Trim(out);
    unsigned int port = 0;
    if (!android::base::ParseUint(trimmed, &port)) {
        int savedErrno = errno;
        ALOGE("%s is not a valid %s: %s", trimmed.c_str(), what.c_str(), strerror(savedErrno));
        return 0;
    }
    if (port == 0) {
        ALOGE("0 is not a valid %s", what.c_str());
        return 0; // explicitly
    }
    return port;
}

// RAII object for adb forwarding
class AdbForwarder {
public:
    AdbForwarder() = default;
    static std::optional<AdbForwarder> forward(unsigned int devicePort);
    AdbForwarder(AdbForwarder&& other) noexcept { (*this) = std::move(other); }
    AdbForwarder& operator=(AdbForwarder&&) noexcept;
    ~AdbForwarder();
    [[nodiscard]] const std::optional<unsigned int>& hostPort() const { return mPort; }

private:
    DISALLOW_COPY_AND_ASSIGN(AdbForwarder);
    explicit AdbForwarder(unsigned int port) : mPort(port) {}
    std::optional<unsigned int> mPort;
};
std::optional<AdbForwarder> AdbForwarder::forward(unsigned int devicePort) {
    auto result =
            execute({"adb", "forward", "tcp:0", "tcp:" + std::to_string(devicePort)}, nullptr);
    if (!result.ok()) {
        ALOGE("Unable to run `adb forward tcp:0 tcp:%d`: %s", devicePort,
              result.error().message().c_str());
        return std::nullopt;
    }
    // Must end with exit code 0 (`has_value() && value() == 0`)
    if (result->exitCode.value_or(1) != 0) {
        ALOGE("Unable to run `adb forward tcp:0 tcp:%d`, command exits with %s", devicePort,
              result->toString().c_str());
        return std::nullopt;
    }
    if (!result->stderr.empty()) {
        LOG_HOST("`adb forward tcp:0 tcp:%d` writes to stderr: %s", devicePort,
                 result->stderr.c_str());
    }

    unsigned int hostPort = parsePortNumber(result->stdout, "host port");
    if (hostPort == 0) return std::nullopt;

    return AdbForwarder(hostPort);
}

AdbForwarder& AdbForwarder::operator=(AdbForwarder&& other) noexcept {
    std::swap(mPort, other.mPort);
    return *this;
}

AdbForwarder::~AdbForwarder() {
    if (!mPort.has_value()) return;

    auto result = execute({"adb", "forward", "--remove", "tcp:" + std::to_string(*mPort)}, nullptr);
    if (!result.ok()) {
        ALOGE("Unable to run `adb forward --remove tcp:%d`: %s", *mPort,
              result.error().message().c_str());
        return;
    }
    // Must end with exit code 0 (`has_value() && value() == 0`)
    if (result->exitCode.value_or(1) != 0) {
        ALOGE("Unable to run `adb forward --remove tcp:%d`, command exits with %s", *mPort,
              result->toString().c_str());
        return;
    }
    if (!result->stderr.empty()) {
        LOG_HOST("`adb forward --remove tcp:%d` writes to stderr: %s", *mPort,
                 result->stderr.c_str());
    }

    LOG_HOST("Successfully run `adb forward --remove tcp:%d`", *mPort);
}

void cleanupCommandResult(const void* id, void* obj, void* /* cookie */) {
    LOG_ALWAYS_FATAL_IF(id != kDeviceServiceExtraId,
                        "cleanupCommandResult invoked with mismatched ID %p, "
                        "expected %p",
                        id, kDeviceServiceExtraId);
    auto ptr = static_cast<CommandResult*>(obj);
    delete ptr;
}

} // namespace

sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs) {
    std::vector<std::string> prefix{"adb", "shell", "servicedispatcher"};
    serviceDispatcherArgs.insert(serviceDispatcherArgs.begin(), prefix.begin(), prefix.end());

    auto result = execute(std::move(serviceDispatcherArgs), &CommandResult::stdoutEndsWithNewLine);
    if (!result.ok()) {
        ALOGE("%s", result.error().message().c_str());
        return nullptr;
    }

    // `servicedispatcher` process must be alive to keep the port open.
    if (result->exitCode.has_value()) {
        ALOGE("Command exits with: %s", result->toString().c_str());
        return nullptr;
    }
    if (!result->stderr.empty()) {
        LOG_HOST("servicedispatcher writes to stderr: %s", result->stderr.c_str());
    }

    if (!result->stdoutEndsWithNewLine()) {
        ALOGE("Unexpected command result: %s", result->toString().c_str());
        return nullptr;
    }

    unsigned int devicePort = parsePortNumber(result->stdout, "device port");
    if (devicePort == 0) return nullptr;

    auto forwardResult = AdbForwarder::forward(devicePort);
    if (!forwardResult.has_value()) {
        return nullptr;
    }
    LOG_ALWAYS_FATAL_IF(!forwardResult->hostPort().has_value());

    auto rpcSession = RpcSession::make();
    if (!rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort())) {
        ALOGE("Unable to set up inet client on host port %u", *forwardResult->hostPort());
        return nullptr;
    }
    auto binder = rpcSession->getRootObject();
    if (binder == nullptr) {
        ALOGE("RpcSession::getRootObject returns nullptr");
        return nullptr;
    }
    binder->attachObject(kDeviceServiceExtraId,
                         static_cast<void*>(new CommandResult(std::move(*result))), nullptr,
                         &cleanupCommandResult);
    return binder;
}

} // namespace android
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.
 */

#pragma once

#include <android-base/macros.h>
#include <android/os/IServiceManager.h>

namespace android {

// Get a service on device by running servicedispatcher with the given args, e.g.
//     getDeviceService({"foo"});
// Return nullptr on any error.
// When the returned binder object is destroyed, remove adb forwarding and kills
// the long-running servicedispatcher process.
sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs);

} // namespace android
+13 −0
Original line number Diff line number Diff line
@@ -169,4 +169,17 @@ bool checkCallingPermission(const String16& permission,
                            int32_t* outPid, int32_t* outUid);
bool checkPermission(const String16& permission, pid_t pid, uid_t uid);

#ifndef __ANDROID__
// Create an IServiceManager that delegates the service manager on the device via adb.
// This is can be set as the default service manager at program start, so that
// defaultServiceManager() returns it:
//    int main() {
//        setDefaultServiceManager(createRpcDelegateServiceManager());
//        auto sm = defaultServiceManager();
//        // ...
//    }
// Resources are cleaned up when the object is destroyed.
sp<IServiceManager> createRpcDelegateServiceManager();
#endif

} // namespace android