| /* |
| * 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 <android-base/properties.h> |
| #include <binder/IPCThreadState.h> |
| #include <binder/ProcessState.h> |
| #include <binder/Status.h> |
| #include <sys/timerfd.h> |
| #include <utils/Looper.h> |
| #include <utils/StrongPointer.h> |
| |
| #include "Access.h" |
| #include "ServiceManager.h" |
| |
| using ::android::Access; |
| using ::android::IPCThreadState; |
| using ::android::Looper; |
| using ::android::LooperCallback; |
| using ::android::ProcessState; |
| using ::android::ServiceManager; |
| using ::android::sp; |
| using ::android::base::SetProperty; |
| using ::android::os::IServiceManager; |
| |
| class BinderCallback : public LooperCallback { |
| public: |
| static sp<BinderCallback> setupTo(const sp<Looper>& looper) { |
| sp<BinderCallback> cb = sp<BinderCallback>::make(); |
| cb->mLooper = looper; |
| |
| IPCThreadState::self()->setupPolling(&cb->mBinderFd); |
| LOG_ALWAYS_FATAL_IF(cb->mBinderFd < 0, "Failed to setupPolling: %d", cb->mBinderFd); |
| |
| int ret = looper->addFd(cb->mBinderFd, 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 { |
| IPCThreadState::self()->handlePolledCommands(); |
| return 1; // Continue receiving callbacks. |
| } |
| |
| void repoll() { |
| if (!mLooper->repoll(mBinderFd)) { |
| ALOGE("Failed to repoll binder FD."); |
| } |
| } |
| |
| private: |
| sp<Looper> mLooper; |
| int mBinderFd = -1; |
| }; |
| |
| // LooperCallback for IClientCallback |
| class ClientCallbackCallback : public LooperCallback { |
| public: |
| static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, |
| const sp<ServiceManager>& manager, |
| sp<BinderCallback> binderCallback) { |
| sp<ClientCallbackCallback> cb = sp<ClientCallbackCallback>::make(manager); |
| cb->mBinderCallback = binderCallback; |
| |
| 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(); |
| mBinderCallback->repoll(); // b/316829336 |
| |
| return 1; // Continue receiving callbacks. |
| } |
| private: |
| friend sp<ClientCallbackCallback>; |
| ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {} |
| sp<ServiceManager> mManager; |
| sp<BinderCallback> mBinderCallback; |
| }; |
| |
| int main(int argc, char** argv) { |
| android::base::InitLogging(argv, android::base::KernelLogger); |
| |
| if (argc > 2) { |
| LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; |
| } |
| |
| const char* driver = argc == 2 ? argv[1] : "/dev/binder"; |
| |
| LOG(INFO) << "Starting sm instance on " << driver; |
| |
| sp<ProcessState> ps = ProcessState::initWithDriver(driver); |
| ps->setThreadPoolMaxThreadCount(0); |
| ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); |
| |
| IPCThreadState::self()->disableBackgroundScheduling(true); |
| |
| sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>()); |
| if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) { |
| LOG(ERROR) << "Could not self register servicemanager"; |
| } |
| |
| IPCThreadState::self()->setTheContextObject(manager); |
| if (!ps->becomeContextManager()) { |
| LOG(FATAL) << "Could not become context manager"; |
| } |
| |
| sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/); |
| |
| sp<BinderCallback> binderCallback = BinderCallback::setupTo(looper); |
| ClientCallbackCallback::setupTo(looper, manager, binderCallback); |
| |
| #ifndef VENDORSERVICEMANAGER |
| if (!SetProperty("servicemanager.ready", "true")) { |
| LOG(ERROR) << "Failed to set servicemanager ready property"; |
| } |
| #endif |
| |
| while(true) { |
| looper->pollAll(-1); |
| } |
| |
| // should not be reached |
| return EXIT_FAILURE; |
| } |