| /* |
| * 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. |
| */ |
| |
| #define LOG_TAG "hwservicemanager" |
| |
| #include <utils/Log.h> |
| |
| #include <inttypes.h> |
| #include <unistd.h> |
| #include <sys/timerfd.h> |
| |
| #include <android/hidl/token/1.0/ITokenManager.h> |
| #include <cutils/properties.h> |
| #include <hidl/HidlBinderSupport.h> |
| #include <hidl/HidlTransportSupport.h> |
| #include <hidl/Status.h> |
| #include <hwbinder/IPCThreadState.h> |
| #include <hwbinder/ProcessState.h> |
| #include <utils/Errors.h> |
| #include <utils/Looper.h> |
| #include <utils/StrongPointer.h> |
| |
| #include "ServiceManager.h" |
| #include "TokenManager.h" |
| |
| // libutils: |
| using android::sp; |
| using android::Looper; |
| using android::LooperCallback; |
| |
| // libhwbinder: |
| using android::hardware::BHwBinder; |
| using android::hardware::IBinder; |
| using android::hardware::IPCThreadState; |
| using android::hardware::ProcessState; |
| |
| // libhidl |
| using android::hardware::handleTransportPoll; |
| using android::hardware::setRequestingSid; |
| using android::hardware::HidlReturnRestriction; |
| using android::hardware::setProcessHidlReturnRestriction; |
| using android::hardware::setupTransportPolling; |
| using android::hardware::toBinder; |
| |
| // implementations |
| using android::hidl::manager::implementation::ServiceManager; |
| using android::hidl::manager::V1_0::IServiceManager; |
| using android::hidl::token::V1_0::implementation::TokenManager; |
| |
| static std::string serviceName = "default"; |
| |
| class HwBinderCallback : public LooperCallback { |
| public: |
| static sp<HwBinderCallback> setupTo(const sp<Looper>& looper) { |
| sp<HwBinderCallback> cb = new HwBinderCallback; |
| |
| int fdHwBinder = setupTransportPolling(); |
| LOG_ALWAYS_FATAL_IF(fdHwBinder < 0, "Failed to setupTransportPolling: %d", fdHwBinder); |
| |
| // Flush after setupPolling(), to make sure the binder driver |
| // knows about this thread handling commands. |
| IPCThreadState::self()->flushCommands(); |
| |
| int ret = looper->addFd(fdHwBinder, |
| Looper::POLL_CALLBACK, |
| Looper::EVENT_INPUT, |
| cb, |
| nullptr /*data*/); |
| LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper"); |
| |
| return cb; |
| } |
| |
| int handleEvent(int fd, int /*events*/, void* /*data*/) override { |
| handleTransportPoll(fd); |
| return 1; // Continue receiving callbacks. |
| } |
| }; |
| |
| // LooperCallback for IClientCallback |
| class ClientCallbackCallback : public LooperCallback { |
| public: |
| static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) { |
| sp<ClientCallbackCallback> cb = new ClientCallbackCallback(manager); |
| |
| int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/); |
| LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno); |
| |
| itimerspec timespec { |
| .it_interval = { |
| .tv_sec = 5, |
| .tv_nsec = 0, |
| }, |
| .it_value = { |
| .tv_sec = 5, |
| .tv_nsec = 0, |
| }, |
| }; |
| |
| int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, ×pec, nullptr); |
| LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno); |
| |
| int addRes = looper->addFd(fdTimer, |
| Looper::POLL_CALLBACK, |
| Looper::EVENT_INPUT, |
| cb, |
| nullptr); |
| LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper"); |
| |
| return cb; |
| } |
| |
| int handleEvent(int fd, int /*events*/, void* /*data*/) override { |
| uint64_t expirations; |
| int ret = read(fd, &expirations, sizeof(expirations)); |
| if (ret != sizeof(expirations)) { |
| ALOGE("Read failed to callback FD: ret: %d err: %d", ret, errno); |
| } |
| |
| mManager->handleClientCallbacks(); |
| return 1; // Continue receiving callbacks. |
| } |
| private: |
| ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {} |
| sp<ServiceManager> mManager; |
| }; |
| |
| int main() { |
| // If hwservicemanager crashes, the system may be unstable and hard to debug. This is both why |
| // we log this and why we care about this at all. |
| setProcessHidlReturnRestriction(HidlReturnRestriction::ERROR_IF_UNCHECKED); |
| |
| // TODO(b/36424585): make fatal |
| ProcessState::self()->setCallRestriction(ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY); |
| |
| sp<ServiceManager> manager = new ServiceManager(); |
| setRequestingSid(manager, true); |
| |
| if (!manager->add(serviceName, manager).withDefault(false)) { |
| ALOGE("Failed to register hwservicemanager with itself."); |
| } |
| |
| sp<TokenManager> tokenManager = new TokenManager(); |
| if (!manager->add(serviceName, tokenManager).withDefault(false)) { |
| ALOGE("Failed to register ITokenManager with hwservicemanager."); |
| } |
| |
| // Tell IPCThreadState we're the service manager |
| sp<IBinder> binder = toBinder<IServiceManager>(manager); |
| sp<BHwBinder> service = static_cast<BHwBinder*>(binder.get()); // local binder object |
| IPCThreadState::self()->setTheContextObject(service); |
| // Then tell the kernel |
| ProcessState::self()->becomeContextManager(); |
| |
| int rc = property_set("hwservicemanager.ready", "true"); |
| if (rc) { |
| ALOGE("Failed to set \"hwservicemanager.ready\" (error %d). "\ |
| "HAL services will not start!\n", rc); |
| } |
| |
| sp<Looper> looper = Looper::prepare(0 /* opts */); |
| |
| (void)HwBinderCallback::setupTo(looper); |
| (void)ClientCallbackCallback::setupTo(looper, manager); |
| |
| ALOGI("hwservicemanager is ready now."); |
| |
| while (true) { |
| looper->pollAll(-1 /* timeoutMillis */); |
| } |
| |
| return 0; |
| } |