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

Commit f7760016 authored by Yifan Hong's avatar Yifan Hong
Browse files

Implement host service manager

On the host, after

  setDefaultServiceManager(createRpcDelegateServiceManager())

is called, defaultServiceManager() will return
a service manager delegate that calls into the service
manager on the device.

Test: binderHostDeviceTest with servicedispatcher installed
Bug: 190233850

Change-Id: I44f9d2e2419883e242fea0472d702f559dd0b283
parent f2acc8dc
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