diff options
author | 2019-06-21 12:35:59 -0700 | |
---|---|---|
committer | 2019-07-09 01:54:25 +0000 | |
commit | 80e1e6de29ffa3012a811ce9b64ccd15312987cd (patch) | |
tree | d5fc74ac807938a0cdd95490cc342c43e0b2c470 | |
parent | 7c292522d1a2c5751a4f4419d63d6d1d365d1905 (diff) |
servicemanager: use libbinder
Bug: 135768100
Test: boot
Test: servicemanager_test
Change-Id: I9d657b6c0d0be0f763b6d54e0e6c6bc1c1e3fc7a
(cherry picked from commit 3e092daa14c63831d76d3ad6e56b2919a0523536)
-rw-r--r-- | cmds/servicemanager/Access.cpp | 140 | ||||
-rw-r--r-- | cmds/servicemanager/Access.h | 59 | ||||
-rw-r--r-- | cmds/servicemanager/Android.bp | 54 | ||||
-rw-r--r-- | cmds/servicemanager/ServiceManager.cpp | 144 | ||||
-rw-r--r-- | cmds/servicemanager/ServiceManager.h | 47 | ||||
-rw-r--r-- | cmds/servicemanager/TEST_MAPPING | 7 | ||||
-rw-r--r-- | cmds/servicemanager/bctest.c | 107 | ||||
-rw-r--r-- | cmds/servicemanager/binder.c | 682 | ||||
-rw-r--r-- | cmds/servicemanager/binder.h | 94 | ||||
-rw-r--r-- | cmds/servicemanager/main.cpp | 54 | ||||
-rw-r--r-- | cmds/servicemanager/service_manager.c | 442 | ||||
-rw-r--r-- | cmds/servicemanager/test_sm.cpp | 261 | ||||
-rw-r--r-- | libs/binder/Android.bp | 4 | ||||
-rw-r--r-- | libs/binder/IPCThreadState.cpp | 2 | ||||
-rw-r--r-- | libs/binder/IServiceManager.cpp | 58 | ||||
-rw-r--r-- | libs/binder/aidl/android/os/IServiceManager.aidl | 80 | ||||
-rw-r--r-- | libs/binder/include/binder/IPCThreadState.h | 2 |
17 files changed, 851 insertions, 1386 deletions
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp new file mode 100644 index 0000000000..f4005c4dee --- /dev/null +++ b/cmds/servicemanager/Access.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 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 "Access.h" + +#include <android-base/logging.h> +#include <binder/IPCThreadState.h> +#include <log/log_safetynet.h> +#include <selinux/android.h> +#include <selinux/avc.h> + +namespace android { + +#ifdef VENDORSERVICEMANAGER +constexpr bool kIsVendor = true; +#else +constexpr bool kIsVendor = false; +#endif + +static std::string getPidcon(pid_t pid) { + android_errorWriteLog(0x534e4554, "121035042"); + + char* lookup = nullptr; + if (getpidcon(pid, &lookup) < 0) { + LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context"; + return ""; + } + std::string result = lookup; + freecon(lookup); + return result; +} + +static struct selabel_handle* getSehandle() { + static struct selabel_handle* gSehandle = nullptr; + + if (gSehandle != nullptr && selinux_status_updated()) { + selabel_close(gSehandle); + gSehandle = nullptr; + } + + if (gSehandle == nullptr) { + gSehandle = kIsVendor + ? selinux_android_vendor_service_context_handle() + : selinux_android_service_context_handle(); + } + + CHECK(gSehandle != nullptr); + return gSehandle; +} + +static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) { + const Access::CallingContext* ad = reinterpret_cast<Access::CallingContext*>(data); + + if (!ad) { + LOG(ERROR) << "No service manager audit data"; + return 0; + } + + snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name.c_str(), ad->debugPid, ad->uid); + return 0; +} + +Access::Access() { + union selinux_callback cb; + + cb.func_audit = auditCallback; + selinux_set_callback(SELINUX_CB_AUDIT, cb); + + cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); + + CHECK(selinux_status_open(true /*fallback*/) >= 0); + + CHECK(getcon(&mThisProcessContext) == 0); +} + +Access::~Access() { + freecon(mThisProcessContext); +} + +Access::CallingContext Access::getCallingContext(const std::string& name) { + IPCThreadState* ipc = IPCThreadState::self(); + + const char* callingSid = ipc->getCallingSid(); + pid_t callingPid = ipc->getCallingPid(); + + return CallingContext { + .debugPid = callingPid, + .uid = ipc->getCallingUid(), + .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid), + .name = name, + }; +} + +bool Access::canFind(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "find"); +} + +bool Access::canAdd(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "add"); +} + +bool Access::canList(const CallingContext& ctx) { + CHECK(ctx.name == ""); + + return actionAllowed(ctx, mThisProcessContext, "list"); +} + +bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) { + const char* tclass = "service_manager"; + + return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast<void*>(const_cast<CallingContext*>((&sctx)))); +} + +bool Access::actionAllowedFromLookup(const CallingContext& sctx, const char *perm) { + char *tctx = nullptr; + if (selabel_lookup(getSehandle(), &tctx, sctx.name.c_str(), 0) != 0) { + LOG(ERROR) << "SELinux: No match for " << sctx.name << " in service_contexts.\n"; + return false; + } + + bool allowed = actionAllowed(sctx, tctx, perm); + freecon(tctx); + return allowed; +} + +} // android diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h new file mode 100644 index 0000000000..b2c78cc34d --- /dev/null +++ b/cmds/servicemanager/Access.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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 <string> +#include <sys/types.h> + +namespace android { + +// singleton +class Access { +public: + Access(); + virtual ~Access(); + + Access(const Access&) = delete; + Access& operator=(const Access&) = delete; + Access(Access&&) = delete; + Access& operator=(Access&&) = delete; + + struct CallingContext { + pid_t debugPid; + uid_t uid; + std::string sid; + + // name of the service + // + // empty if call is unrelated to service (e.g. list) + std::string name; + }; + + virtual CallingContext getCallingContext(const std::string& name); + + virtual bool canFind(const CallingContext& ctx); + virtual bool canAdd(const CallingContext& ctx); + virtual bool canList(const CallingContext& ctx); + +private: + bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm); + bool actionAllowedFromLookup(const CallingContext& sctx, const char *perm); + + char* mThisProcessContext = nullptr; +}; + +}; diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 428561bc8a..9cf3c5c134 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -1,51 +1,51 @@ cc_defaults { - name: "servicemanager_flags", + name: "servicemanager_defaults", cflags: [ "-Wall", "-Wextra", "-Werror", ], - product_variables: { - binder32bit: { - cflags: ["-DBINDER_IPC_32BIT=1"], - }, - }, - shared_libs: ["liblog"], -} - -cc_binary { - name: "bctest", - defaults: ["servicemanager_flags"], srcs: [ - "bctest.c", - "binder.c", + "Access.cpp", + "ServiceManager.cpp", + ], + + shared_libs: [ + "libbase", + "libbinder", // also contains servicemanager_interface + "libcutils", + "liblog", + "libutils", + "libselinux", ], } cc_binary { name: "servicemanager", - defaults: ["servicemanager_flags"], - srcs: [ - "service_manager.c", - "binder.c", - ], - shared_libs: ["libcutils", "libselinux"], + defaults: ["servicemanager_defaults"], init_rc: ["servicemanager.rc"], + srcs: ["main.cpp"], } cc_binary { name: "vndservicemanager", - defaults: ["servicemanager_flags"], + defaults: ["servicemanager_defaults"], + init_rc: ["vndservicemanager.rc"], vendor: true, - srcs: [ - "service_manager.c", - "binder.c", - ], cflags: [ "-DVENDORSERVICEMANAGER=1", ], - shared_libs: ["libcutils", "libselinux"], - init_rc: ["vndservicemanager.rc"], + srcs: ["main.cpp"], +} + +cc_test { + name: "servicemanager_test", + test_suites: ["device-tests"], + defaults: ["servicemanager_defaults"], + srcs: [ + "test_sm.cpp", + ], + static_libs: ["libgmock"], } diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp new file mode 100644 index 0000000000..b88b67d138 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2019 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 "ServiceManager.h" + +#include <android-base/logging.h> +#include <cutils/android_filesystem_config.h> +#include <cutils/multiuser.h> + +using ::android::binder::Status; + +namespace android { + +ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {} + +Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) { + // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons. + return checkService(name, outBinder); +} + +Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) { + auto ctx = mAccess->getCallingContext(name); + + auto it = mNameToService.find(name); + if (it == mNameToService.end()) { + *outBinder = nullptr; + return Status::ok(); + } + + const Service& service = it->second; + + if (!service.allowIsolated) { + uid_t appid = multiuser_get_app_id(ctx.uid); + bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; + + if (isIsolated) { + *outBinder = nullptr; + return Status::ok(); + } + } + + // TODO(b/136023468): move this check to be first + if (!mAccess->canFind(ctx)) { + // returns ok and null for legacy reasons + *outBinder = nullptr; + return Status::ok(); + } + + *outBinder = service.binder; + return Status::ok(); +} + +Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) { + auto ctx = mAccess->getCallingContext(name); + + // apps cannot add services + if (multiuser_get_app_id(ctx.uid) >= AID_APP) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (!mAccess->canAdd(ctx)) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (binder == nullptr) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + // match legacy rules + if (name.size() == 0 || name.size() > 127) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + if (OK != binder->linkToDeath(this)) { + LOG(ERROR) << "Could not linkToDeath when adding " << name; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + + auto it = mNameToService.find(name); + if (it != mNameToService.end()) { + if (OK != it->second.binder->unlinkToDeath(this)) { + LOG(WARNING) << "Could not unlinkToDeath when adding " << name; + } + } + + mNameToService[name] = Service { + .binder = binder, + .allowIsolated = allowIsolated, + .dumpPriority = dumpPriority, + }; + + return Status::ok(); +} + +Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::string>* outList) { + if (!mAccess->canList(mAccess->getCallingContext(""))) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + size_t toReserve = 0; + for (auto const& [name, service] : mNameToService) { + (void) name; + + if (service.dumpPriority & dumpPriority) ++toReserve; + } + + CHECK(outList->empty()); + + outList->reserve(toReserve); + for (auto const& [name, service] : mNameToService) { + (void) service; + + if (service.dumpPriority & dumpPriority) { + outList->push_back(name); + } + } + + return Status::ok(); +} + +void ServiceManager::binderDied(const wp<IBinder>& who) { + for (auto it = mNameToService.begin(); it != mNameToService.end();) { + if (who == it->second.binder) { + it = mNameToService.erase(it); + } else { + ++it; + } + } +} + +} // namespace android diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h new file mode 100644 index 0000000000..78e48052b8 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 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/os/BnServiceManager.h> + +#include "Access.h" + +namespace android { + +class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { +public: + ServiceManager(std::unique_ptr<Access>&& access); + + binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override; + binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override; + binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override; + binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override; + + void binderDied(const wp<IBinder>& who) override; + +private: + struct Service { + sp<IBinder> binder; + bool allowIsolated; + int32_t dumpPriority; + }; + + std::map<std::string, Service> mNameToService; + std::unique_ptr<Access> mAccess; +}; + +} // namespace android diff --git a/cmds/servicemanager/TEST_MAPPING b/cmds/servicemanager/TEST_MAPPING new file mode 100644 index 0000000000..3e47269fe0 --- /dev/null +++ b/cmds/servicemanager/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "servicemanager_test" + } + ] +} diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c deleted file mode 100644 index 354df670e5..0000000000 --- a/cmds/servicemanager/bctest.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "binder.h" - -uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) -{ - uint32_t handle; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) - return 0; - - handle = bio_get_ref(&reply); - - if (handle) - binder_acquire(bs, handle); - - binder_done(bs, &msg, &reply); - - return handle; -} - -int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) -{ - int status; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - bio_put_obj(&msg, ptr); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) - return -1; - - status = bio_get_uint32(&reply); - - binder_done(bs, &msg, &reply); - - return status; -} - -unsigned token; - -int main(int argc, char **argv) -{ - struct binder_state *bs; - uint32_t svcmgr = BINDER_SERVICE_MANAGER; - uint32_t handle; - - bs = binder_open("/dev/binder", 128*1024); - if (!bs) { - fprintf(stderr, "failed to open binder driver\n"); - return -1; - } - - argc--; - argv++; - while (argc > 0) { - if (!strcmp(argv[0],"alt")) { - handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); - if (!handle) { - fprintf(stderr,"cannot find alt_svc_mgr\n"); - return -1; - } - svcmgr = handle; - fprintf(stderr,"svcmgr is via %x\n", handle); - } else if (!strcmp(argv[0],"lookup")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - handle = svcmgr_lookup(bs, svcmgr, argv[1]); - fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle); - argc--; - argv++; - } else if (!strcmp(argv[0],"publish")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - svcmgr_publish(bs, svcmgr, argv[1], &token); - argc--; - argv++; - } else { - fprintf(stderr,"unknown command %s\n", argv[0]); - return -1; - } - argc--; - argv++; - } - return 0; -} diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c deleted file mode 100644 index cf3b1728b6..0000000000 --- a/cmds/servicemanager/binder.c +++ /dev/null @@ -1,682 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#define LOG_TAG "Binder" - -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mman.h> -#include <unistd.h> - -#include <log/log.h> - -#include "binder.h" - -#define MAX_BIO_SIZE (1 << 30) - -#define TRACE 0 - -void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn); - -#if TRACE -void hexdump(void *_data, size_t len) -{ - unsigned char *data = _data; - size_t count; - - for (count = 0; count < len; count++) { - if ((count & 15) == 0) - fprintf(stderr,"%04zu:", count); - fprintf(stderr," %02x %c", *data, - (*data < 32) || (*data > 126) ? '.' : *data); - data++; - if ((count & 15) == 15) - fprintf(stderr,"\n"); - } - if ((count & 15) != 0) - fprintf(stderr,"\n"); -} - -void binder_dump_txn(struct binder_transaction_data *txn) -{ - struct flat_binder_object *obj; - binder_size_t *offs = (binder_size_t *)(uintptr_t)txn->data.ptr.offsets; - size_t count = txn->offsets_size / sizeof(binder_size_t); - - fprintf(stderr," target %016"PRIx64" cookie %016"PRIx64" code %08x flags %08x\n", - (uint64_t)txn->target.ptr, (uint64_t)txn->cookie, txn->code, txn->flags); - fprintf(stderr," pid %8d uid %8d data %"PRIu64" offs %"PRIu64"\n", - txn->sender_pid, txn->sender_euid, (uint64_t)txn->data_size, (uint64_t)txn->offsets_size); - hexdump((void *)(uintptr_t)txn->data.ptr.buffer, txn->data_size); - while (count--) { - obj = (struct flat_binder_object *) (((char*)(uintptr_t)txn->data.ptr.buffer) + *offs++); - fprintf(stderr," - type %08x flags %08x ptr %016"PRIx64" cookie %016"PRIx64"\n", - obj->type, obj->flags, (uint64_t)obj->binder, (uint64_t)obj->cookie); - } -} - -#define NAME(n) case n: return #n -const char *cmd_name(uint32_t cmd) -{ - switch(cmd) { - NAME(BR_NOOP); - NAME(BR_TRANSACTION_COMPLETE); - NAME(BR_INCREFS); - NAME(BR_ACQUIRE); - NAME(BR_RELEASE); - NAME(BR_DECREFS); - NAME(BR_TRANSACTION); - NAME(BR_REPLY); - NAME(BR_FAILED_REPLY); - NAME(BR_DEAD_REPLY); - NAME(BR_DEAD_BINDER); - default: return "???"; - } -} -#else -#define hexdump(a,b) do{} while (0) -#define binder_dump_txn(txn) do{} while (0) -#endif - -#define BIO_F_SHARED 0x01 /* needs to be buffer freed */ -#define BIO_F_OVERFLOW 0x02 /* ran out of space */ -#define BIO_F_IOERROR 0x04 -#define BIO_F_MALLOCED 0x08 /* needs to be free()'d */ - -struct binder_state -{ - int fd; - void *mapped; - size_t mapsize; -}; - -struct binder_state *binder_open(const char* driver, size_t mapsize) -{ - struct binder_state *bs; - struct binder_version vers; - - bs = malloc(sizeof(*bs)); - if (!bs) { - errno = ENOMEM; - return NULL; - } - - bs->fd = open(driver, O_RDWR | O_CLOEXEC); - if (bs->fd < 0) { - fprintf(stderr,"binder: cannot open %s (%s)\n", - driver, strerror(errno)); - goto fail_open; - } - - if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || - (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { - fprintf(stderr, - "binder: kernel driver version (%d) differs from user space version (%d)\n", - vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); - goto fail_open; - } - - bs->mapsize = mapsize; - bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); - if (bs->mapped == MAP_FAILED) { - fprintf(stderr,"binder: cannot map device (%s)\n", - strerror(errno)); - goto fail_map; - } - - return bs; - -fail_map: - close(bs->fd); -fail_open: - free(bs); - return NULL; -} - -void binder_close(struct binder_state *bs) -{ - munmap(bs->mapped, bs->mapsize); - close(bs->fd); - free(bs); -} - -int binder_become_context_manager(struct binder_state *bs) -{ - struct flat_binder_object obj; - memset(&obj, 0, sizeof(obj)); - obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX; - - int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj); - - // fallback to original method - if (result != 0) { - android_errorWriteLog(0x534e4554, "121035042"); - - result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); - } - return result; -} - -int binder_write(struct binder_state *bs, void *data, size_t len) -{ - struct binder_write_read bwr; - int res; - - bwr.write_size = len; - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) data; - bwr.read_size = 0; - bwr.read_consumed = 0; - bwr.read_buffer = 0; - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - if (res < 0) { - fprintf(stderr,"binder_write: ioctl failed (%s)\n", - strerror(errno)); - } - return res; -} - -void binder_free_buffer(struct binder_state *bs, - binder_uintptr_t buffer_to_free) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - } __attribute__((packed)) data; - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - binder_write(bs, &data, sizeof(data)); -} - -void binder_send_reply(struct binder_state *bs, - struct binder_io *reply, - binder_uintptr_t buffer_to_free, - int status) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - uint32_t cmd_reply; - struct binder_transaction_data txn; - } __attribute__((packed)) data; - - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - data.cmd_reply = BC_REPLY; - data.txn.target.ptr = 0; - data.txn.cookie = 0; - data.txn.code = 0; - if (status) { - data.txn.flags = TF_STATUS_CODE; - data.txn.data_size = sizeof(int); - data.txn.offsets_size = 0; - data.txn.data.ptr.buffer = (uintptr_t)&status; - data.txn.data.ptr.offsets = 0; - } else { - data.txn.flags = 0; - data.txn.data_size = reply->data - reply->data0; - data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0); - data.txn.data.ptr.buffer = (uintptr_t)reply->data0; - data.txn.data.ptr.offsets = (uintptr_t)reply->offs0; - } - binder_write(bs, &data, sizeof(data)); -} - -int binder_parse(struct binder_state *bs, struct binder_io *bio, - uintptr_t ptr, size_t size, binder_handler func) -{ - int r = 1; - uintptr_t end = ptr + (uintptr_t) size; - - while (ptr < end) { - uint32_t cmd = *(uint32_t *) ptr; - ptr += sizeof(uint32_t); -#if TRACE - fprintf(stderr,"%s:\n", cmd_name(cmd)); -#endif - switch(cmd) { - case BR_NOOP: - break; - case BR_TRANSACTION_COMPLETE: - break; - case BR_INCREFS: - case BR_ACQUIRE: - case BR_RELEASE: - case BR_DECREFS: -#if TRACE - fprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *))); -#endif - ptr += sizeof(struct binder_ptr_cookie); - break; - case BR_TRANSACTION_SEC_CTX: - case BR_TRANSACTION: { - struct binder_transaction_data_secctx txn; - if (cmd == BR_TRANSACTION_SEC_CTX) { - if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) { - ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n"); - return -1; - } - memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx)); - ptr += sizeof(struct binder_transaction_data_secctx); - } else /* BR_TRANSACTION */ { - if ((end - ptr) < sizeof(struct binder_transaction_data)) { - ALOGE("parse: txn too small (binder_transaction_data)!\n"); - return -1; - } - memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data)); - ptr += sizeof(struct binder_transaction_data); - - txn.secctx = 0; - } - - binder_dump_txn(&txn.transaction_data); - if (func) { - unsigned rdata[256/4]; - struct binder_io msg; - struct binder_io reply; - int res; - - bio_init(&reply, rdata, sizeof(rdata), 4); - bio_init_from_txn(&msg, &txn.transaction_data); - res = func(bs, &txn, &msg, &reply); - if (txn.transaction_data.flags & TF_ONE_WAY) { - binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer); - } else { - binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res); - } - } - break; - } - case BR_REPLY: { - struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr; - if ((end - ptr) < sizeof(*txn)) { - ALOGE("parse: reply too small!\n"); - return -1; - } - binder_dump_txn(txn); - if (bio) { - bio_init_from_txn(bio, txn); - bio = 0; - } else { - /* todo FREE BUFFER */ - } - ptr += sizeof(*txn); - r = 0; - break; - } - case BR_DEAD_BINDER: { - struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr; - ptr += sizeof(binder_uintptr_t); - death->func(bs, death->ptr); - break; - } - case BR_FAILED_REPLY: - r = -1; - break; - case BR_DEAD_REPLY: - r = -1; - break; - default: - ALOGE("parse: OOPS %d\n", cmd); - return -1; - } - } - - return r; -} - -void binder_acquire(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_ACQUIRE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_release(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_RELEASE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death) -{ - struct { - uint32_t cmd; - struct binder_handle_cookie payload; - } __attribute__((packed)) data; - - data.cmd = BC_REQUEST_DEATH_NOTIFICATION; - data.payload.handle = target; - data.payload.cookie = (uintptr_t) death; - binder_write(bs, &data, sizeof(data)); -} - -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code) -{ - int res; - struct binder_write_read bwr; - struct { - uint32_t cmd; - struct binder_transaction_data txn; - } __attribute__((packed)) writebuf; - unsigned readbuf[32]; - - if (msg->flags & BIO_F_OVERFLOW) { - fprintf(stderr,"binder: txn buffer overflow\n"); - goto fail; - } - - writebuf.cmd = BC_TRANSACTION; - writebuf.txn.target.handle = target; - writebuf.txn.code = code; - writebuf.txn.flags = 0; - writebuf.txn.data_size = msg->data - msg->data0; - writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0); - writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0; - writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0; - - bwr.write_size = sizeof(writebuf); - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) &writebuf; - - hexdump(msg->data0, msg->data - msg->data0); - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); - goto fail; - } - - res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); - if (res == 0) return 0; - if (res < 0) goto fail; - } - -fail: - memset(reply, 0, sizeof(*reply)); - reply->flags |= BIO_F_IOERROR; - return -1; -} - -void binder_loop(struct binder_state *bs, binder_handler func) -{ - int res; - struct binder_write_read bwr; - uint32_t readbuf[32]; - - bwr.write_size = 0; - bwr.write_consumed = 0; - bwr.write_buffer = 0; - - readbuf[0] = BC_ENTER_LOOPER; - binder_write(bs, readbuf, sizeof(uint32_t)); - - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); - break; - } - - res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); - if (res == 0) { - ALOGE("binder_loop: unexpected reply?!\n"); - break; - } - if (res < 0) { - ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); - break; - } - } -} - -void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn) -{ - bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer; - bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets; - bio->data_avail = txn->data_size; - bio->offs_avail = txn->offsets_size / sizeof(size_t); - bio->flags = BIO_F_SHARED; -} - -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxoffs) -{ - size_t n = maxoffs * sizeof(size_t); - - if (n > maxdata) { - bio->flags = BIO_F_OVERFLOW; - bio->data_avail = 0; - bio->offs_avail = 0; - return; - } - - bio->data = bio->data0 = (char *) data + n; - bio->offs = bio->offs0 = data; - bio->data_avail = maxdata - n; - bio->offs_avail = maxoffs; - bio->flags = 0; -} - -static void *bio_alloc(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - if (size > bio->data_avail) { - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -void binder_done(struct binder_state *bs, - __unused struct binder_io *msg, - struct binder_io *reply) -{ - struct { - uint32_t cmd; - uintptr_t buffer; - } __attribute__((packed)) data; - - if (reply->flags & BIO_F_SHARED) { - data.cmd = BC_FREE_BUFFER; - data.buffer = (uintptr_t) reply->data0; - binder_write(bs, &data, sizeof(data)); - reply->flags = 0; - } -} - -static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = bio_alloc(bio, sizeof(*obj)); - - if (obj && bio->offs_avail) { - bio->offs_avail--; - *bio->offs++ = ((char*) obj) - ((char*) bio->data0); - return obj; - } - - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -void bio_put_uint32(struct binder_io *bio, uint32_t n) -{ - uint32_t *ptr = bio_alloc(bio, sizeof(n)); - if (ptr) - *ptr = n; -} - -void bio_put_obj(struct binder_io *bio, void *ptr) -{ - struct flat_binder_object *obj; - - obj = bio_alloc_obj(bio); - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_BINDER; - obj->binder = (uintptr_t)ptr; - obj->cookie = 0; -} - -void bio_put_ref(struct binder_io *bio, uint32_t handle) -{ - struct flat_binder_object *obj; - - if (handle) - obj = bio_alloc_obj(bio); - else - obj = bio_alloc(bio, sizeof(*obj)); - - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_HANDLE; - obj->handle = handle; - obj->cookie = 0; -} - -void bio_put_string16(struct binder_io *bio, const uint16_t *str) -{ - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = 0; - while (str[len]) len++; - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, (uint32_t) len); - len = (len + 1) * sizeof(uint16_t); - ptr = bio_alloc(bio, len); - if (ptr) - memcpy(ptr, str, len); -} - -void bio_put_string16_x(struct binder_io *bio, const char *_str) -{ - unsigned char *str = (unsigned char*) _str; - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = strlen(_str); - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, len); - ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t)); - if (!ptr) - return; - - while (*str) - *ptr++ = *str++; - *ptr++ = 0; -} - -static void *bio_get(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - - if (bio->data_avail < size){ - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -uint32_t bio_get_uint32(struct binder_io *bio) -{ - uint32_t *ptr = bio_get(bio, sizeof(*ptr)); - return ptr ? *ptr : 0; -} - -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz) -{ - size_t len; - - /* Note: The payload will carry 32bit size instead of size_t */ - len = (size_t) bio_get_uint32(bio); - if (sz) - *sz = len; - return bio_get(bio, (len + 1) * sizeof(uint16_t)); -} - -static struct flat_binder_object *_bio_get_obj(struct binder_io *bio) -{ - size_t n; - size_t off = bio->data - bio->data0; - - /* TODO: be smarter about this? */ - for (n = 0; n < bio->offs_avail; n++) { - if (bio->offs[n] == off) - return bio_get(bio, sizeof(struct flat_binder_object)); - } - - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -uint32_t bio_get_ref(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = _bio_get_obj(bio); - if (!obj) - return 0; - - if (obj->hdr.type == BINDER_TYPE_HANDLE) - return obj->handle; - - return 0; -} diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h deleted file mode 100644 index a9ccc74130..0000000000 --- a/cmds/servicemanager/binder.h +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#ifndef _BINDER_H_ -#define _BINDER_H_ - -#include <linux/android/binder.h> -#include <sys/ioctl.h> - -struct binder_state; - -struct binder_io -{ - char *data; /* pointer to read/write from */ - binder_size_t *offs; /* array of offsets */ - size_t data_avail; /* bytes available in data buffer */ - size_t offs_avail; /* entries available in offsets array */ - - char *data0; /* start of data buffer */ - binder_size_t *offs0; /* start of offsets buffer */ - uint32_t flags; - uint32_t unused; -}; - -struct binder_death { - void (*func)(struct binder_state *bs, void *ptr); - void *ptr; -}; - -/* the one magic handle */ -#define BINDER_SERVICE_MANAGER 0U - -#define SVC_MGR_NAME "android.os.IServiceManager" - -enum { - /* Must match definitions in IBinder.h and IServiceManager.h */ - PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), - SVC_MGR_GET_SERVICE = 1, - SVC_MGR_CHECK_SERVICE, - SVC_MGR_ADD_SERVICE, - SVC_MGR_LIST_SERVICES, -}; - -typedef int (*binder_handler)(struct binder_state *bs, - struct binder_transaction_data_secctx *txn, - struct binder_io *msg, - struct binder_io *reply); - -struct binder_state *binder_open(const char* driver, size_t mapsize); -void binder_close(struct binder_state *bs); - -/* initiate a blocking binder call - * - returns zero on success - */ -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code); - -/* release any state associate with the binder_io - * - call once any necessary data has been extracted from the - * binder_io after binder_call() returns - * - can safely be called even if binder_call() fails - */ -void binder_done(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply); - -/* manipulate strong references */ -void binder_acquire(struct binder_state *bs, uint32_t target); -void binder_release(struct binder_state *bs, uint32_t target); - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death); - -void binder_loop(struct binder_state *bs, binder_handler func); - -int binder_become_context_manager(struct binder_state *bs); - -/* allocate a binder_io, providing a stack-allocated working - * buffer, size of the working buffer, and how many object - * offset entries to reserve from the buffer - */ -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxobjects); - -void bio_put_obj(struct binder_io *bio, void *ptr); -void bio_put_ref(struct binder_io *bio, uint32_t handle); -void bio_put_uint32(struct binder_io *bio, uint32_t n); -void bio_put_string16(struct binder_io *bio, const uint16_t *str); -void bio_put_string16_x(struct binder_io *bio, const char *_str); - -uint32_t bio_get_uint32(struct binder_io *bio); -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz); -uint32_t bio_get_ref(struct binder_io *bio); - -#endif diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp new file mode 100644 index 0000000000..c8ceb42ac8 --- /dev/null +++ b/cmds/servicemanager/main.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 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 <android-base/logging.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/Status.h> +#include <utils/StrongPointer.h> + +#include "Access.h" +#include "ServiceManager.h" + +using ::android::sp; +using ::android::ProcessState; +using ::android::IPCThreadState; +using ::android::ServiceManager; +using ::android::Access; + +int main(int argc, char** argv) { + if (argc > 2) { + LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; + } + + const char* driver = argc == 2 ? argv[1] : "/dev/binder"; + + android::base::InitLogging(nullptr, &android::base::KernelLogger); + + ProcessState::self()->initWithDriver(driver); + ProcessState::self()->setThreadPoolMaxThreadCount(0); + ProcessState::self()->setCallRestriction( + ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); + + sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>()); + IPCThreadState::self()->setTheContextObject(manager); + ProcessState::self()->becomeContextManager(nullptr, nullptr); + + IPCThreadState::self()->joinThreadPool(); + + // should not be reached + return EXIT_FAILURE; +} diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c deleted file mode 100644 index ec3fac538d..0000000000 --- a/cmds/servicemanager/service_manager.c +++ /dev/null @@ -1,442 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <cutils/android_filesystem_config.h> -#include <cutils/multiuser.h> - -#include <selinux/android.h> -#include <selinux/avc.h> - -#include "binder.h" - -#ifdef VENDORSERVICEMANAGER -#define LOG_TAG "VendorServiceManager" -#else -#define LOG_TAG "ServiceManager" -#endif -#include <log/log.h> - -struct audit_data { - pid_t pid; - uid_t uid; - const char *name; -}; - -const char *str8(const uint16_t *x, size_t x_len) -{ - static char buf[128]; - size_t max = 127; - char *p = buf; - - if (x_len < max) { - max = x_len; - } - - if (x) { - while ((max > 0) && (*x != '\0')) { - *p++ = *x++; - max--; - } - } - *p++ = 0; - return buf; -} - -int str16eq(const uint16_t *a, const char *b) -{ - while (*a && *b) - if (*a++ != *b++) return 0; - if (*a || *b) - return 0; - return 1; -} - -static char *service_manager_context; -static struct selabel_handle* sehandle; - -static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name) -{ - char *lookup_sid = NULL; - const char *class = "service_manager"; - bool allowed; - struct audit_data ad; - - if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) { - ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); - return false; - } - - ad.pid = spid; - ad.uid = uid; - ad.name = name; - - if (sid == NULL) { - android_errorWriteLog(0x534e4554, "121035042"); - } - - int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad); - allowed = (result == 0); - - freecon(lookup_sid); - return allowed; -} - -static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm) -{ - return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL); -} - -static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name) -{ - bool allowed; - char *tctx = NULL; - - if (!sehandle) { - ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); - abort(); - } - - if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { - ALOGE("SELinux: No match for %s in service_contexts.\n", name); - return false; - } - - allowed = check_mac_perms(spid, sid, uid, tctx, perm, name); - freecon(tctx); - return allowed; -} - -static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "add"; - - if (multiuser_get_app_id(uid) >= AID_APP) { - return 0; /* Don't allow apps to register services */ - } - - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -static int svc_can_list(pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "list"; - return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0; -} - -static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "find"; - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -struct svcinfo -{ - struct svcinfo *next; - uint32_t handle; - struct binder_death death; - int allow_isolated; - uint32_t dumpsys_priority; - size_t len; - uint16_t name[0]; -}; - -struct svcinfo *svclist = NULL; - -struct svcinfo *find_svc(const uint16_t *s16, size_t len) -{ - struct svcinfo *si; - - for (si = svclist; si; si = si->next) { - if ((len == si->len) && - !memcmp(s16, si->name, len * sizeof(uint16_t))) { - return si; - } - } - return NULL; -} - -void svcinfo_death(struct binder_state *bs, void *ptr) -{ - struct svcinfo *si = (struct svcinfo* ) ptr; - - ALOGI("service '%s' died\n", str8(si->name, si->len)); - if (si->handle) { - binder_release(bs, si->handle); - si->handle = 0; - } -} - -uint16_t svcmgr_id[] = { - 'a','n','d','r','o','i','d','.','o','s','.', - 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' -}; - - -uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid) -{ - struct svcinfo *si = find_svc(s, len); - - if (!si || !si->handle) { - return 0; - } - - if (!si->allow_isolated) { - // If this service doesn't allow access from isolated processes, - // then check the uid to see if it is isolated. - uid_t appid = uid % AID_USER; - if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { - return 0; - } - } - - if (!svc_can_find(s, len, spid, sid, uid)) { - return 0; - } - - return si->handle; -} - -int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, - uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) { - struct svcinfo *si; - - //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, - // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); - - if (!handle || (len == 0) || (len > 127)) - return -1; - - if (!svc_can_register(s, len, spid, sid, uid)) { - ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", - str8(s, len), handle, uid); - return -1; - } - - si = find_svc(s, len); - if (si) { - if (si->handle) { - ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", - str8(s, len), handle, uid); - svcinfo_death(bs, si); - } - si->handle = handle; - } else { - si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); - if (!si) { - ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", - str8(s, len), handle, uid); - return -1; - } - si->handle = handle; - si->len = len; - memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); - si->name[len] = '\0'; - si->death.func = (void*) svcinfo_death; - si->death.ptr = si; - si->allow_isolated = allow_isolated; - si->dumpsys_priority = dumpsys_priority; - si->next = svclist; - svclist = si; - } - - binder_acquire(bs, handle); - binder_link_to_death(bs, handle, &si->death); - return 0; -} - -int svcmgr_handler(struct binder_state *bs, - struct binder_transaction_data_secctx *txn_secctx, - struct binder_io *msg, - struct binder_io *reply) -{ - struct svcinfo *si; - uint16_t *s; - size_t len; - uint32_t handle; - uint32_t strict_policy; - int allow_isolated; - uint32_t dumpsys_priority; - - struct binder_transaction_data *txn = &txn_secctx->transaction_data; - - //ALOGI("target=%p code=%d pid=%d uid=%d\n", - // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); - - if (txn->target.ptr != BINDER_SERVICE_MANAGER) - return -1; - - if (txn->code == PING_TRANSACTION) - return 0; - - // Equivalent to Parcel::enforceInterface(), reading the RPC - // header with the strict mode policy mask and the interface name. - // Note that we ignore the strict_policy and don't propagate it - // further (since we do no outbound RPCs anyway). - strict_policy = bio_get_uint32(msg); - bio_get_uint32(msg); // Ignore worksource header. - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - - if ((len != (sizeof(svcmgr_id) / 2)) || - memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { - fprintf(stderr,"invalid id %s\n", str8(s, len)); - return -1; - } - - if (sehandle && selinux_status_updated() > 0) { -#ifdef VENDORSERVICEMANAGER - struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle(); -#else - struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle(); -#endif - if (tmp_sehandle) { - selabel_close(sehandle); - sehandle = tmp_sehandle; - } - } - - switch(txn->code) { - case SVC_MGR_GET_SERVICE: - case SVC_MGR_CHECK_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid, - (const char*) txn_secctx->secctx); - if (!handle) - break; - bio_put_ref(reply, handle); - return 0; - - case SVC_MGR_ADD_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = bio_get_ref(msg); - allow_isolated = bio_get_uint32(msg) ? 1 : 0; - dumpsys_priority = bio_get_uint32(msg); - if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, - txn->sender_pid, (const char*) txn_secctx->secctx)) - return -1; - break; - - case SVC_MGR_LIST_SERVICES: { - uint32_t n = bio_get_uint32(msg); - uint32_t req_dumpsys_priority = bio_get_uint32(msg); - - if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) { - ALOGE("list_service() uid=%d - PERMISSION DENIED\n", - txn->sender_euid); - return -1; - } - si = svclist; - // walk through the list of services n times skipping services that - // do not support the requested priority - while (si) { - if (si->dumpsys_priority & req_dumpsys_priority) { - if (n == 0) break; - n--; - } - si = si->next; - } - if (si) { - bio_put_string16(reply, si->name); - return 0; - } - return -1; - } - default: - ALOGE("unknown code %d\n", txn->code); - return -1; - } - - bio_put_uint32(reply, 0); - return 0; -} - - -static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len) -{ - struct audit_data *ad = (struct audit_data *)data; - - if (!ad || !ad->name) { - ALOGE("No service manager audit data"); - return 0; - } - - snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid); - return 0; -} - -int main(int argc, char** argv) -{ - struct binder_state *bs; - union selinux_callback cb; - char *driver; - - if (argc > 1) { - driver = argv[1]; - } else { - driver = "/dev/binder"; - } - - bs = binder_open(driver, 128*1024); - if (!bs) { -#ifdef VENDORSERVICEMANAGER - ALOGW("failed to open binder driver %s\n", driver); - while (true) { - sleep(UINT_MAX); - } -#else - ALOGE("failed to open binder driver %s\n", driver); -#endif - return -1; - } - - if (binder_become_context_manager(bs)) { - ALOGE("cannot become context manager (%s)\n", strerror(errno)); - return -1; - } - - cb.func_audit = audit_callback; - selinux_set_callback(SELINUX_CB_AUDIT, cb); -#ifdef VENDORSERVICEMANAGER - cb.func_log = selinux_vendor_log_callback; -#else - cb.func_log = selinux_log_callback; -#endif - selinux_set_callback(SELINUX_CB_LOG, cb); - -#ifdef VENDORSERVICEMANAGER - sehandle = selinux_android_vendor_service_context_handle(); -#else - sehandle = selinux_android_service_context_handle(); -#endif - selinux_status_open(true); - - if (sehandle == NULL) { - ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); - abort(); - } - - if (getcon(&service_manager_context) != 0) { - ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); - abort(); - } - - - binder_loop(bs, svcmgr_handler); - - return 0; -} diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp new file mode 100644 index 0000000000..812d5cacd5 --- /dev/null +++ b/cmds/servicemanager/test_sm.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2019 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 <binder/ProcessState.h> +#include <cutils/android_filesystem_config.h> +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include "Access.h" +#include "ServiceManager.h" + +using android::sp; +using android::Access; +using android::IBinder; +using android::ServiceManager; +using android::os::IServiceManager; +using testing::_; +using testing::ElementsAre; +using testing::NiceMock; +using testing::Return; + +static sp<IBinder> getBinder() { + // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work. + // The context manager (servicemanager) is easy to get and is in another process. + return android::ProcessState::self()->getContextObject(nullptr); +} + +class MockAccess : public Access { +public: + MOCK_METHOD1(getCallingContext, CallingContext(const std::string& name)); + MOCK_METHOD1(canAdd, bool(const CallingContext&)); + MOCK_METHOD1(canFind, bool(const CallingContext&)); + MOCK_METHOD1(canList, bool(const CallingContext&)); +}; + +static sp<ServiceManager> getPermissiveServiceManager() { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + ON_CALL(*access, getCallingContext(_)).WillByDefault(Return(Access::CallingContext{})); + ON_CALL(*access, canAdd(_)).WillByDefault(Return(true)); + ON_CALL(*access, canFind(_)).WillByDefault(Return(true)); + ON_CALL(*access, canList(_)).WillByDefault(Return(true)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + return sm; +} + +TEST(AddService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, EmptyNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, JustShortEnoughServiceNameHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService(std::string(127, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, TooLongNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService(std::string(128, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddNullServiceDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("foo", nullptr, false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddDisallowedFromApp) { + for (uid_t uid : { AID_APP_START, AID_APP_START + 1, AID_APP_END }) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{ + .debugPid = 1337, + .uid = uid, + })); + EXPECT_CALL(*access, canAdd(_)).Times(0); + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + } + +} + +TEST(AddService, HappyOverExistingService) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, NoPermissions) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(false)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(GetService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out); +} + +TEST(GetService, NonExistant) { + auto sm = getPermissiveServiceManager(); + + sp<IBinder> out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, NoPermissionsForGettingService) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillRepeatedly(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(false)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, AllowedFromIsolated) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out.get()); +} + +TEST(GetService, NotAllowedFromIsolated) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + + // TODO(b/136023468): when security check is first, this should be called first + // EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(ListServices, NoPermissions) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canList(_)).WillOnce(Return(false)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + std::vector<std::string> out; + EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + EXPECT_TRUE(out.empty()); +} + +TEST(ListServices, AllServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector<std::string> out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa", "sb", "sc", "sd")); +} + +TEST(ListServices, CriticalServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector<std::string> out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa")); +} diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 905b25f397..760d55b751 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -94,7 +94,6 @@ cc_library_shared { "PermissionController.cpp", "ProcessInfoService.cpp", "IpPrefix.cpp", - ":libbinder_aidl", ], }, }, @@ -142,8 +141,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", + "aidl/android/os/IServiceManager.aidl", ], path: "aidl", } - -subdirs = ["tests"] diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index a2d10ab0ab..3424c28883 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -1062,7 +1062,7 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, sp<BBinder> the_context_object; -void setTheContextObject(sp<BBinder> obj) +void IPCThreadState::setTheContextObject(sp<BBinder> obj) { the_context_object = obj; } diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 0203d41992..07550fb571 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -18,6 +18,7 @@ #include <binder/IServiceManager.h> +#include <android/os/IServiceManager.h> #include <utils/Log.h> #include <binder/IPCThreadState.h> #ifndef __ANDROID_VNDK__ @@ -34,6 +35,9 @@ namespace android { +using AidlServiceManager = android::os::IServiceManager; +using android::binder::Status; + sp<IServiceManager> defaultServiceManager() { static Mutex gDefaultServiceManagerLock; @@ -142,11 +146,12 @@ class BpServiceManager : public BpInterface<IServiceManager> { public: explicit BpServiceManager(const sp<IBinder>& impl) - : BpInterface<IServiceManager>(impl) + : BpInterface<IServiceManager>(impl), + mTheRealServiceManager(interface_cast<AidlServiceManager>(impl)) { } - virtual sp<IBinder> getService(const String16& name) const + sp<IBinder> getService(const String16& name) const override { static bool gSystemBootCompleted = false; @@ -179,43 +184,36 @@ public: return nullptr; } - virtual sp<IBinder> checkService( const String16& name) const - { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); - return reply.readStrongBinder(); + sp<IBinder> checkService(const String16& name) const override { + sp<IBinder> ret; + if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { + return nullptr; + } + return ret; } - virtual status_t addService(const String16& name, const sp<IBinder>& service, - bool allowIsolated, int dumpsysPriority) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - data.writeStrongBinder(service); - data.writeInt32(allowIsolated ? 1 : 0); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); - return err == NO_ERROR ? reply.readExceptionCode() : err; + status_t addService(const String16& name, const sp<IBinder>& service, + bool allowIsolated, int dumpsysPriority) override { + Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority); + return status.exceptionCode(); } virtual Vector<String16> listServices(int dumpsysPriority) { - Vector<String16> res; - int n = 0; + std::vector<std::string> ret; + if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) { + return {}; + } - for (;;) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeInt32(n++); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); - if (err != NO_ERROR) - break; - res.add(reply.readString16()); + Vector<String16> res; + res.setCapacity(ret.size()); + for (const std::string& name : ret) { + res.push(String16(name.c_str())); } return res; } + +private: + sp<AidlServiceManager> mTheRealServiceManager; }; IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl new file mode 100644 index 0000000000..50a72aa9e4 --- /dev/null +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2006 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. + */ + +package android.os; + +/** + * Basic interface for finding and publishing system services. + * + * You likely want to use android.os.ServiceManager in Java or + * android::IServiceManager in C++ in order to use this interface. + * + * @hide + */ +interface IServiceManager { + /* + * Must update values in IServiceManager.h + */ + /* Allows services to dump sections according to priorities. */ + const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0 + const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1 + const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2 + /** + * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the + * same priority as NORMAL priority but the services are not called with dump priority + * arguments. + */ + const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3 + + const int DUMP_FLAG_PRIORITY_ALL = 15; + // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH + // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT; + + /* Allows services to dump sections in protobuf format. */ + const int DUMP_FLAG_PROTO = 16; // 1 << 4 + + /** + * Retrieve an existing service called @a name from the + * service manager. + * + * This is the same as checkService (returns immediately) but + * exists for legacy purposes. + * + * Returns null if the service does not exist. + */ + @UnsupportedAppUsage + IBinder getService(@utf8InCpp String name); + + /** + * Retrieve an existing service called @a name from the service + * manager. Non-blocking. Returns null if the service does not + * exist. + */ + @UnsupportedAppUsage + IBinder checkService(@utf8InCpp String name); + + /** + * Place a new @a service called @a name into the service + * manager. + */ + void addService(@utf8InCpp String name, IBinder service, + boolean allowIsolated, int dumpPriority); + + /** + * Return a list of all currently running services. + */ + @utf8InCpp String[] listServices(int dumpPriority); +} diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 614b0b33dd..b810f7e8ee 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -110,6 +110,8 @@ public: // the maximum number of binder threads threads allowed for this process. void blockUntilThreadAvailable(); + // Service manager registration + void setTheContextObject(sp<BBinder> obj); // Is this thread currently serving a binder call. This method // returns true if while traversing backwards from the function call |