upload android base code part6
This commit is contained in:
parent
421e214c7d
commit
4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions
121
android/system/hwservicemanager/AccessControl.cpp
Normal file
121
android/system/hwservicemanager/AccessControl.cpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
#include <android-base/logging.h>
|
||||
#include <hidl-util/FQName.h>
|
||||
#include <log/log.h>
|
||||
|
||||
#include "AccessControl.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
static const char *kPermissionAdd = "add";
|
||||
static const char *kPermissionGet = "find";
|
||||
static const char *kPermissionList = "list";
|
||||
|
||||
struct audit_data {
|
||||
const char* interfaceName;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
using android::FQName;
|
||||
using Context = AccessControl::Context;
|
||||
|
||||
AccessControl::AccessControl() {
|
||||
mSeHandle = selinux_android_hw_service_context_handle();
|
||||
LOG_ALWAYS_FATAL_IF(mSeHandle == NULL, "Failed to acquire SELinux handle.");
|
||||
|
||||
if (getcon(&mSeContext) != 0) {
|
||||
LOG_ALWAYS_FATAL("Failed to acquire hwservicemanager context.");
|
||||
}
|
||||
|
||||
selinux_status_open(true);
|
||||
|
||||
mSeCallbacks.func_audit = AccessControl::auditCallback;
|
||||
selinux_set_callback(SELINUX_CB_AUDIT, mSeCallbacks);
|
||||
|
||||
mSeCallbacks.func_log = selinux_log_callback; /* defined in libselinux */
|
||||
selinux_set_callback(SELINUX_CB_LOG, mSeCallbacks);
|
||||
}
|
||||
|
||||
bool AccessControl::canAdd(const std::string& fqName, const Context &context, pid_t pid) {
|
||||
FQName fqIface(fqName);
|
||||
|
||||
if (!fqIface.isValid()) {
|
||||
return false;
|
||||
}
|
||||
const std::string checkName = fqIface.package() + "::" + fqIface.name();
|
||||
|
||||
return checkPermission(context, pid, kPermissionAdd, checkName.c_str());
|
||||
}
|
||||
|
||||
bool AccessControl::canGet(const std::string& fqName, pid_t pid) {
|
||||
FQName fqIface(fqName);
|
||||
|
||||
if (!fqIface.isValid()) {
|
||||
return false;
|
||||
}
|
||||
const std::string checkName = fqIface.package() + "::" + fqIface.name();
|
||||
|
||||
return checkPermission(getContext(pid), pid, kPermissionGet, checkName.c_str());
|
||||
}
|
||||
|
||||
bool AccessControl::canList(pid_t pid) {
|
||||
return checkPermission(getContext(pid), pid, mSeContext, kPermissionList, nullptr);
|
||||
}
|
||||
|
||||
Context AccessControl::getContext(pid_t sourcePid) {
|
||||
char *sourceContext = NULL;
|
||||
|
||||
if (getpidcon(sourcePid, &sourceContext) < 0) {
|
||||
ALOGE("SELinux: failed to retrieve process context for pid %d", sourcePid);
|
||||
return Context(nullptr, freecon);
|
||||
}
|
||||
|
||||
return Context(sourceContext, freecon);
|
||||
}
|
||||
|
||||
bool AccessControl::checkPermission(const Context &context, pid_t sourceAuditPid, const char *targetContext, const char *perm, const char *interface) {
|
||||
if (context == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool allowed = false;
|
||||
struct audit_data ad;
|
||||
|
||||
ad.pid = sourceAuditPid;
|
||||
ad.interfaceName = interface;
|
||||
|
||||
allowed = (selinux_check_access(context.get(), targetContext, "hwservice_manager",
|
||||
perm, (void *) &ad) == 0);
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
bool AccessControl::checkPermission(const Context &context, pid_t sourceAuditPid, const char *perm, const char *interface) {
|
||||
char *targetContext = NULL;
|
||||
bool allowed = false;
|
||||
|
||||
// Lookup service in hwservice_contexts
|
||||
if (selabel_lookup(mSeHandle, &targetContext, interface, 0) != 0) {
|
||||
ALOGE("No match for interface %s in hwservice_contexts", interface);
|
||||
return false;
|
||||
}
|
||||
|
||||
allowed = checkPermission(context, sourceAuditPid, targetContext, perm, interface);
|
||||
|
||||
freecon(targetContext);
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
int AccessControl::auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
|
||||
struct audit_data *ad = (struct audit_data *)data;
|
||||
|
||||
if (!ad || !ad->interfaceName) {
|
||||
ALOGE("No valid hwservicemanager audit data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(buf, len, "interface=%s pid=%d", ad->interfaceName, ad->pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace android
|
31
android/system/hwservicemanager/AccessControl.h
Normal file
31
android/system/hwservicemanager/AccessControl.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include <string>
|
||||
|
||||
#include <selinux/android.h>
|
||||
#include <selinux/avc.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class AccessControl {
|
||||
public:
|
||||
AccessControl();
|
||||
|
||||
using Context = std::unique_ptr<char, decltype(&freecon)>;
|
||||
Context getContext(pid_t sourcePid);
|
||||
|
||||
bool canAdd(const std::string& fqName, const Context &context, pid_t pid);
|
||||
bool canGet(const std::string& fqName, pid_t pid);
|
||||
bool canList(pid_t pid);
|
||||
|
||||
private:
|
||||
|
||||
bool checkPermission(const Context &context, pid_t sourceAuditPid, const char *targetContext, const char *perm, const char *interface);
|
||||
bool checkPermission(const Context &context, pid_t sourcePid, const char *perm, const char *interface);
|
||||
|
||||
static int auditCallback(void *data, security_class_t cls, char *buf, size_t len);
|
||||
|
||||
char* mSeContext;
|
||||
struct selabel_handle* mSeHandle;
|
||||
union selinux_callback mSeCallbacks;
|
||||
};
|
||||
|
||||
} // namespace android
|
52
android/system/hwservicemanager/Android.bp
Normal file
52
android/system/hwservicemanager/Android.bp
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
cc_binary {
|
||||
name: "hwservicemanager",
|
||||
init_rc: [
|
||||
"hwservicemanager.rc",
|
||||
],
|
||||
srcs: [
|
||||
"AccessControl.cpp",
|
||||
"HidlService.cpp",
|
||||
"ServiceManager.cpp",
|
||||
"service.cpp",
|
||||
"TokenManager.cpp",
|
||||
"Vintf.cpp",
|
||||
],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hidl.token@1.0",
|
||||
"libbase",
|
||||
"libcrypto", // for TokenManager
|
||||
"libcutils",
|
||||
"libhidlbase",
|
||||
"libhidltransport",
|
||||
"libhidl-gen-utils",
|
||||
"libhwbinder",
|
||||
"liblog",
|
||||
"libselinux",
|
||||
"libutils",
|
||||
"libvintf",
|
||||
],
|
||||
product_variables: {
|
||||
binder32bit: {
|
||||
cflags: ["-DBINDER_IPC_32BIT=1"],
|
||||
},
|
||||
},
|
||||
}
|
112
android/system/hwservicemanager/HidlService.cpp
Normal file
112
android/system/hwservicemanager/HidlService.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
#define LOG_TAG "hwservicemanager"
|
||||
#include "HidlService.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <hidl/HidlTransportSupport.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace android {
|
||||
namespace hidl {
|
||||
namespace manager {
|
||||
namespace implementation {
|
||||
|
||||
HidlService::HidlService(
|
||||
const std::string &interfaceName,
|
||||
const std::string &instanceName,
|
||||
const sp<IBase> &service,
|
||||
pid_t pid)
|
||||
: mInterfaceName(interfaceName),
|
||||
mInstanceName(instanceName),
|
||||
mService(service),
|
||||
mPid(pid)
|
||||
{}
|
||||
|
||||
sp<IBase> HidlService::getService() const {
|
||||
return mService;
|
||||
}
|
||||
void HidlService::setService(sp<IBase> service, pid_t pid) {
|
||||
mService = service;
|
||||
mPid = pid;
|
||||
|
||||
sendRegistrationNotifications();
|
||||
}
|
||||
|
||||
pid_t HidlService::getPid() const {
|
||||
return mPid;
|
||||
}
|
||||
const std::string &HidlService::getInterfaceName() const {
|
||||
return mInterfaceName;
|
||||
}
|
||||
const std::string &HidlService::getInstanceName() const {
|
||||
return mInstanceName;
|
||||
}
|
||||
|
||||
void HidlService::addListener(const sp<IServiceNotification> &listener) {
|
||||
if (mService != nullptr) {
|
||||
auto ret = listener->onRegistration(
|
||||
mInterfaceName, mInstanceName, true /* preexisting */);
|
||||
if (!ret.isOk()) {
|
||||
LOG(ERROR) << "Not adding listener for " << mInterfaceName << "/"
|
||||
<< mInstanceName << ": transport error when sending "
|
||||
<< "notification for already registered instance.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
mListeners.push_back(listener);
|
||||
}
|
||||
|
||||
bool HidlService::removeListener(const wp<IBase>& listener) {
|
||||
using ::android::hardware::interfacesEqual;
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto it = mListeners.begin(); it != mListeners.end();) {
|
||||
if (interfacesEqual(*it, listener.promote())) {
|
||||
it = mListeners.erase(it);
|
||||
found = true;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void HidlService::registerPassthroughClient(pid_t pid) {
|
||||
mPassthroughClients.insert(pid);
|
||||
}
|
||||
|
||||
const std::set<pid_t> &HidlService::getPassthroughClients() const {
|
||||
return mPassthroughClients;
|
||||
}
|
||||
|
||||
std::string HidlService::string() const {
|
||||
std::stringstream ss;
|
||||
ss << mInterfaceName << "/" << mInstanceName;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void HidlService::sendRegistrationNotifications() {
|
||||
if (mListeners.size() == 0 || mService == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
hidl_string iface = mInterfaceName;
|
||||
hidl_string name = mInstanceName;
|
||||
|
||||
for (auto it = mListeners.begin(); it != mListeners.end();) {
|
||||
auto ret = (*it)->onRegistration(iface, name, false /* preexisting */);
|
||||
if (ret.isOk()) {
|
||||
++it;
|
||||
} else {
|
||||
LOG(ERROR) << "Dropping registration callback for " << iface << "/" << name
|
||||
<< ": transport error.";
|
||||
it = mListeners.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace manager
|
||||
} // namespace hidl
|
||||
} // namespace android
|
72
android/system/hwservicemanager/HidlService.h
Normal file
72
android/system/hwservicemanager/HidlService.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
#ifndef ANDROID_HARDWARE_MANAGER_HIDLSERVICE_H
|
||||
#define ANDROID_HARDWARE_MANAGER_HIDLSERVICE_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <android/hidl/manager/1.1/IServiceManager.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <hidl/MQDescriptor.h>
|
||||
|
||||
namespace android {
|
||||
namespace hidl {
|
||||
namespace manager {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::hardware::hidl_vec;
|
||||
using ::android::hardware::hidl_string;
|
||||
using ::android::hardware::Return;
|
||||
using ::android::hardware::Void;
|
||||
using ::android::hidl::base::V1_0::IBase;
|
||||
using ::android::hidl::manager::V1_0::IServiceNotification;
|
||||
using ::android::hidl::manager::V1_1::IServiceManager;
|
||||
using ::android::sp;
|
||||
|
||||
struct HidlService {
|
||||
HidlService(const std::string &interfaceName,
|
||||
const std::string &instanceName,
|
||||
const sp<IBase> &service,
|
||||
const pid_t pid);
|
||||
HidlService(const std::string &interfaceName,
|
||||
const std::string &instanceName)
|
||||
: HidlService(
|
||||
interfaceName,
|
||||
instanceName,
|
||||
nullptr,
|
||||
static_cast<pid_t>(IServiceManager::PidConstant::NO_PID))
|
||||
{}
|
||||
|
||||
/**
|
||||
* Note, getService() can be nullptr. This is because you can have a HidlService
|
||||
* with registered IServiceNotification objects but no service registered yet.
|
||||
*/
|
||||
sp<IBase> getService() const;
|
||||
void setService(sp<IBase> service, pid_t pid);
|
||||
pid_t getPid() const;
|
||||
const std::string &getInterfaceName() const;
|
||||
const std::string &getInstanceName() const;
|
||||
|
||||
void addListener(const sp<IServiceNotification> &listener);
|
||||
bool removeListener(const wp<IBase> &listener);
|
||||
void registerPassthroughClient(pid_t pid);
|
||||
|
||||
std::string string() const; // e.x. "android.hidl.manager@1.0::IServiceManager/manager"
|
||||
const std::set<pid_t> &getPassthroughClients() const;
|
||||
|
||||
private:
|
||||
void sendRegistrationNotifications();
|
||||
|
||||
const std::string mInterfaceName; // e.x. "android.hidl.manager@1.0::IServiceManager"
|
||||
const std::string mInstanceName; // e.x. "manager"
|
||||
sp<IBase> mService;
|
||||
|
||||
std::vector<sp<IServiceNotification>> mListeners{};
|
||||
std::set<pid_t> mPassthroughClients{};
|
||||
pid_t mPid = static_cast<pid_t>(IServiceManager::PidConstant::NO_PID);
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace manager
|
||||
} // namespace hidl
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HARDWARE_MANAGER_HIDLSERVICE_H
|
0
android/system/hwservicemanager/MODULE_LICENSE_APACHE2
Normal file
0
android/system/hwservicemanager/MODULE_LICENSE_APACHE2
Normal file
202
android/system/hwservicemanager/NOTICE
Normal file
202
android/system/hwservicemanager/NOTICE
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
4
android/system/hwservicemanager/OWNERS
Normal file
4
android/system/hwservicemanager/OWNERS
Normal file
|
@ -0,0 +1,4 @@
|
|||
elsk@google.com
|
||||
maco@google.com
|
||||
malchev@google.com
|
||||
smoreland@google.com
|
507
android/system/hwservicemanager/ServiceManager.cpp
Normal file
507
android/system/hwservicemanager/ServiceManager.cpp
Normal file
|
@ -0,0 +1,507 @@
|
|||
#define LOG_TAG "hwservicemanager"
|
||||
|
||||
#include "ServiceManager.h"
|
||||
#include "Vintf.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <hwbinder/IPCThreadState.h>
|
||||
#include <hidl/HidlSupport.h>
|
||||
#include <hidl/HidlTransportSupport.h>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
using android::hardware::IPCThreadState;
|
||||
|
||||
namespace android {
|
||||
namespace hidl {
|
||||
namespace manager {
|
||||
namespace implementation {
|
||||
|
||||
static constexpr uint64_t kServiceDiedCookie = 0;
|
||||
static constexpr uint64_t kPackageListenerDiedCookie = 1;
|
||||
static constexpr uint64_t kServiceListenerDiedCookie = 2;
|
||||
|
||||
size_t ServiceManager::countExistingService() const {
|
||||
size_t total = 0;
|
||||
forEachExistingService([&] (const HidlService *) {
|
||||
++total;
|
||||
});
|
||||
return total;
|
||||
}
|
||||
|
||||
void ServiceManager::forEachExistingService(std::function<void(const HidlService *)> f) const {
|
||||
forEachServiceEntry([f] (const HidlService *service) {
|
||||
if (service->getService() == nullptr) {
|
||||
return;
|
||||
}
|
||||
f(service);
|
||||
});
|
||||
}
|
||||
|
||||
void ServiceManager::forEachServiceEntry(std::function<void(const HidlService *)> f) const {
|
||||
for (const auto &interfaceMapping : mServiceMap) {
|
||||
const auto &instanceMap = interfaceMapping.second.getInstanceMap();
|
||||
|
||||
for (const auto &instanceMapping : instanceMap) {
|
||||
f(instanceMapping.second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceManager::serviceDied(uint64_t cookie, const wp<IBase>& who) {
|
||||
switch (cookie) {
|
||||
case kServiceDiedCookie:
|
||||
removeService(who);
|
||||
break;
|
||||
case kPackageListenerDiedCookie:
|
||||
removePackageListener(who);
|
||||
break;
|
||||
case kServiceListenerDiedCookie:
|
||||
removeServiceListener(who);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ServiceManager::InstanceMap &ServiceManager::PackageInterfaceMap::getInstanceMap() {
|
||||
return mInstanceMap;
|
||||
}
|
||||
|
||||
const ServiceManager::InstanceMap &ServiceManager::PackageInterfaceMap::getInstanceMap() const {
|
||||
return mInstanceMap;
|
||||
}
|
||||
|
||||
const HidlService *ServiceManager::PackageInterfaceMap::lookup(
|
||||
const std::string &name) const {
|
||||
auto it = mInstanceMap.find(name);
|
||||
|
||||
if (it == mInstanceMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
HidlService *ServiceManager::PackageInterfaceMap::lookup(
|
||||
const std::string &name) {
|
||||
|
||||
return const_cast<HidlService*>(
|
||||
const_cast<const PackageInterfaceMap*>(this)->lookup(name));
|
||||
}
|
||||
|
||||
void ServiceManager::PackageInterfaceMap::insertService(
|
||||
std::unique_ptr<HidlService> &&service) {
|
||||
mInstanceMap.insert({service->getInstanceName(), std::move(service)});
|
||||
}
|
||||
|
||||
void ServiceManager::PackageInterfaceMap::sendPackageRegistrationNotification(
|
||||
const hidl_string &fqName,
|
||||
const hidl_string &instanceName) {
|
||||
|
||||
for (auto it = mPackageListeners.begin(); it != mPackageListeners.end();) {
|
||||
auto ret = (*it)->onRegistration(fqName, instanceName, false /* preexisting */);
|
||||
if (ret.isOk()) {
|
||||
++it;
|
||||
} else {
|
||||
LOG(ERROR) << "Dropping registration callback for " << fqName << "/" << instanceName
|
||||
<< ": transport error.";
|
||||
it = mPackageListeners.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceManager::PackageInterfaceMap::addPackageListener(sp<IServiceNotification> listener) {
|
||||
for (const auto &instanceMapping : mInstanceMap) {
|
||||
const std::unique_ptr<HidlService> &service = instanceMapping.second;
|
||||
|
||||
if (service->getService() == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ret = listener->onRegistration(
|
||||
service->getInterfaceName(),
|
||||
service->getInstanceName(),
|
||||
true /* preexisting */);
|
||||
if (!ret.isOk()) {
|
||||
LOG(ERROR) << "Not adding package listener for " << service->getInterfaceName()
|
||||
<< "/" << service->getInstanceName() << ": transport error "
|
||||
<< "when sending notification for already registered instance.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
mPackageListeners.push_back(listener);
|
||||
}
|
||||
|
||||
bool ServiceManager::PackageInterfaceMap::removePackageListener(const wp<IBase>& who) {
|
||||
using ::android::hardware::interfacesEqual;
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto it = mPackageListeners.begin(); it != mPackageListeners.end();) {
|
||||
if (interfacesEqual(*it, who.promote())) {
|
||||
it = mPackageListeners.erase(it);
|
||||
found = true;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool ServiceManager::PackageInterfaceMap::removeServiceListener(const wp<IBase>& who) {
|
||||
using ::android::hardware::interfacesEqual;
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto &servicePair : getInstanceMap()) {
|
||||
const std::unique_ptr<HidlService> &service = servicePair.second;
|
||||
found |= service->removeListener(who);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// Methods from ::android::hidl::manager::V1_0::IServiceManager follow.
|
||||
Return<sp<IBase>> ServiceManager::get(const hidl_string& fqName,
|
||||
const hidl_string& name) {
|
||||
pid_t pid = IPCThreadState::self()->getCallingPid();
|
||||
if (!mAcl.canGet(fqName, pid)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ifaceIt = mServiceMap.find(fqName);
|
||||
if (ifaceIt == mServiceMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const PackageInterfaceMap &ifaceMap = ifaceIt->second;
|
||||
const HidlService *hidlService = ifaceMap.lookup(name);
|
||||
|
||||
if (hidlService == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hidlService->getService();
|
||||
}
|
||||
|
||||
Return<bool> ServiceManager::add(const hidl_string& name, const sp<IBase>& service) {
|
||||
bool isValidService = false;
|
||||
|
||||
if (service == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(b/34235311): use HIDL way to determine this
|
||||
// also, this assumes that the PID that is registering is the pid that is the service
|
||||
pid_t pid = IPCThreadState::self()->getCallingPid();
|
||||
auto context = mAcl.getContext(pid);
|
||||
|
||||
auto ret = service->interfaceChain([&](const auto &interfaceChain) {
|
||||
if (interfaceChain.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First, verify you're allowed to add() the whole interface hierarchy
|
||||
for(size_t i = 0; i < interfaceChain.size(); i++) {
|
||||
std::string fqName = interfaceChain[i];
|
||||
|
||||
if (!mAcl.canAdd(fqName, context, pid)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < interfaceChain.size(); i++) {
|
||||
std::string fqName = interfaceChain[i];
|
||||
|
||||
PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
|
||||
HidlService *hidlService = ifaceMap.lookup(name);
|
||||
|
||||
if (hidlService == nullptr) {
|
||||
ifaceMap.insertService(
|
||||
std::make_unique<HidlService>(fqName, name, service, pid));
|
||||
} else {
|
||||
if (hidlService->getService() != nullptr) {
|
||||
auto ret = hidlService->getService()->unlinkToDeath(this);
|
||||
ret.isOk(); // ignore
|
||||
}
|
||||
hidlService->setService(service, pid);
|
||||
}
|
||||
|
||||
ifaceMap.sendPackageRegistrationNotification(fqName, name);
|
||||
}
|
||||
|
||||
auto linkRet = service->linkToDeath(this, 0 /*cookie*/);
|
||||
linkRet.isOk(); // ignore
|
||||
|
||||
isValidService = true;
|
||||
});
|
||||
|
||||
if (!ret.isOk()) {
|
||||
LOG(ERROR) << "Failed to retrieve interface chain.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return isValidService;
|
||||
}
|
||||
|
||||
Return<ServiceManager::Transport> ServiceManager::getTransport(const hidl_string& fqName,
|
||||
const hidl_string& name) {
|
||||
using ::android::hardware::getTransport;
|
||||
|
||||
pid_t pid = IPCThreadState::self()->getCallingPid();
|
||||
if (!mAcl.canGet(fqName, pid)) {
|
||||
return Transport::EMPTY;
|
||||
}
|
||||
|
||||
switch (getTransport(fqName, name)) {
|
||||
case vintf::Transport::HWBINDER:
|
||||
return Transport::HWBINDER;
|
||||
case vintf::Transport::PASSTHROUGH:
|
||||
return Transport::PASSTHROUGH;
|
||||
case vintf::Transport::EMPTY:
|
||||
default:
|
||||
return Transport::EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
Return<void> ServiceManager::list(list_cb _hidl_cb) {
|
||||
pid_t pid = IPCThreadState::self()->getCallingPid();
|
||||
if (!mAcl.canList(pid)) {
|
||||
_hidl_cb({});
|
||||
return Void();
|
||||
}
|
||||
|
||||
hidl_vec<hidl_string> list;
|
||||
|
||||
list.resize(countExistingService());
|
||||
|
||||
size_t idx = 0;
|
||||
forEachExistingService([&] (const HidlService *service) {
|
||||
list[idx++] = service->string();
|
||||
});
|
||||
|
||||
_hidl_cb(list);
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> ServiceManager::listByInterface(const hidl_string& fqName,
|
||||
listByInterface_cb _hidl_cb) {
|
||||
pid_t pid = IPCThreadState::self()->getCallingPid();
|
||||
if (!mAcl.canGet(fqName, pid)) {
|
||||
_hidl_cb({});
|
||||
return Void();
|
||||
}
|
||||
|
||||
auto ifaceIt = mServiceMap.find(fqName);
|
||||
if (ifaceIt == mServiceMap.end()) {
|
||||
_hidl_cb(hidl_vec<hidl_string>());
|
||||
return Void();
|
||||
}
|
||||
|
||||
const auto &instanceMap = ifaceIt->second.getInstanceMap();
|
||||
|
||||
hidl_vec<hidl_string> list;
|
||||
|
||||
size_t total = 0;
|
||||
for (const auto &serviceMapping : instanceMap) {
|
||||
const std::unique_ptr<HidlService> &service = serviceMapping.second;
|
||||
if (service->getService() == nullptr) continue;
|
||||
|
||||
++total;
|
||||
}
|
||||
list.resize(total);
|
||||
|
||||
size_t idx = 0;
|
||||
for (const auto &serviceMapping : instanceMap) {
|
||||
const std::unique_ptr<HidlService> &service = serviceMapping.second;
|
||||
if (service->getService() == nullptr) continue;
|
||||
|
||||
list[idx++] = service->getInstanceName();
|
||||
}
|
||||
|
||||
_hidl_cb(list);
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<bool> ServiceManager::registerForNotifications(const hidl_string& fqName,
|
||||
const hidl_string& name,
|
||||
const sp<IServiceNotification>& callback) {
|
||||
if (callback == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pid_t pid = IPCThreadState::self()->getCallingPid();
|
||||
if (!mAcl.canGet(fqName, pid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
|
||||
|
||||
if (name.empty()) {
|
||||
auto ret = callback->linkToDeath(this, kPackageListenerDiedCookie /*cookie*/);
|
||||
if (!ret.isOk()) {
|
||||
LOG(ERROR) << "Failed to register death recipient for " << fqName << "/" << name;
|
||||
return false;
|
||||
}
|
||||
ifaceMap.addPackageListener(callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
HidlService *service = ifaceMap.lookup(name);
|
||||
|
||||
auto ret = callback->linkToDeath(this, kServiceListenerDiedCookie);
|
||||
if (!ret.isOk()) {
|
||||
LOG(ERROR) << "Failed to register death recipient for " << fqName << "/" << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (service == nullptr) {
|
||||
auto adding = std::make_unique<HidlService>(fqName, name);
|
||||
adding->addListener(callback);
|
||||
ifaceMap.insertService(std::move(adding));
|
||||
} else {
|
||||
service->addListener(callback);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Return<bool> ServiceManager::unregisterForNotifications(const hidl_string& fqName,
|
||||
const hidl_string& name,
|
||||
const sp<IServiceNotification>& callback) {
|
||||
if (callback == nullptr) {
|
||||
LOG(ERROR) << "Cannot unregister null callback for " << fqName << "/" << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: don't need ACL since callback is binder token, and if someone has gotten it,
|
||||
// then they already have access to it.
|
||||
|
||||
if (fqName.empty()) {
|
||||
bool success = false;
|
||||
success |= removePackageListener(callback);
|
||||
success |= removeServiceListener(callback);
|
||||
return success;
|
||||
}
|
||||
|
||||
PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
|
||||
|
||||
if (name.empty()) {
|
||||
bool success = false;
|
||||
success |= ifaceMap.removePackageListener(callback);
|
||||
success |= ifaceMap.removeServiceListener(callback);
|
||||
return success;
|
||||
}
|
||||
|
||||
HidlService *service = ifaceMap.lookup(name);
|
||||
|
||||
if (service == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return service->removeListener(callback);
|
||||
}
|
||||
|
||||
Return<void> ServiceManager::debugDump(debugDump_cb _cb) {
|
||||
pid_t pid = IPCThreadState::self()->getCallingPid();
|
||||
if (!mAcl.canList(pid)) {
|
||||
_cb({});
|
||||
return Void();
|
||||
}
|
||||
|
||||
std::vector<IServiceManager::InstanceDebugInfo> list;
|
||||
forEachServiceEntry([&] (const HidlService *service) {
|
||||
hidl_vec<int32_t> clientPids;
|
||||
clientPids.resize(service->getPassthroughClients().size());
|
||||
|
||||
size_t i = 0;
|
||||
for (pid_t p : service->getPassthroughClients()) {
|
||||
clientPids[i++] = p;
|
||||
}
|
||||
|
||||
list.push_back({
|
||||
.pid = service->getPid(),
|
||||
.interfaceName = service->getInterfaceName(),
|
||||
.instanceName = service->getInstanceName(),
|
||||
.clientPids = clientPids,
|
||||
.arch = ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN
|
||||
});
|
||||
});
|
||||
|
||||
_cb(list);
|
||||
return Void();
|
||||
}
|
||||
|
||||
|
||||
Return<void> ServiceManager::registerPassthroughClient(const hidl_string &fqName,
|
||||
const hidl_string &name) {
|
||||
pid_t pid = IPCThreadState::self()->getCallingPid();
|
||||
if (!mAcl.canGet(fqName, pid)) {
|
||||
/* We guard this function with "get", because it's typically used in
|
||||
* the getService() path, albeit for a passthrough service in this
|
||||
* case
|
||||
*/
|
||||
return Void();
|
||||
}
|
||||
|
||||
PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
|
||||
|
||||
if (name.empty()) {
|
||||
LOG(WARNING) << "registerPassthroughClient encounters empty instance name for "
|
||||
<< fqName.c_str();
|
||||
return Void();
|
||||
}
|
||||
|
||||
HidlService *service = ifaceMap.lookup(name);
|
||||
|
||||
if (service == nullptr) {
|
||||
auto adding = std::make_unique<HidlService>(fqName, name);
|
||||
adding->registerPassthroughClient(pid);
|
||||
ifaceMap.insertService(std::move(adding));
|
||||
} else {
|
||||
service->registerPassthroughClient(pid);
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
|
||||
bool ServiceManager::removeService(const wp<IBase>& who) {
|
||||
using ::android::hardware::interfacesEqual;
|
||||
|
||||
bool found = false;
|
||||
for (auto &interfaceMapping : mServiceMap) {
|
||||
auto &instanceMap = interfaceMapping.second.getInstanceMap();
|
||||
|
||||
for (auto &servicePair : instanceMap) {
|
||||
const std::unique_ptr<HidlService> &service = servicePair.second;
|
||||
if (interfacesEqual(service->getService(), who.promote())) {
|
||||
service->setService(nullptr, static_cast<pid_t>(IServiceManager::PidConstant::NO_PID));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool ServiceManager::removePackageListener(const wp<IBase>& who) {
|
||||
bool found = false;
|
||||
|
||||
for (auto &interfaceMapping : mServiceMap) {
|
||||
found |= interfaceMapping.second.removePackageListener(who);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool ServiceManager::removeServiceListener(const wp<IBase>& who) {
|
||||
bool found = false;
|
||||
for (auto &interfaceMapping : mServiceMap) {
|
||||
auto &packageInterfaceMap = interfaceMapping.second;
|
||||
|
||||
found |= packageInterfaceMap.removeServiceListener(who);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
} // namespace implementation
|
||||
} // namespace manager
|
||||
} // namespace hidl
|
||||
} // namespace android
|
121
android/system/hwservicemanager/ServiceManager.h
Normal file
121
android/system/hwservicemanager/ServiceManager.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
#ifndef ANDROID_HARDWARE_MANAGER_SERVICEMANAGER_H
|
||||
#define ANDROID_HARDWARE_MANAGER_SERVICEMANAGER_H
|
||||
|
||||
#include <android/hidl/manager/1.1/IServiceManager.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <hidl/MQDescriptor.h>
|
||||
#include <map>
|
||||
|
||||
#include "AccessControl.h"
|
||||
#include "HidlService.h"
|
||||
|
||||
namespace android {
|
||||
namespace hidl {
|
||||
namespace manager {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::hardware::hidl_death_recipient;
|
||||
using ::android::hardware::hidl_vec;
|
||||
using ::android::hardware::hidl_string;
|
||||
using ::android::hardware::Return;
|
||||
using ::android::hardware::Void;
|
||||
using ::android::hidl::base::V1_0::IBase;
|
||||
using ::android::hidl::manager::V1_1::IServiceManager;
|
||||
using ::android::hidl::manager::V1_0::IServiceNotification;
|
||||
using ::android::sp;
|
||||
using ::android::wp;
|
||||
|
||||
struct ServiceManager : public IServiceManager, hidl_death_recipient {
|
||||
// Methods from ::android::hidl::manager::V1_0::IServiceManager follow.
|
||||
Return<sp<IBase>> get(const hidl_string& fqName,
|
||||
const hidl_string& name) override;
|
||||
Return<bool> add(const hidl_string& name,
|
||||
const sp<IBase>& service) override;
|
||||
|
||||
Return<Transport> getTransport(const hidl_string& fqName,
|
||||
const hidl_string& name);
|
||||
|
||||
Return<void> list(list_cb _hidl_cb) override;
|
||||
Return<void> listByInterface(const hidl_string& fqInstanceName,
|
||||
listByInterface_cb _hidl_cb) override;
|
||||
|
||||
Return<bool> registerForNotifications(const hidl_string& fqName,
|
||||
const hidl_string& name,
|
||||
const sp<IServiceNotification>& callback) override;
|
||||
|
||||
Return<void> debugDump(debugDump_cb _cb) override;
|
||||
Return<void> registerPassthroughClient(const hidl_string &fqName,
|
||||
const hidl_string &name) override;
|
||||
|
||||
// Methods from ::android::hidl::manager::V1_1::IServiceManager follow.
|
||||
Return<bool> unregisterForNotifications(const hidl_string& fqName,
|
||||
const hidl_string& name,
|
||||
const sp<IServiceNotification>& callback) override;
|
||||
|
||||
virtual void serviceDied(uint64_t cookie, const wp<IBase>& who);
|
||||
private:
|
||||
bool removeService(const wp<IBase>& who);
|
||||
bool removePackageListener(const wp<IBase>& who);
|
||||
bool removeServiceListener(const wp<IBase>& who);
|
||||
size_t countExistingService() const;
|
||||
void forEachExistingService(std::function<void(const HidlService *)> f) const;
|
||||
void forEachServiceEntry(std::function<void(const HidlService *)> f) const;
|
||||
|
||||
using InstanceMap = std::map<
|
||||
std::string, // instance name e.x. "manager"
|
||||
std::unique_ptr<HidlService>
|
||||
>;
|
||||
|
||||
struct PackageInterfaceMap {
|
||||
InstanceMap &getInstanceMap();
|
||||
const InstanceMap &getInstanceMap() const;
|
||||
|
||||
/**
|
||||
* Finds a HidlService with the desired name. If none,
|
||||
* returns nullptr. HidlService::getService() might also be nullptr
|
||||
* if there are registered IServiceNotification objects for it. Return
|
||||
* value should be treated as a temporary reference.
|
||||
*/
|
||||
HidlService *lookup(
|
||||
const std::string &name);
|
||||
const HidlService *lookup(
|
||||
const std::string &name) const;
|
||||
|
||||
void insertService(std::unique_ptr<HidlService> &&service);
|
||||
|
||||
void addPackageListener(sp<IServiceNotification> listener);
|
||||
bool removePackageListener(const wp<IBase>& who);
|
||||
bool removeServiceListener(const wp<IBase>& who);
|
||||
|
||||
void sendPackageRegistrationNotification(
|
||||
const hidl_string &fqName,
|
||||
const hidl_string &instanceName);
|
||||
|
||||
private:
|
||||
InstanceMap mInstanceMap{};
|
||||
|
||||
std::vector<sp<IServiceNotification>> mPackageListeners{};
|
||||
};
|
||||
|
||||
AccessControl mAcl;
|
||||
|
||||
/**
|
||||
* Access to this map doesn't need to be locked, since hwservicemanager
|
||||
* is single-threaded.
|
||||
*
|
||||
* e.x.
|
||||
* mServiceMap["android.hidl.manager@1.0::IServiceManager"]["manager"]
|
||||
* -> HidlService object
|
||||
*/
|
||||
std::map<
|
||||
std::string, // package::interface e.x. "android.hidl.manager@1.0::IServiceManager"
|
||||
PackageInterfaceMap
|
||||
> mServiceMap;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace manager
|
||||
} // namespace hidl
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HARDWARE_MANAGER_SERVICEMANAGER_H
|
177
android/system/hwservicemanager/TokenManager.cpp
Normal file
177
android/system/hwservicemanager/TokenManager.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
#define LOG_TAG "hwservicemanager"
|
||||
|
||||
#include "TokenManager.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <functional>
|
||||
#include <log/log.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
namespace android {
|
||||
namespace hidl {
|
||||
namespace token {
|
||||
namespace V1_0 {
|
||||
namespace implementation {
|
||||
|
||||
static void ReadRandomBytes(uint8_t *buf, size_t len) {
|
||||
int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
|
||||
if (fd == -1) {
|
||||
ALOGE("%s: cannot read /dev/urandom", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t n;
|
||||
while ((n = TEMP_FAILURE_RETRY(read(fd, buf, len))) > 0) {
|
||||
len -= n;
|
||||
buf += n;
|
||||
}
|
||||
if (len > 0) {
|
||||
ALOGW("%s: there are %d bytes skipped", __func__, (int)len);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
TokenManager::TokenManager() {
|
||||
ReadRandomBytes(mKey.data(), mKey.size());
|
||||
}
|
||||
|
||||
// Methods from ::android::hidl::token::V1_0::ITokenManager follow.
|
||||
Return<void> TokenManager::createToken(const sp<IBase>& store, createToken_cb hidl_cb) {
|
||||
TokenInterface interface = generateToken(store);
|
||||
|
||||
if (interface.interface == nullptr) {
|
||||
hidl_cb({});
|
||||
return Void();
|
||||
}
|
||||
|
||||
uint64_t id = getTokenId(interface.token);
|
||||
|
||||
if (id == TOKEN_ID_NONE) {
|
||||
hidl_cb({});
|
||||
return Void();
|
||||
}
|
||||
|
||||
mMap[id] = interface;
|
||||
|
||||
hidl_cb(interface.token);
|
||||
return Void();
|
||||
}
|
||||
|
||||
std::unordered_map<uint64_t, TokenManager::TokenInterface>::const_iterator
|
||||
TokenManager::lookupToken(const hidl_vec<uint8_t> &token) {
|
||||
uint64_t tokenId = getTokenId(token);
|
||||
|
||||
if (tokenId == TOKEN_ID_NONE) {
|
||||
return mMap.end();
|
||||
}
|
||||
|
||||
auto it = mMap.find(tokenId);
|
||||
|
||||
if (it == mMap.end()) {
|
||||
return mMap.end();
|
||||
}
|
||||
|
||||
const TokenInterface &interface = it->second;
|
||||
|
||||
if (!constantTimeCompare(token, interface.token)) {
|
||||
ALOGE("Fetch of token with invalid hash.");
|
||||
return mMap.end();
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
Return<bool> TokenManager::unregister(const hidl_vec<uint8_t> &token) {
|
||||
auto it = lookupToken(token);
|
||||
|
||||
if (it == mMap.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mMap.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
Return<sp<IBase>> TokenManager::get(const hidl_vec<uint8_t> &token) {
|
||||
auto it = lookupToken(token);
|
||||
|
||||
if (it == mMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return it->second.interface;
|
||||
}
|
||||
|
||||
|
||||
TokenManager::TokenInterface TokenManager::generateToken(const sp<IBase> &interface) {
|
||||
uint64_t id = ++mTokenIndex;
|
||||
|
||||
std::array<uint8_t, EVP_MAX_MD_SIZE> hmac;
|
||||
uint32_t hmacSize;
|
||||
|
||||
uint8_t *hmacOut = HMAC(EVP_sha256(),
|
||||
mKey.data(), mKey.size(),
|
||||
(uint8_t*) &id, ID_SIZE,
|
||||
hmac.data(), &hmacSize);
|
||||
|
||||
if (hmacOut == nullptr ||
|
||||
hmacOut != hmac.data()) {
|
||||
ALOGE("Generating token failed, got %p.", hmacOut);
|
||||
return { nullptr, {} };
|
||||
}
|
||||
|
||||
// only care about the first HMAC_SIZE bytes of the HMAC
|
||||
const hidl_vec<uint8_t> &token = TokenManager::getToken(id, hmac.data(), hmacSize);
|
||||
|
||||
return { interface, token };
|
||||
}
|
||||
|
||||
__attribute__((optnone))
|
||||
bool TokenManager::constantTimeCompare(const hidl_vec<uint8_t> &t1, const hidl_vec<uint8_t> &t2) {
|
||||
if (t1.size() != t2.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t x = 0;
|
||||
for (size_t i = 0; i < t1.size(); i++) {
|
||||
x |= t1[i] ^ t2[i];
|
||||
}
|
||||
|
||||
return x == 0;
|
||||
}
|
||||
|
||||
uint64_t TokenManager::getTokenId(const hidl_vec<uint8_t> &token) {
|
||||
if (token.size() < ID_SIZE) {
|
||||
return TOKEN_ID_NONE;
|
||||
}
|
||||
|
||||
uint64_t id = 0;
|
||||
for (size_t i = 0; i < ID_SIZE; i++) {
|
||||
id |= token[i] << i;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
hidl_vec<uint8_t> TokenManager::getToken(const uint64_t id, const uint8_t *hmac, uint64_t hmacSize) {
|
||||
hidl_vec<uint8_t> token;
|
||||
token.resize(ID_SIZE + hmacSize);
|
||||
|
||||
for (size_t i = 0; i < ID_SIZE; i++) {
|
||||
token[i] = (id >> i) & 0xFF;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < hmacSize; i++) {
|
||||
token[i + ID_SIZE] = hmac[i];
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace token
|
||||
} // namespace hidl
|
||||
} // namespace android
|
68
android/system/hwservicemanager/TokenManager.h
Normal file
68
android/system/hwservicemanager/TokenManager.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
#ifndef ANDROID_HIDL_TOKEN_V1_0_TOKENMANAGER_H
|
||||
#define ANDROID_HIDL_TOKEN_V1_0_TOKENMANAGER_H
|
||||
|
||||
#include <android/hidl/token/1.0/ITokenManager.h>
|
||||
#include <chrono>
|
||||
#include <hidl/MQDescriptor.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <unordered_map>
|
||||
#include <array>
|
||||
|
||||
namespace android {
|
||||
namespace hidl {
|
||||
namespace token {
|
||||
namespace V1_0 {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::hidl::base::V1_0::IBase;
|
||||
using ::android::hidl::token::V1_0::ITokenManager;
|
||||
using ::android::hardware::hidl_array;
|
||||
using ::android::hardware::hidl_string;
|
||||
using ::android::hardware::hidl_vec;
|
||||
using ::android::hardware::Return;
|
||||
using ::android::hardware::Void;
|
||||
using ::android::sp;
|
||||
|
||||
struct TokenManager : public ITokenManager {
|
||||
TokenManager();
|
||||
|
||||
// Methods from ::android::hidl::token::V1_0::ITokenManager follow.
|
||||
Return<void> createToken(const sp<IBase>& store, createToken_cb hidl_cb) override;
|
||||
Return<bool> unregister(const hidl_vec<uint8_t> &token) override;
|
||||
Return<sp<IBase>> get(const hidl_vec<uint8_t> &token) override;
|
||||
|
||||
private:
|
||||
static constexpr uint64_t ID_SIZE = sizeof(uint64_t) / sizeof(uint8_t);
|
||||
static constexpr uint64_t KEY_SIZE = 16;
|
||||
|
||||
static constexpr uint64_t TOKEN_ID_NONE = 0;
|
||||
|
||||
static bool constantTimeCompare(const hidl_vec<uint8_t> &t1, const hidl_vec<uint8_t> &t2);
|
||||
|
||||
static hidl_vec<uint8_t> getToken(const uint64_t id, const uint8_t *hmac, uint64_t hmacSize);
|
||||
static uint64_t getTokenId(const hidl_vec<uint8_t> &token);
|
||||
|
||||
std::array<uint8_t, KEY_SIZE> mKey;
|
||||
|
||||
struct TokenInterface {
|
||||
sp<IBase> interface;
|
||||
hidl_vec<uint8_t> token; // First eight bytes are tokenId. Remaining bytes are hmac.
|
||||
};
|
||||
|
||||
TokenInterface generateToken(const sp<IBase> &interface);
|
||||
|
||||
// verifies token, returns iterator into mMap
|
||||
std::unordered_map<uint64_t, TokenInterface>::const_iterator
|
||||
lookupToken(const hidl_vec<uint8_t> &token);
|
||||
|
||||
std::unordered_map<uint64_t, TokenInterface> mMap; // map getTokenId(i.token) -> i
|
||||
uint64_t mTokenIndex = TOKEN_ID_NONE; // last token index
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace token
|
||||
} // namespace hidl
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HIDL_TOKEN_V1_0_TOKENMANAGER_H
|
61
android/system/hwservicemanager/Vintf.cpp
Normal file
61
android/system/hwservicemanager/Vintf.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
#define LOG_TAG "hwservicemanager"
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
#include "Vintf.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <hidl-util/FQName.h>
|
||||
#include <vintf/parse_string.h>
|
||||
#include <vintf/VintfObject.h>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
|
||||
vintf::Transport getTransportFromManifest(
|
||||
const FQName &fqName, const std::string &instanceName,
|
||||
const vintf::HalManifest *vm) {
|
||||
if (vm == nullptr) {
|
||||
return vintf::Transport::EMPTY;
|
||||
}
|
||||
return vm->getTransport(fqName.package(),
|
||||
vintf::Version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()},
|
||||
fqName.name(), instanceName);
|
||||
}
|
||||
|
||||
vintf::Transport getTransport(const std::string &interfaceName, const std::string &instanceName) {
|
||||
FQName fqName(interfaceName);
|
||||
if (!fqName.isValid()) {
|
||||
LOG(ERROR) << __FUNCTION__ << ": " << interfaceName
|
||||
<< " is not a valid fully-qualified name ";
|
||||
return vintf::Transport::EMPTY;
|
||||
}
|
||||
if (!fqName.hasVersion()) {
|
||||
LOG(ERROR) << __FUNCTION__ << ": " << fqName.string()
|
||||
<< " does not specify a version.";
|
||||
return vintf::Transport::EMPTY;
|
||||
}
|
||||
if (fqName.name().empty()) {
|
||||
LOG(ERROR) << __FUNCTION__ << ": " << fqName.string()
|
||||
<< " does not specify an interface name.";
|
||||
return vintf::Transport::EMPTY;
|
||||
}
|
||||
|
||||
vintf::Transport tr = getTransportFromManifest(fqName, instanceName,
|
||||
vintf::VintfObject::GetFrameworkHalManifest());
|
||||
if (tr != vintf::Transport::EMPTY) {
|
||||
return tr;
|
||||
}
|
||||
tr = getTransportFromManifest(fqName, instanceName,
|
||||
vintf::VintfObject::GetDeviceHalManifest());
|
||||
if (tr != vintf::Transport::EMPTY) {
|
||||
return tr;
|
||||
}
|
||||
|
||||
LOG(WARNING) << __FUNCTION__ << ": Cannot find entry "
|
||||
<< fqName.string() << "/" << instanceName
|
||||
<< " in either framework or device manifest.";
|
||||
return vintf::Transport::EMPTY;
|
||||
}
|
||||
|
||||
} // hardware
|
||||
} // android
|
17
android/system/hwservicemanager/Vintf.h
Normal file
17
android/system/hwservicemanager/Vintf.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vintf/Transport.h>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
|
||||
// Get transport method from vendor interface manifest.
|
||||
// interfaceName has the format "android.hardware.foo@1.0::IFoo"
|
||||
// instanceName is "default", "ashmem", etc.
|
||||
// If it starts with "android.hidl.", a static map is looked up instead.
|
||||
vintf::Transport getTransport(const std::string &interfaceName,
|
||||
const std::string &instanceName);
|
||||
|
||||
} // hardware
|
||||
} // android
|
11
android/system/hwservicemanager/hwservicemanager.rc
Normal file
11
android/system/hwservicemanager/hwservicemanager.rc
Normal file
|
@ -0,0 +1,11 @@
|
|||
service hwservicemanager /system/bin/hwservicemanager
|
||||
user system
|
||||
disabled
|
||||
group system readproc
|
||||
critical
|
||||
onrestart setprop hwservicemanager.ready false
|
||||
onrestart class_restart hal
|
||||
onrestart class_restart early_hal
|
||||
writepid /dev/cpuset/system-background/tasks
|
||||
class animation
|
||||
shutdown critical
|
119
android/system/hwservicemanager/service.cpp
Normal file
119
android/system/hwservicemanager/service.cpp
Normal file
|
@ -0,0 +1,119 @@
|
|||
#define LOG_TAG "hwservicemanager"
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android/hidl/manager/1.0/BnHwServiceManager.h>
|
||||
#include <android/hidl/manager/1.0/IServiceManager.h>
|
||||
#include <android/hidl/token/1.0/ITokenManager.h>
|
||||
#include <cutils/properties.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <hwbinder/IPCThreadState.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Looper.h>
|
||||
#include <utils/StrongPointer.h>
|
||||
|
||||
#include "ServiceManager.h"
|
||||
#include "TokenManager.h"
|
||||
|
||||
// libutils:
|
||||
using android::BAD_TYPE;
|
||||
using android::Looper;
|
||||
using android::LooperCallback;
|
||||
using android::OK;
|
||||
using android::sp;
|
||||
using android::status_t;
|
||||
|
||||
// libhwbinder:
|
||||
using android::hardware::IPCThreadState;
|
||||
|
||||
// libhidl
|
||||
using android::hardware::configureRpcThreadpool;
|
||||
using android::hardware::hidl_string;
|
||||
using android::hardware::hidl_vec;
|
||||
|
||||
// hidl types
|
||||
using android::hidl::manager::V1_0::BnHwServiceManager;
|
||||
using android::hidl::manager::V1_1::IServiceManager;
|
||||
using android::hidl::token::V1_0::ITokenManager;
|
||||
|
||||
// implementations
|
||||
using android::hidl::manager::implementation::ServiceManager;
|
||||
using android::hidl::token::V1_0::implementation::TokenManager;
|
||||
|
||||
static std::string serviceName = "default";
|
||||
|
||||
class BinderCallback : public LooperCallback {
|
||||
public:
|
||||
BinderCallback() {}
|
||||
~BinderCallback() override {}
|
||||
|
||||
int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
|
||||
IPCThreadState::self()->handlePolledCommands();
|
||||
return 1; // Continue receiving callbacks.
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
configureRpcThreadpool(1, true /* callerWillJoin */);
|
||||
|
||||
ServiceManager *manager = new ServiceManager();
|
||||
|
||||
if (!manager->add(serviceName, manager)) {
|
||||
ALOGE("Failed to register hwservicemanager with itself.");
|
||||
}
|
||||
|
||||
TokenManager *tokenManager = new TokenManager();
|
||||
|
||||
if (!manager->add(serviceName, tokenManager)) {
|
||||
ALOGE("Failed to register ITokenManager with hwservicemanager.");
|
||||
}
|
||||
|
||||
sp<Looper> looper(Looper::prepare(0 /* opts */));
|
||||
|
||||
int binder_fd = -1;
|
||||
|
||||
IPCThreadState::self()->setupPolling(&binder_fd);
|
||||
if (binder_fd < 0) {
|
||||
ALOGE("Failed to aquire binder FD. Aborting...");
|
||||
return -1;
|
||||
}
|
||||
// Flush after setupPolling(), to make sure the binder driver
|
||||
// knows about this thread handling commands.
|
||||
IPCThreadState::self()->flushCommands();
|
||||
|
||||
sp<BinderCallback> cb(new BinderCallback);
|
||||
if (looper->addFd(binder_fd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb,
|
||||
nullptr) != 1) {
|
||||
ALOGE("Failed to add hwbinder FD to Looper. Aborting...");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Tell IPCThreadState we're the service manager
|
||||
sp<BnHwServiceManager> service = new BnHwServiceManager(manager);
|
||||
IPCThreadState::self()->setTheContextObject(service);
|
||||
// Then tell binder kernel
|
||||
ioctl(binder_fd, BINDER_SET_CONTEXT_MGR, 0);
|
||||
// Only enable FIFO inheritance for hwbinder
|
||||
// FIXME: remove define when in the kernel
|
||||
#define BINDER_SET_INHERIT_FIFO_PRIO _IO('b', 10)
|
||||
|
||||
int rc = ioctl(binder_fd, BINDER_SET_INHERIT_FIFO_PRIO);
|
||||
if (rc) {
|
||||
ALOGE("BINDER_SET_INHERIT_FIFO_PRIO failed with error %d\n", rc);
|
||||
}
|
||||
|
||||
rc = property_set("hwservicemanager.ready", "true");
|
||||
if (rc) {
|
||||
ALOGE("Failed to set \"hwservicemanager.ready\" (error %d). "\
|
||||
"HAL services will not start!\n", rc);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
looper->pollAll(-1 /* timeoutMillis */);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue