| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/fuchsia/service_directory.h" |
| |
| #include <lib/async/default.h> |
| #include <lib/svc/dir.h> |
| #include <lib/zx/channel.h> |
| #include <zircon/process.h> |
| #include <zircon/processargs.h> |
| |
| #include "base/fuchsia/fuchsia_logging.h" |
| #include "base/message_loop/message_loop_current.h" |
| #include "base/no_destructor.h" |
| #include "starboard/types.h" |
| |
| namespace base { |
| namespace fuchsia { |
| |
| ServiceDirectory::ServiceDirectory(zx::channel directory_request) { |
| zx_status_t status = svc_dir_create(async_get_default_dispatcher(), |
| directory_request.release(), &svc_dir_); |
| ZX_CHECK(status == ZX_OK, status); |
| } |
| |
| ServiceDirectory::~ServiceDirectory() { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| DCHECK(services_.empty()); |
| |
| zx_status_t status = svc_dir_destroy(svc_dir_); |
| ZX_DCHECK(status == ZX_OK, status); |
| } |
| |
| // static |
| ServiceDirectory* ServiceDirectory::GetDefault() { |
| static base::NoDestructor<ServiceDirectory> directory( |
| zx::channel(zx_take_startup_handle(PA_DIRECTORY_REQUEST))); |
| return directory.get(); |
| } |
| |
| void ServiceDirectory::AddService(StringPiece name, |
| ConnectServiceCallback connect_callback) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| DCHECK(services_.find(name) == services_.end()); |
| |
| std::string name_str = name.as_string(); |
| services_[name_str] = connect_callback; |
| |
| zx_status_t status = |
| svc_dir_add_service(svc_dir_, "public", name_str.c_str(), this, |
| &ServiceDirectory::HandleConnectRequest); |
| ZX_DCHECK(status == ZX_OK, status); |
| |
| // Publish to the legacy "flat" namespace, which is required by some clients. |
| status = svc_dir_add_service(svc_dir_, nullptr, name_str.c_str(), this, |
| &ServiceDirectory::HandleConnectRequest); |
| ZX_DCHECK(status == ZX_OK, status); |
| } |
| |
| void ServiceDirectory::RemoveService(StringPiece name) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| |
| std::string name_str = name.as_string(); |
| |
| auto it = services_.find(name_str); |
| DCHECK(it != services_.end()); |
| services_.erase(it); |
| |
| zx_status_t status = |
| svc_dir_remove_service(svc_dir_, "public", name_str.c_str()); |
| ZX_DCHECK(status == ZX_OK, status); |
| |
| // Unregister from the legacy "flat" namespace. |
| status = svc_dir_remove_service(svc_dir_, nullptr, name_str.c_str()); |
| ZX_DCHECK(status == ZX_OK, status); |
| } |
| |
| void ServiceDirectory::RemoveAllServices() { |
| while (!services_.empty()) { |
| RemoveService(services_.begin()->first); |
| } |
| } |
| |
| // static |
| void ServiceDirectory::HandleConnectRequest(void* context, |
| const char* service_name, |
| zx_handle_t service_request) { |
| auto* directory = reinterpret_cast<ServiceDirectory*>(context); |
| DCHECK_CALLED_ON_VALID_THREAD(directory->thread_checker_); |
| |
| auto it = directory->services_.find(service_name); |
| |
| // HandleConnectRequest() is expected to be called only for registered |
| // services. |
| DCHECK(it != directory->services_.end()); |
| |
| it->second.Run(zx::channel(service_request)); |
| } |
| |
| } // namespace fuchsia |
| } // namespace base |