From 483c66de10dffca7ce42dbdf5d3e1e503bd9a5fa Mon Sep 17 00:00:00 2001 From: mamingshuai Date: Wed, 2 Jun 2021 00:05:38 +0800 Subject: [PATCH] update OpenHarmony 2.0 Canary --- .gitattributes | 15 + BUILD.gn | 43 + LICENSE | 178 ++ README.en.md | 36 - README.md | 275 +++- README_zh.md | 264 +++ figures/ipc-architecture.png | Bin 0 -> 7890 bytes interfaces/innerkits/ipc_core/BUILD.gn | 67 + .../ipc_core/include/ipc_file_descriptor.h | 38 + .../ipc_core/include/ipc_object_proxy.h | 117 ++ .../ipc_core/include/ipc_object_stub.h | 84 + .../innerkits/ipc_core/include/ipc_skeleton.h | 59 + .../innerkits/ipc_core/include/ipc_types.h | 122 ++ .../ipc_core/include/iremote_broker.h | 109 ++ .../ipc_core/include/iremote_object.h | 86 + .../ipc_core/include/iremote_proxy.h | 43 + .../innerkits/ipc_core/include/iremote_stub.h | 44 + .../innerkits/ipc_core/include/jni_help.h | 26 + .../ipc_core/include/message_option.h | 43 + .../ipc_core/include/message_parcel.h | 67 + .../innerkits/ipc_core/include/peer_holder.h | 34 + interfaces/innerkits/ipc_single/BUILD.gn | 58 + interfaces/innerkits/libdbinder/BUILD.gn | 66 + .../libdbinder/include/dbinder_service.h | 194 +++ .../libdbinder/include/dbinder_service_stub.h | 51 + ipc/native/src/core/include/buffer_object.h | 76 + ipc/native/src/core/include/comm_auth_info.h | 39 + .../core/include/databus_session_callback.h | 42 + .../src/core/include/dbinder_error_code.h | 144 ++ .../src/core/include/dbinder_session_object.h | 70 + ipc/native/src/core/include/ipc_debug.h | 62 + .../src/core/include/ipc_process_skeleton.h | 258 +++ ipc/native/src/core/include/ipc_thread_pool.h | 74 + .../src/core/include/ipc_thread_skeleton.h | 63 + ipc/native/src/core/include/ipc_workthread.h | 60 + .../src/core/include/stub_refcount_object.h | 36 + ipc/native/src/core/source/buffer_object.cpp | 223 +++ ipc/native/src/core/source/comm_auth_info.cpp | 43 + .../core/source/databus_session_callback.cpp | 81 + .../core/source/dbinder_session_object.cpp | 95 ++ .../src/core/source/ipc_file_descriptor.cpp | 91 + .../src/core/source/ipc_object_proxy.cpp | 660 ++++++++ .../src/core/source/ipc_object_stub.cpp | 495 ++++++ .../src/core/source/ipc_process_skeleton.cpp | 1229 ++++++++++++++ ipc/native/src/core/source/ipc_skeleton.cpp | 148 ++ .../src/core/source/ipc_thread_pool.cpp | 147 ++ .../src/core/source/ipc_thread_skeleton.cpp | 158 ++ ipc/native/src/core/source/ipc_workthread.cpp | 94 ++ ipc/native/src/core/source/iremote_broker.cpp | 79 + ipc/native/src/core/source/iremote_object.cpp | 84 + ipc/native/src/core/source/message_option.cpp | 46 + ipc/native/src/core/source/message_parcel.cpp | 327 ++++ ipc/native/src/core/source/peer_holder.cpp | 25 + .../src/core/source/stub_refcount_object.cpp | 43 + ipc/native/src/jni/include/jni_helper.h | 68 + .../src/jni/include/jni_remote_object.h | 27 + .../src/jni/include/ohos_rpc_message_option.h | 59 + .../src/jni/include/ohos_rpc_message_parcel.h | 158 ++ .../src/jni/include/ohos_rpc_remote_object.h | 181 ++ ipc/native/src/jni/source/jni_helper.cpp | 176 ++ .../jni/source/ohos_rpc_message_option.cpp | 138 ++ .../jni/source/ohos_rpc_message_parcel.cpp | 519 ++++++ .../src/jni/source/ohos_rpc_remote_object.cpp | 982 +++++++++++ .../src/mock/include/binder_connector.h | 48 + ipc/native/src/mock/include/binder_debug.h | 30 + ipc/native/src/mock/include/binder_invoker.h | 154 ++ .../src/mock/include/dbinder_base_invoker.h | 1022 ++++++++++++ .../mock/include/dbinder_databus_invoker.h | 111 ++ ipc/native/src/mock/include/hitrace_invoker.h | 42 + ipc/native/src/mock/include/invoker_factory.h | 70 + ipc/native/src/mock/include/invoker_rawdata.h | 40 + ipc/native/src/mock/include/iremote_invoker.h | 105 ++ ipc/native/src/mock/include/sys_binder.h | 270 +++ .../src/mock/source/binder_connector.cpp | 147 ++ ipc/native/src/mock/source/binder_debug.cpp | 65 + ipc/native/src/mock/source/binder_invoker.cpp | 951 +++++++++++ .../mock/source/dbinder_databus_invoker.cpp | 892 ++++++++++ .../src/mock/source/hitrace_invoker.cpp | 140 ++ .../src/mock/source/invoker_factory.cpp | 87 + .../src/mock/source/invoker_rawdata.cpp | 40 + ipc/native/test/BUILD.gn | 22 + ipc/native/test/unittest/common/BUILD.gn | 82 + .../unittest/common/ipc_core_unittest.cpp | 489 ++++++ .../common/ipc_file_desc_unittest.cpp | 93 ++ .../unittest/common/ipc_hitrace_unittest.cpp | 414 +++++ ipc/test/BUILD.gn | 33 + ipc/test/auxiliary/native/BUILD.gn | 157 ++ .../native/include/assist_test_service.h | 137 ++ .../auxiliary/native/include/foo_service.h | 77 + .../native/include/ipc_test_helper.h | 76 + .../native/include/ohos_rpc_test_testhelper.h | 122 ++ .../auxiliary/native/include/test_service.h | 54 + .../native/include/test_service_client.h | 48 + .../native/include/test_service_command.h | 31 + .../native/include/test_service_skeleton.h | 122 ++ .../native/src/assist_test_service.cpp | 391 +++++ ipc/test/auxiliary/native/src/foo_service.cpp | 129 ++ .../auxiliary/native/src/ipc_test_helper.cpp | 337 ++++ ipc/test/auxiliary/native/src/main_client.cpp | 101 ++ ipc/test/auxiliary/native/src/main_server.cpp | 31 + .../native/src/ohos_rpc_test_testhelper.cpp | 301 ++++ .../auxiliary/native/src/test_service.cpp | 219 +++ .../native/src/test_service_client.cpp | 143 ++ .../native/src/test_service_skeleton.cpp | 686 ++++++++ ipc/test/moduletest/native/BUILD.gn | 51 + .../native/common/ipc_core_module_test.cpp | 740 +++++++++ ohos.build | 73 + .../include/dbinder_death_recipient.h | 29 + .../dbinder_service/include/dbinder_log.h | 39 + .../include/dbinder_remote_listener.h | 65 + .../include/dbinder_sa_death_recipient.h | 31 + .../src/dbinder_death_recipient.cpp | 64 + .../src/dbinder_sa_death_recipient.cpp | 55 + .../dbinder_service/src/dbinder_service.cpp | 941 +++++++++++ .../src/dbinder_service_stub.cpp | 210 +++ .../src/socket/dbinder_remote_listener.cpp | 159 ++ services/dbinder/test/BUILD.gn | 164 ++ .../include/dbinder_service_test_helper.h | 99 ++ .../include/dbinder_test_service.h | 53 + .../include/dbinder_test_service_skeleton.h | 160 ++ .../src/dbinder_distributed_test.cpp | 1460 +++++++++++++++++ .../src/dbinder_service_test_helper.cpp | 246 +++ .../src/dbinder_test_agent.cpp | 144 ++ .../src/dbinder_test_server_main.cpp | 33 + .../src/dbinder_test_service.cpp | 198 +++ .../src/dbinder_test_service_skeleton.cpp | 752 +++++++++ services/dbinder/test/test_dbinder.py | 55 + test/resource/ipc/ohos_test.xml | 48 + test/resource/services/ohos_test.xml | 28 + utils/include/log_tags.h | 48 + 130 files changed, 23812 insertions(+), 61 deletions(-) create mode 100644 .gitattributes create mode 100755 BUILD.gn create mode 100755 LICENSE delete mode 100644 README.en.md mode change 100644 => 100755 README.md create mode 100755 README_zh.md create mode 100755 figures/ipc-architecture.png create mode 100755 interfaces/innerkits/ipc_core/BUILD.gn create mode 100755 interfaces/innerkits/ipc_core/include/ipc_file_descriptor.h create mode 100755 interfaces/innerkits/ipc_core/include/ipc_object_proxy.h create mode 100755 interfaces/innerkits/ipc_core/include/ipc_object_stub.h create mode 100755 interfaces/innerkits/ipc_core/include/ipc_skeleton.h create mode 100755 interfaces/innerkits/ipc_core/include/ipc_types.h create mode 100755 interfaces/innerkits/ipc_core/include/iremote_broker.h create mode 100755 interfaces/innerkits/ipc_core/include/iremote_object.h create mode 100755 interfaces/innerkits/ipc_core/include/iremote_proxy.h create mode 100755 interfaces/innerkits/ipc_core/include/iremote_stub.h create mode 100755 interfaces/innerkits/ipc_core/include/jni_help.h create mode 100755 interfaces/innerkits/ipc_core/include/message_option.h create mode 100755 interfaces/innerkits/ipc_core/include/message_parcel.h create mode 100755 interfaces/innerkits/ipc_core/include/peer_holder.h create mode 100755 interfaces/innerkits/ipc_single/BUILD.gn create mode 100755 interfaces/innerkits/libdbinder/BUILD.gn create mode 100755 interfaces/innerkits/libdbinder/include/dbinder_service.h create mode 100755 interfaces/innerkits/libdbinder/include/dbinder_service_stub.h create mode 100755 ipc/native/src/core/include/buffer_object.h create mode 100755 ipc/native/src/core/include/comm_auth_info.h create mode 100755 ipc/native/src/core/include/databus_session_callback.h create mode 100755 ipc/native/src/core/include/dbinder_error_code.h create mode 100755 ipc/native/src/core/include/dbinder_session_object.h create mode 100755 ipc/native/src/core/include/ipc_debug.h create mode 100755 ipc/native/src/core/include/ipc_process_skeleton.h create mode 100755 ipc/native/src/core/include/ipc_thread_pool.h create mode 100755 ipc/native/src/core/include/ipc_thread_skeleton.h create mode 100755 ipc/native/src/core/include/ipc_workthread.h create mode 100755 ipc/native/src/core/include/stub_refcount_object.h create mode 100755 ipc/native/src/core/source/buffer_object.cpp create mode 100755 ipc/native/src/core/source/comm_auth_info.cpp create mode 100755 ipc/native/src/core/source/databus_session_callback.cpp create mode 100755 ipc/native/src/core/source/dbinder_session_object.cpp create mode 100755 ipc/native/src/core/source/ipc_file_descriptor.cpp create mode 100755 ipc/native/src/core/source/ipc_object_proxy.cpp create mode 100755 ipc/native/src/core/source/ipc_object_stub.cpp create mode 100755 ipc/native/src/core/source/ipc_process_skeleton.cpp create mode 100755 ipc/native/src/core/source/ipc_skeleton.cpp create mode 100755 ipc/native/src/core/source/ipc_thread_pool.cpp create mode 100755 ipc/native/src/core/source/ipc_thread_skeleton.cpp create mode 100755 ipc/native/src/core/source/ipc_workthread.cpp create mode 100755 ipc/native/src/core/source/iremote_broker.cpp create mode 100755 ipc/native/src/core/source/iremote_object.cpp create mode 100755 ipc/native/src/core/source/message_option.cpp create mode 100755 ipc/native/src/core/source/message_parcel.cpp create mode 100755 ipc/native/src/core/source/peer_holder.cpp create mode 100755 ipc/native/src/core/source/stub_refcount_object.cpp create mode 100755 ipc/native/src/jni/include/jni_helper.h create mode 100755 ipc/native/src/jni/include/jni_remote_object.h create mode 100755 ipc/native/src/jni/include/ohos_rpc_message_option.h create mode 100755 ipc/native/src/jni/include/ohos_rpc_message_parcel.h create mode 100755 ipc/native/src/jni/include/ohos_rpc_remote_object.h create mode 100755 ipc/native/src/jni/source/jni_helper.cpp create mode 100755 ipc/native/src/jni/source/ohos_rpc_message_option.cpp create mode 100755 ipc/native/src/jni/source/ohos_rpc_message_parcel.cpp create mode 100755 ipc/native/src/jni/source/ohos_rpc_remote_object.cpp create mode 100755 ipc/native/src/mock/include/binder_connector.h create mode 100755 ipc/native/src/mock/include/binder_debug.h create mode 100755 ipc/native/src/mock/include/binder_invoker.h create mode 100755 ipc/native/src/mock/include/dbinder_base_invoker.h create mode 100755 ipc/native/src/mock/include/dbinder_databus_invoker.h create mode 100755 ipc/native/src/mock/include/hitrace_invoker.h create mode 100755 ipc/native/src/mock/include/invoker_factory.h create mode 100755 ipc/native/src/mock/include/invoker_rawdata.h create mode 100755 ipc/native/src/mock/include/iremote_invoker.h create mode 100755 ipc/native/src/mock/include/sys_binder.h create mode 100755 ipc/native/src/mock/source/binder_connector.cpp create mode 100755 ipc/native/src/mock/source/binder_debug.cpp create mode 100755 ipc/native/src/mock/source/binder_invoker.cpp create mode 100755 ipc/native/src/mock/source/dbinder_databus_invoker.cpp create mode 100755 ipc/native/src/mock/source/hitrace_invoker.cpp create mode 100755 ipc/native/src/mock/source/invoker_factory.cpp create mode 100755 ipc/native/src/mock/source/invoker_rawdata.cpp create mode 100755 ipc/native/test/BUILD.gn create mode 100755 ipc/native/test/unittest/common/BUILD.gn create mode 100755 ipc/native/test/unittest/common/ipc_core_unittest.cpp create mode 100755 ipc/native/test/unittest/common/ipc_file_desc_unittest.cpp create mode 100755 ipc/native/test/unittest/common/ipc_hitrace_unittest.cpp create mode 100755 ipc/test/BUILD.gn create mode 100755 ipc/test/auxiliary/native/BUILD.gn create mode 100755 ipc/test/auxiliary/native/include/assist_test_service.h create mode 100755 ipc/test/auxiliary/native/include/foo_service.h create mode 100755 ipc/test/auxiliary/native/include/ipc_test_helper.h create mode 100755 ipc/test/auxiliary/native/include/ohos_rpc_test_testhelper.h create mode 100755 ipc/test/auxiliary/native/include/test_service.h create mode 100755 ipc/test/auxiliary/native/include/test_service_client.h create mode 100755 ipc/test/auxiliary/native/include/test_service_command.h create mode 100755 ipc/test/auxiliary/native/include/test_service_skeleton.h create mode 100755 ipc/test/auxiliary/native/src/assist_test_service.cpp create mode 100755 ipc/test/auxiliary/native/src/foo_service.cpp create mode 100755 ipc/test/auxiliary/native/src/ipc_test_helper.cpp create mode 100755 ipc/test/auxiliary/native/src/main_client.cpp create mode 100755 ipc/test/auxiliary/native/src/main_server.cpp create mode 100755 ipc/test/auxiliary/native/src/ohos_rpc_test_testhelper.cpp create mode 100755 ipc/test/auxiliary/native/src/test_service.cpp create mode 100755 ipc/test/auxiliary/native/src/test_service_client.cpp create mode 100755 ipc/test/auxiliary/native/src/test_service_skeleton.cpp create mode 100755 ipc/test/moduletest/native/BUILD.gn create mode 100755 ipc/test/moduletest/native/common/ipc_core_module_test.cpp create mode 100755 ohos.build create mode 100755 services/dbinder/dbinder_service/include/dbinder_death_recipient.h create mode 100755 services/dbinder/dbinder_service/include/dbinder_log.h create mode 100755 services/dbinder/dbinder_service/include/dbinder_remote_listener.h create mode 100755 services/dbinder/dbinder_service/include/dbinder_sa_death_recipient.h create mode 100755 services/dbinder/dbinder_service/src/dbinder_death_recipient.cpp create mode 100755 services/dbinder/dbinder_service/src/dbinder_sa_death_recipient.cpp create mode 100755 services/dbinder/dbinder_service/src/dbinder_service.cpp create mode 100755 services/dbinder/dbinder_service/src/dbinder_service_stub.cpp create mode 100755 services/dbinder/dbinder_service/src/socket/dbinder_remote_listener.cpp create mode 100755 services/dbinder/test/BUILD.gn create mode 100755 services/dbinder/test/distributedtest/include/dbinder_service_test_helper.h create mode 100755 services/dbinder/test/distributedtest/include/dbinder_test_service.h create mode 100755 services/dbinder/test/distributedtest/include/dbinder_test_service_skeleton.h create mode 100755 services/dbinder/test/distributedtest/src/dbinder_distributed_test.cpp create mode 100755 services/dbinder/test/distributedtest/src/dbinder_service_test_helper.cpp create mode 100755 services/dbinder/test/distributedtest/src/dbinder_test_agent.cpp create mode 100755 services/dbinder/test/distributedtest/src/dbinder_test_server_main.cpp create mode 100755 services/dbinder/test/distributedtest/src/dbinder_test_service.cpp create mode 100755 services/dbinder/test/distributedtest/src/dbinder_test_service_skeleton.cpp create mode 100755 services/dbinder/test/test_dbinder.py create mode 100755 test/resource/ipc/ohos_test.xml create mode 100755 test/resource/services/ohos_test.xml create mode 100755 utils/include/log_tags.h diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..51c63e29 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +*.tgz filter=lfs diff=lfs merge=lfs -text +*.trp filter=lfs diff=lfs merge=lfs -text +*.apk filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.asm filter=lfs diff=lfs merge=lfs -text +*.8svn filter=lfs diff=lfs merge=lfs -text +*.9svn filter=lfs diff=lfs merge=lfs -text +*.dylib filter=lfs diff=lfs merge=lfs -text +*.exe filter=lfs diff=lfs merge=lfs -text +*.a filter=lfs diff=lfs merge=lfs -text +*.so filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.dll filter=lfs diff=lfs merge=lfs -text diff --git a/BUILD.gn b/BUILD.gn new file mode 100755 index 00000000..3fa1dbc2 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,43 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") +import("//build/ohos_var.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +IPC_CORE_ROOT = "$SUBSYSTEM_DIR/ipc/native" + +config("ipc_util_config") { + # header file path + + include_dirs = [ + "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_core/include", + "$IPC_CORE_ROOT/src/core/include", + "$IPC_CORE_ROOT/src/mock/include", + "//utils/native/base/include", + ] + + cflags = [] + if (is_double_framework) { + cflags = [ "-DCONFIG_DUAL_FRAMEWORK" ] + } + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + if (is_standard_system) { + cflags += [ "-DCONFIG_STANDARD_SYSTEM" ] + } + if (defined(build_public_version) && build_public_version) { + cflags += [ "-DBUILD_PUBLIC_VERSION" ] + } +} diff --git a/LICENSE b/LICENSE new file mode 100755 index 00000000..e454a525 --- /dev/null +++ b/LICENSE @@ -0,0 +1,178 @@ + + 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 + diff --git a/README.en.md b/README.en.md deleted file mode 100644 index ed5f1d72..00000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# communication_ipc - -#### Description -Inter-process communication (IPC) and Remote Procedure Call (RPC) | 跨进程通信与跨设备的远程过程调用 - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md old mode 100644 new mode 100755 index b235630e..3c0a2c04 --- a/README.md +++ b/README.md @@ -1,37 +1,262 @@ -# communication_ipc +# communication\_ipc -#### 介绍 -Inter-process communication (IPC) and Remote Procedure Call (RPC) | 跨进程通信与跨设备的远程过程调用 +- [Introduction](#section11660541593) +- [Architecture](#section1950291414611) +- [Directory Structure](#section161941989596) +- [Constraints](#section119744591305) +- [Compilation and Building](#section137768191623) +- [Usage](#section1312121216216) + - [Available APIs](#section1551164914237) + - [Usage Guidelines](#section129654513264) -#### 软件架构 -软件架构说明 +- [Repositories Involved](#section1371113476307) +## Introduction -#### 安装教程 +The inter-process communication \(IPC\) and remote procedure call \(RPC\) mechanisms are used to implement cross-process communication. The difference between them lies in that IPC uses the Binder driver to implement cross-process communication within a device, whereas RPC uses the DSoftBus driver to implement cross-process communication across devices. IPC and RPC generally use a client-server model. The service requester \(client\) can obtain the proxy of the service provider \(server\) and use the proxy to read and write data, thus implementing data communication between processes. Generally, the server registers system abilities \(SAs\) with the system ability manager \(SAMgr\), which manages the SAs and provides APIs for the client. To communicate with a specific SA, the client must obtain the proxy of the SA from SAMgr. In this document, Proxy represents the service requester, and Stub represents the service provider. -1. xxxx -2. xxxx -3. xxxx +## Architecture -#### 使用说明 +**Figure 1** IPC architecture +![](figures/ipc-architecture.png "ipc-architecture") -1. xxxx -2. xxxx -3. xxxx +## Directory Structure -#### 参与贡献 +``` +/foundation/communication/ipc +├── interfaces # APIs exposed externally +│ └── innerkits # Header files for internal subsystems +│ ├── ipc_core # IPC APIs +│ └── libdbinder # dbinder APIs +├── ipc # IPC framework +│ ├── native # IPC native implementation +│ ├── src # IPC native source code +│ └── test # IPC native unit test cases +│ └── test # IPC native module test cases +├── service # dbinder implementation +│ └── dbinder # dbinder source code +``` -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +## Constraints +Currently, cross-device RPC communication is not supported. -#### 特技 +## Compilation and Building + +**Native Dependency** + +SDK dependency: + +``` +external_deps = [ + "ipc:ipc_core", +] +``` + +In addition, the refbase implementation on which IPC/RPC depends is stored in **//utils**. Add the dependency on the Utils source code. + +``` +deps = [ + "//utils/native/base:utils", +] +``` + +## Usage + +The procedure for implementing cross-process communication using native APIs is similar to that using Java APIs. + +1. Define an interface. + + The interface inherits **IRemoteBroker** and defines descriptors, functions, and message code. + +2. Implement the server provider \(stub\). + + The stub inherits **IRemoteStub\(Native\)** or **RemoteObject\(Java\)** as well as **AsObject** and **OnRemoteRequest**. + +3. Implement the service requester \(proxy\). + + The proxy inherits **IRemoteProxy\(Native\)** or **RemoteProxy\(Java\)**, encapsulates functions, and calls **SendRequest** to send requests to the stub. + +4. Register an SA. + + After the process where the service provider resides starts, apply for the unique SA ID and register the stub with SAMgr. + +5. Obtain the SA. +6. Obtain the proxy from the SAMgr based on the SA ID and device ID, and implement cross-process communication with the stub through the proxy. + +### Available APIs + +**Table 1** Native IPC APIs + + + + + + + + + + + + + + + + + + + + +

Class/Interface

+

Method

+

Description

+

IRemoteBroker

+

sptr<IRemoteObject> AsObject()

+

Obtains the holder of a remote proxy object. This method must be implemented by the derived classes of IRemoteBroker. If you call this method on the stub, the RemoteObject is returned; if you call this method on the proxy, the proxy object is returned.

+

IRemoteStub

+

virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)

+

Called to process a request from the proxy and return the result. Derived classes need to override this method.

+

IRemoteProxy

+
  

Service proxy classes are derived from the IRemoteProxy class.

+
+ +### Usage Guidelines + +**Native** + +Define the IPC interface **ITestAbility**. + +**ITestAbility** inherits the IPC base class **IRemoteBroker** and defines descriptors, functions, and message code. The functions need to be implemented on both the proxy and stub. + +``` +class ITestAbility : public IRemoteBroker { +public: +// DECLARE_INTERFACE_DESCRIPTOR is mandatory, and the input parameter is std::u16string. +DECLARE_INTERFACE_DESCRIPTOR(u"test.ITestAbility"); +int TRANS_ID_PING_ABILITY = 1; // Define the message code. +virtual int TestPingAbility(const std::u16string &dummy) = 0; // Define functions. +}; +``` + +Define and implement service provider **TestAbilityStub**. + +This class is related to the IPC framework and needs to inherit **IRemoteStub**. You need to override **OnRemoteRequest** on the stub to receive requests from the proxy. + +``` +class TestAbilityStub : public IRemoteStub { +public: + virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + int TestPingAbility(const std::u16string &dummy) override; +}; + +int TestServiceStub::OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + switch (code) { + case TRANS_ID_PING_ABILITY: { + std::u16string dummy = data.ReadString16(); + int result = TestPingAbility(dummy); + reply.WriteInt32(result); + return 0; + } + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } +} +``` + +Define the **TestAbility** class that implements functions for the stub. + +``` +class TestAbility : public TestAbilityStub { +public: + int TestPingAbility(const std::u16string &dummy); +} + +int TestAbility::TestPingAbility(const std::u16string &dummy) { + return 0; +} +``` + +Define and implement **TestAbilityProxy**. + +This class is implemented on the proxy and inherits **IRemoteProxy**. You can call **SendRequest** to send a request to the stub and expose the capabilities provided by the stub. + +``` +class TestAbilityProxy : public IRemoteProxy { +public: + explicit TestAbilityProxy(const sptr &impl); + int TestPingService(const std::u16string &dummy) override; +private: + static inline BrokerDelegator delegator_; // Use the iface_cast macro. +} + +TestAbilityProxy::TestAbilityProxy(const sptr &impl) + : IRemoteProxy(impl) +{ +} + +int TestAbilityProxy::TestPingService(const std::u16string &dummy) { + MessageOption option; + MessageParcel dataParcel, replyParcel; + dataParcel.WriteString16(dummy); + int error = Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option); + int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1; + return result; +} +``` + +Send a request synchronously or asynchronously. + +The **MessageOption** parameter for the **sendRequest\(\)** method can be set to **TF\_SYNC**, **TF\_ASYNC**, or **TF\_ACCEPT\_FDS** using the **MessageOption** constructor or **void SetFlags\(int flags\)**. The default value is **TF\_SYNC**. + +``` +int SendRequest(uint32_t code, MessageParcel &data, + MessageParcel &reply, MessageOption &option) override; +MessageOption option = { MessageOption::TF_ASYNC }; +``` + +Register and start an SA. + +Call **AddSystemAbility** to register the **TestAbilityStub** instance of the SA with **SystemAbilityManager**. The registration parameters vary depending on whether the **SystemAbilityManager** resides on the same device as the SA. + +``` +// Register the TestAbilityStub instance with the SystemAbilityManager on the same device as the SA. +auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); +samgr->AddSystemAbility(said, new TestAbility()); + +// Register the TestAbilityStub instance with the SystemAbilityManager on a different device. +auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); +ISystemAbilityManager::SAExtraProp saExtra; +saExtra.isDistributed = true; // Set a distributed SA. +int result = samgr->AddSystemAbility(said, new TestAbility(), saExtra); +``` + +Obtain the SA. + +Call the **GetSystemAbility** function of the **SystemAbilityManager** class to obtain the **IRemoteObject** for the SA, and create a **TestAbilityProxy** instance. + +``` +// Obtain the proxy of the SA registered on the local device. +sptr samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); +sptr remoteObject = samgr->GetSystemAbility(said); +sptr testAbility = iface_cast(remoteObject); // Use the iface_cast macro to convert the proxy to a specific type. + +// Obtain the proxies of the SAs registered with other devices. +sptr samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); +sptr remoteObject = samgr->GetSystemAbility(sdid, deviceId); // deviceId identifies a device. +sptr proxy(new TestAbilityProxy(remoteObject)); // Construct a proxy. +``` + +## Repositories Involved + +DSoftBus subsystem + +**communication\_ipc** + +utils + +utils\_native + +distributedschedule\_samgr -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README_zh.md b/README_zh.md new file mode 100755 index 00000000..84d11bfe --- /dev/null +++ b/README_zh.md @@ -0,0 +1,264 @@ +# IPC/RPC组件 + +- [简介](#section11660541593) +- [系统架构](#section1950291414611) +- [目录](#section161941989596) +- [约束](#section119744591305) +- [编译构建](#section137768191623) +- [说明](#section1312121216216) + - [接口说明](#section1551164914237) + - [使用说明](#section129654513264) + +- [相关仓](#section1371113476307) + +## 简介 + +IPC(Inter-Process Communication)与RPC(Remote Procedure Call)机制用于实现跨进程通信,不同的是前者使用Binder驱动,用于设备内的跨进程通信,而后者使用软总线驱动,用于跨设备跨进程通信。IPC和RPC通常采用客户端-服务器(Client-Server)模型,服务请求方(Client)可获取提供服务提供方(Server)的代理 (Proxy),并通过此代理读写数据来实现进程间的数据通信。通常,Server会先注册系统能力(System Ability)到系统能力管理者(System Ability Manager,缩写SAMgr)中,SAMgr负责管理这些SA并向Client提供相关的接口。Client要和某个具体的SA通信,必须先从SAMgr中获取该SA的代理,然后使用代理和SA通信。下文使用Proxy表示服务请求方,Stub表示服务提供方。 + +## 系统架构 + +**图 1** IPC通信机制架构图 +![](figures/ipc-architecture.png "IPC通信机制架构图") + +## 目录 + +``` +/foundation/communication/ipc +├── interfaces # 对外接口存放目录 +│ └── innerkits # 对内部子系统暴露的头文件存放目录 +│ ├── ipc_core # ipc 接口存放目录 +│ └── libdbinder # dbinder 接口存放目录 +├── ipc # ipc 框架代码 +│ ├── native # ipc native 实现存放目录 +│ ├── src # ipc native 源代码存放目录 +│ └── test # ipc native 单元测试用例存放目录 +│ └── test # ipc native 模块测试用例存放目录 +├── service # dbinder 实现存放目录 +│ └── dbinder # dbinder 源代码存放目录 +``` + +## 约束 + +目前暂不支持的场景: + +跨设备RPC调用 + +## 编译构建 + +**Native侧编译依赖** + +sdk依赖: + +``` +external_deps = [ + "ipc:ipc_core", +] +``` + +此外, IPC/RPC依赖的refbase实现在公共基础库实现//utils下,请增加对utils的源码依赖: + +``` +deps = [ + "//utils/native/base:utils", +] +``` + +## 说明 + +Native侧和Java侧实现跨进程通信的步骤基本相同。 + +1. 定义接口类 + + 接口类继承IRemoteBroker,定义描述符、业务函数和消息码。 + +2. 实现服务提供端\(Stub\) + + Stub继承IRemoteStub\(Native\)或者RemoteObject\(Java\),除了接口类中未实现方法外,还需要实现AsObject方法及OnRemoteRequest方法。 + +3. 实现服务请求端\(Proxy\) + + Proxy继承IRemoteProxy\(Native\)或者RemoteProxy\(Java\),封装业务函数,调用SendRequest将请求发送到Stub。 + +4. 注册SA + + 服务提供方所在进程启动后,申请SA的唯一标识,将Stub注册到SAMgr。 + +5. 获取SA +6. 通过SA的标识和设备标识,从SAMgr获取Proxy,通过Proxy实现与Stub的跨进程通信。 + +### 接口说明 + +**表 1** Native侧IPC接口 + + + + + + + + + + + + + + + + + + + + +

类/接口

+

方法

+

功能说明

+

IRemoteBroker

+

sptr<IRemoteObject> AsObject()

+

返回通信对象。派生类需要实现,Stub端返回RemoteObject对象本身,Proxy端返回代理对象。

+

IRemoteStub

+

virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)

+

请求处理方法,派生类需要重写,处理Proxy的请求并返回结果。

+

IRemoteProxy

+
  

业务Proxy类派生自IRemoteProxy类。

+
+ +### 使用说明 + +**Native侧使用说明** + +定义IPC接口ITestAbility + +IPC接口继承IPC基类接口IRemoteBroker,接口里定义描述符、业务函数和消息码,其中业务函数在Proxy端和Stub端都需要实现。 + +``` +class ITestAbility : public IRemoteBroker { +public: +// DECLARE_INTERFACE_DESCRIPTOR是必须的, 入参需使用std::u16string; +DECLARE_INTERFACE_DESCRIPTOR(u"test.ITestAbility"); +int TRANS_ID_PING_ABILITY = 1; // 定义消息码 +virtual int TestPingAbility(const std::u16string &dummy) = 0; // 定义业务函数 +}; +``` + +定义和实现服务端TestAbilityStub + +该类是和IPC框架相关的实现,需要继承 IRemoteStub。Stub端作为接收请求的一端,需重写OnRemoteRequest方法用于接收客户端调用。 + +``` +class TestAbilityStub : public IRemoteStub { +public: + virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + int TestPingAbility(const std::u16string &dummy) override; +}; + +int TestServiceStub::OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + switch (code) { + case TRANS_ID_PING_ABILITY: { + std::u16string dummy = data.ReadString16(); + int result = TestPingAbility(dummy); + reply.WriteInt32(result); + return 0; + } + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } +} +``` + +定义服务端业务函数具体实现类TestAbility + +``` +class TestAbility : public TestAbilityStub { +public: + int TestPingAbility(const std::u16string &dummy); +} + +int TestAbility::TestPingAbility(const std::u16string &dummy) { + return 0; +} +``` + +定义和实现客户端TestAbilityProxy + +该类是Proxy端实现,继承IRemoteProxy,调用SendRequest接口向Stub端发送请求,对外暴露服务端提供的能力。 + +``` +class TestAbilityProxy : public IRemoteProxy { +public: + explicit TestAbilityProxy(const sptr &impl); + int TestPingService(const std::u16string &dummy) override; +private: + static inline BrokerDelegator delegator_; // 方便使用iface_cast宏 +} + +TestAbilityProxy::TestAbilityProxy(const sptr &impl) + : IRemoteProxy(impl) +{ +} + +int TestAbilityProxy::TestPingService(const std::u16string &dummy) { + MessageOption option; + MessageParcel dataParcel, replyParcel; + dataParcel.WriteString16(dummy); + int error = Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option); + int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1; + return result; +} +``` + +同步调用与异步调用 + +MessageOption作为发送接口(原型如下)的入参,可设定同步(TF\_SYNC)、异步(TF\_ASYNC)、接收FD(TF\_ACCEPT\_FDS),默认情况下设定为同步,其余可通过MessageOption构造方法或void SetFlags\(int flags\)设定。 + +``` +int SendRequest(uint32_t code, MessageParcel &data, + MessageParcel &reply, MessageOption &option) override; +MessageOption option = { MessageOption::TF_ASYNC }; +``` + +SA注册与启动 + +SA需要将自己的TestAbilityStub实例通过AddSystemAbility接口注册到SystemAbilityManager,设备内与分布式的注册参数不同。 + +``` +// 注册到本设备内 +auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); +samgr->AddSystemAbility(said, new TestAbility()); + +// 在组网场景下,会被同步到其他设备上 +auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); +ISystemAbilityManager::SAExtraProp saExtra; +saExtra.isDistributed = true; // 设置为分布式SA +int result = samgr->AddSystemAbility(said, new TestAbility(), saExtra); +``` + +SA获取与调用 + +通过SystemAbilityManager的GetSystemAbility方法可获取到对应SA的代理IRemoteObject,然后构造TestAbilityProxy即可。 + +``` +// 获取本设备内注册的SA的proxy +sptr samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); +sptr remoteObject = samgr->GetSystemAbility(said); +sptr testAbility = iface_cast(remoteObject); // 使用iface_cast宏转换成具体类型 + +// 获取其他设备注册的SA的Proxy +sptr samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); +sptr remoteObject = samgr->GetSystemAbility(sdid, deviceId); // deviceId是指定设备的标识符 +sptr proxy(new TestAbilityProxy(remoteObject)); // 直接构造具体Proxy +``` + +## 相关仓 + +分布式软总线子系统 + +**communication\_ipc** + +utils + +utils\_native + +distributedschedule\_samgr + diff --git a/figures/ipc-architecture.png b/figures/ipc-architecture.png new file mode 100755 index 0000000000000000000000000000000000000000..0fd4beead6f9cb4a5f9f066546e1b2ad3bb42cf6 GIT binary patch literal 7890 zcmeHMd0bNY`lfNpnbNSkWN4x7n@MS#g)*jQjjfiMxsFSig=->;Kr2)>k~R&Mrj^-d z<_@_a7InomK?_Y#i4?^JAyg3Y9DYZu+uZy4{qy_%dGGw8$8!!I-tYT;-sgRu_gvh! z$K7D{Fzo8^)M6$Lt=NjIv*qiC_0{}tm*TwmFnQT!0%$(XB};? z6f|A4+<8*=^Za<}&%55;`Y^Bk;>C|YpFHUI!?IOp7X5hXhwb|hF1ciFyTtkVud^=R z6{z!70TN%Ze}t%fSLOde(rW}yxL?`W7k9s>C6VGEUm+n}S+X zi`Odao#{)Ct>B)Wym{w8;O4{SmdH**mnp&XNM65T+Su*z{Kp344=WqwJ83iu$Tyr> zzHR_@{pkUX4mzXM7&m?jV>3yh#4vkrL`zYvswTbaS%J4Eu}pBb#G(30E0dq{YJS7| zf%hSVpq&Bjt*iA_N951j<_ESM7x%sjo_+LY{NOrt;S$u)z%^39nvoADQc(kCis9gO z#`bTvXyzdgr<-d>Upp1dO^V)F%NP}D5{s^%y>WB_(FAT&m!eM!%l4k-xH+S%J_)C< zI^6JlS4pZP)%f@BS0r{ZKkqy;^UYL*0X98B_kC)STq6(l$LfH#Ug0))W6xM|fY=E& zH*W3QCn0p{>7|J=fdzxZ5qFHSamhXfxNP$jhwI1wT-Kkv^`8ksiiqL=GLnunepFd20Uj}`LAl~%RP}_65t-5J ziDRWtBnXa7mLWSYNiVJ*&E>G%JCg<$!<7>?TE}FN4&JV^>ZvC;9hs_7$K{4GI0aC3 zVaB;|35b)Zo7c$)Boh@hs|ip^8tagNzpC+U49Jy;nfXrIir8#LQFnG8?ogUxhP@rS zU4T+Y>8Pwu5%qGv(<%gdTug7rW6-YDGZA8THc{yvP;pE8TvZr6S>(#c+iA1_>V^L5 z>#OzKj!!X*)-N<%PT$~O-IpKLPQC1_O_Sz~PYl?hC$c9tT~Curf5L1IEy{kSk0OJ^ zsAToqY;xZTS0=)zp?8-X({K|`8GB`xR^Wvb=TT`U(}hf;gGZC3Q58fuTr|lZ30^n? z@5cE|ug&VdY(pCj`n(GYBy;q2*)~dg;@4^#a*!L-GQ-CD_JS{&JEF+aUP@1H$(*(x z2`I}3B|s_81a6f%715n5_R|!Umo}wQrqhADP6j{R+vBrz6KykoGx>{<$p!~P^?0kv zKhkqE7uID{jk(-QpLZmJ>jFM;lITk~6K~CpT)_!72aGFU5V!dYH@CCvea@j-yt^EW znKw=TjuTG|gTquBJOH$8;Hmb>QNua_qaTjV2-td7_1;VXU+NH-rjIm$?|sgZ2|VH& z5e9>2<~TA;EEKyg{vquFVT22NC*IRfh}|1^92BpmeP!s5%0PoKFgeCgm&X~q3O%@S zOQ<;cuOS8pF4q`kFg+SdSTQndG|eMTq|r5!M|I1LTq-3RC)!2=nt5Akb-KdoV;mcZh>aTK#RcGBJivT%y6Q?9`V9CdFhdGi1@V;tdM$V|aL7>oIY%CV?DR zSpZ7%#OtHTfH!?PBK0vpa6hu3C1SFJ4RwxU{~CEKJ{;;yN-h|3jrm^5I>r)jwfKw1 zihpIeLo#{`<N4?9o^`Fn69hT`!id!Xi+u^bG2d&lyH-9fq0#81R`=3icd#u1l6Tu^M3=TdDCIju*A1^n?>GoDd`TB72)ch!KfT zj^uqVk%BGg(4cS%TyGCkkQbq{6mdQyEJ|Z=wblICKwYx% zIN|CfabmVIA5qg+*N3!xVH0D8=RMw1cb`-A%=7Onx%(fBe?SH)1zSmdojWv(e<0&J$yH zkn3V;_p!z79p)c7QfZ4SW+9xk@;TW{GV{5IJseJ<5Osvn4g-SgV)(>vQVjWIi7#gj{=is% zcuoJ1GiKKaV`G>!o3CI+8M#yD2BEaVp$8QwA6g(k%A0dF8}z^AS|DQsg}@lO>7 z#)?yn4)|JY-Uy_cd?x2Sr7}CmjX=@uGXz|G&0_*xjW;g%VolZMOq^j%Utfr{41cGnH*%4G*&B9!Tt?H?1yc3*d2Su-x0^xhjeD4tvuJ)or59XIO=#fcx#CZzsWb zkCLeYm=mSWci2tiMdAQ2WaSsMXUUp#@W(tGZ4ZhE!%p!uX_7JlW#|zf-K{HCM6x$^ zWy$`4p+}=+VTa}B@$-qL9;9Mb=^YB6+hm!M0Y0$vVk|Bz`2k@)uC;F;cZ-HHf_LZ=81(sKf1hvBjh?N^ zn>crOV>HATpFsmA9BLO0{Yz9c$F(a4B^Uhqj8l_aIixDg>b1p%L#UY7FlZ?)DnVey zJL+jbkz;|pYih}&=KAtw@-FY+YxBycEQ|MsK3^Pt@Wu!{)L!*H0eN5IB@;&0z#0ul!3UXKpl9M0ko*U3C|haoZ(!e{?N5IFumX$7A~ z^h}bM!p0f;3}dN`PkzS3>q~wB5L7_6D~ExSF>#ge4W8x1^smtpXNwXBGpZO1vD1pf z=_d1ZsT4!Pvm}>Tz2hwRSrd5uL>t_!+(2G&5rULmXsI?lRL&!fYDp)Lb~*6kG9m3p zB|itR1H`|nm5Mkzn-NrC^}Ps@QcI@UgyyegGtmHT<+qxIN&!+(R@SS8 z9|Z8ZLgKPwQl-r*RJ%I^Rc1dsW@PKiA-AlvU+SVvt~G|jp^?cf70OoFU-}(b-7x9RfM~#2{;EZ0ol*2AxgJ8*E_LGBa}IW z=QBx=GtRo2xrP^Xr9M@Zpw39P$tDhx<{-9>*V8rF6~)h#6s#-Qa3hr|k78}LK#DlM z8xu<5$s3z02o{q6Z(!0ic@LA3uoB!GlUm&LgB&iKwf+L!<4!^Lgq zK@*o;3hE#Eo32Pwd??RP-kNgkt%6R=Ph@_n-|4TC@r$Vsm^k<_NBgsDWp`i8Mr~+I z;9CC&lVYOwZN1)F6gJZxqv*@}Dr~Rvw!gNS?i0_87D}^=c@TjU!&;UL<9pTugQe7)Zh9>QVY!hfQUt`8Kg2C3lR6(P6lXYn5 zx66Om<(j)r+HyXwmRFnHz1S*|(0eO^smRkO{#{wEA4<{ZJHczpWMhttxkfdwF3*Ou zSrW2d>Jd2ZnMhd-WlFoIR*66$VYc_JkWQnI_TmiH+8g}j9%+}AVT_v*RjmsaXI><9 zOnae%MN48QveKl}J_Os%FFl_OmW%G!6<&cR6dJ^e#|jvsQ*E(!>U*kQs|4LoTq@s~ zbH-l9TEeml<{KcH0DE@56@eTV5AvP50W%%JcK7%T^J-PFU`#-BD!o<4YfI@b&h@hs zI^mC7*D1vKNn<74(9QMSvmN&J6o_H!v zZvGyq6{`vZYqa7+T$dSCO_9l86kSB0c9vp%;bIpzy~sVa^Ffo7Brsh_Il*zP>5ol@ zv=p?afCK_BS`gVvsS2#Y62i4N&Xe`M5rhl)Y@cqem9h+{jvuFM12<_UGg9#Pb4=}o zB$l|0&l2~1(iqKz1zzitU4{~BK3u_d!N5jX1LmLH88a7{!rifdznT1mRLxO>c=x~( zN|qics^u2KRL|z4K4%3U3)z=Bmmr}hLY(Pe?l7uMkt-|N1s_`wDdBV+$G?(a8ws!R zmR)z4%5U;ME*E5*u_4_|lsL!hH!c~J&;&!PwPH%LQa-?>CsK@RuFtps{B(ONZQ@|A z=F>)WH=nHU%!m938UQp58yTa;OU$_hc~?zQEfo%{URB%hC6ka}Qs3+ED%gs4)$iN` zS>)5c zmTMOo?V%(duq}z8uhzJ{XsVs|@arZ(N+QN!#RG;PFG^^@(Tz7ISZl zZ?hAY0GoF;q-P2g_Rt7v9`8kE5;s=a0Bt}BzL7lXH7iXl0H1V7+F=)~{qn@6if@U9 z!Gi_dzYX1M<&)%ld b4AU##EO &object); + static IPCFileDescriptor *Unmarshalling(Parcel &parcel); + int GetFd() const; + void SetFd(int fd); + +private: + int fd_ = -1; +}; +} // namespace OHOS +#endif // OHOS_IPC_IPC_FILE_DESCRIPTOR_H diff --git a/interfaces/innerkits/ipc_core/include/ipc_object_proxy.h b/interfaces/innerkits/ipc_core/include/ipc_object_proxy.h new file mode 100755 index 00000000..1d66e4b6 --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/ipc_object_proxy.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IPC_OBJECT_PROXY_H +#define OHOS_IPC_IPC_OBJECT_PROXY_H + +#include +#include + +#include "iremote_object.h" + +namespace OHOS { +class IPCObjectProxy : public IRemoteObject { +public: + explicit IPCObjectProxy(int handle, std::u16string descriptor = std::u16string(), + int proto = IRemoteObject::IF_PROT_DEFAULT); + ~IPCObjectProxy(); + + int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &optionoption) override; + + bool IsProxyObject() const override + { + return true; + }; + + bool IsObjectDead() const; + + int32_t GetObjectRefCount() override; + + int Dump(int fd, const std::vector &args) override; + + void OnFirstStrongRef(const void *objectId) override; + + void OnLastStrongRef(const void *objectId) override; + + bool AddDeathRecipient(const sptr &recipient) override; + + bool RemoveDeathRecipient(const sptr &recipient) override; + + void SendObituary(); + + bool IsSubscribeDeathNotice() const + { + if (recipients_.empty()) { + return false; + } + return true; + }; + + uint32_t GetHandle() const + { + return handle_; + }; + + int InvokeListenThread(MessageParcel &data, MessageParcel &reply); + int32_t NoticeServiceDie(); + std::string GetPidAndUidInfo(); + + std::string GetDataBusName(); + int GetProto() const; + void WaitForInit(); + std::u16string GetInterfaceDescriptor(); + +private: + void MarkObjectDied(); + int SendLocalRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &optionoption); + int SendRequestInner(bool isLocal, uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + +#ifndef CONFIG_IPC_SINGLE + void SetProto(int proto); + + int UpdateProto(); + + void ReleaseProto(); + + void IncRefToRemote(); + + int GetSessionFromDBinderService(); + + bool AddDbinderDeathRecipient(); + + bool RemoveDbinderDeathRecipient(); + + void ReleaseDatabusProto(); + + void ReleaseBinderProto(); + + bool UpdateDatabusClientSession(int handle, MessageParcel &reply); + + bool CheckHaveSession(uint32_t &type); +#endif + +private: + std::mutex initMutex_; + std::recursive_mutex mutex_; + + std::vector> recipients_; + const uint32_t handle_; + int proto_; + bool isFinishInit_; + bool isRemoteDead_; + std::u16string remoteDescriptor_; +}; +} // namespace OHOS +#endif // OHOS_IPC_IPC_OBJECT_PROXY_H diff --git a/interfaces/innerkits/ipc_core/include/ipc_object_stub.h b/interfaces/innerkits/ipc_core/include/ipc_object_stub.h new file mode 100755 index 00000000..91eed02a --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/ipc_object_stub.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IPC_OBJECT_STUB_H +#define OHOS_IPC_IPC_OBJECT_STUB_H + +#include "iremote_object.h" +#include +#include "ipc_object_proxy.h" + +namespace OHOS { +struct RefCountNode { + int remotePid; + std::string deviceId; +}; + +class IPCObjectStub : public IRemoteObject { +public: + explicit IPCObjectStub(std::u16string descriptor = nullptr); + ~IPCObjectStub(); + + bool IsProxyObject() const override + { + return false; + }; + + int32_t GetObjectRefCount() override; + + int Dump(int fd, const std::vector &args) override; + + virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + + int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + void OnFirstStrongRef(const void *objectId) override; + + void OnLastStrongRef(const void *objectId) override; + + bool AddDeathRecipient(const sptr &recipient) override; + + bool RemoveDeathRecipient(const sptr &recipient) override; + + int GetCallingPid(); + + int GetCallingUid(); + + virtual int OnRemoteDump(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + + virtual int32_t ProcessProto(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + +#ifndef CONFIG_IPC_SINGLE + int32_t InvokerThread(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + + int32_t NoticeServiceDie(MessageParcel &data, MessageParcel &reply, MessageOption &option); + + int32_t InvokerDataBusThread(MessageParcel &data, MessageParcel &reply); + + int32_t IncStubRefs(MessageParcel &data, MessageParcel &reply); + int32_t DecStubRefs(MessageParcel &data, MessageParcel &reply); + + int32_t AddAuthInfo(MessageParcel &data, MessageParcel &reply); + +private: + int32_t GrantDataBusName(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + std::string CreateDatabusName(int uid, int pid); + std::string GetDataBusName(); +#endif +private: + bool IsDeviceIdIllegal(const std::string &deviceID); +}; +} // namespace OHOS +#endif // OHOS_IPC_IPC_OBJECT_STUB_H diff --git a/interfaces/innerkits/ipc_core/include/ipc_skeleton.h b/interfaces/innerkits/ipc_core/include/ipc_skeleton.h new file mode 100755 index 00000000..fa59b085 --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/ipc_skeleton.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IPC_SKELETON_H +#define OHOS_IPC_IPC_SKELETON_H + +#include "iremote_object.h" + +namespace OHOS { +class IPCSkeleton { +public: + IPCSkeleton() = default; + ~IPCSkeleton() = default; + + // default max is 4, only if you need a customize value + static bool SetMaxWorkThreadNum(int maxThreadNum); + + // join current thread into work loop. + static void JoinWorkThread(); + + // remove current thread from work loop. + static void StopWorkThread(); + + static pid_t GetCallingPid(); + + static pid_t GetCallingUid(); + + static std::string GetLocalDeviceID(); + + static std::string GetCallingDeviceID(); + + static bool IsLocalCalling(); + + static IPCSkeleton &GetInstance(); + + static sptr GetContextObject(); + + static bool SetContextObject(sptr &object); + + static int FlushCommands(IRemoteObject *object); + + static std::string ResetCallingIdentity(); + + static bool SetCallingIdentity(std::string &identity); +}; +} // namespace OHOS +#endif // OHOS_IPC_IPC_SKELETON_H diff --git a/interfaces/innerkits/ipc_core/include/ipc_types.h b/interfaces/innerkits/ipc_core/include/ipc_types.h new file mode 100755 index 00000000..df3b3cb4 --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/ipc_types.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IPC_TYPES_H +#define OHOS_IPC_IPC_TYPES_H + +#include +#include +#include "errors.h" + +namespace OHOS { +#define ZIPC_PACK_CHARS(c1, c2, c3, c4) ((((c1) << 24)) | (((c2) << 16)) | (((c3) << 8)) | (c4)) + +constexpr int REGISTRY_HANDLE = 0; + +enum { + FIRST_CALL_TRANSACTION = 0x00000001, + LAST_CALL_TRANSACTION = 0x00ffffff, + PING_TRANSACTION = ZIPC_PACK_CHARS('_', 'P', 'N', 'G'), + DUMP_TRANSACTION = ZIPC_PACK_CHARS('_', 'D', 'M', 'P'), + SHELL_COMMAND_TRANSACTION = ZIPC_PACK_CHARS('_', 'C', 'M', 'D'), + INTERFACE_TRANSACTION = ZIPC_PACK_CHARS('_', 'N', 'T', 'F'), + SYSPROPS_TRANSACTION = ZIPC_PACK_CHARS('_', 'S', 'P', 'R'), + SYNCHRONIZE_REFERENCE = ZIPC_PACK_CHARS('_', 'S', 'Y', 'C'), + INVOKE_LISTEN_THREAD = ZIPC_PACK_CHARS('_', 'I', 'L', 'T'), + GET_PROTO_INFO = ZIPC_PACK_CHARS('_', 'G', 'R', 'I'), + GET_UIDPID_INFO = ZIPC_PACK_CHARS('_', 'G', 'U', 'I'), + GRANT_DATABUS_NAME = ZIPC_PACK_CHARS('_', 'G', 'D', 'N'), + DBINDER_OBITUARY_TRANSACTION = ZIPC_PACK_CHARS('_', 'D', 'O', 'T'), + DBINDER_INCREFS_TRANSACTION = ZIPC_PACK_CHARS('_', 'D', 'I', 'T'), + DBINDER_DECREFS_TRANSACTION = ZIPC_PACK_CHARS('_', 'D', 'D', 'T'), + DBINDER_ADD_COMMAUTH = ZIPC_PACK_CHARS('_', 'D', 'A', 'C'), + TRANS_SYNC = 0, + TRANS_ASYNC = 1, +}; + +enum { + NO_ERROR = 0, + TRANSACTION_ERR, + FLATTEN_ERR = 3, + UNKNOWN_TRANSACTION = 4, + INVALID_DATA = 5, + OBJECT_NULL = 7, + INVALID_OPERATION = 8, + DEAD_OBJECT = -EPIPE, + UNKNOWN_ERROR, +}; + +constexpr int MIN_TRANSACTION_ID = 0x1; +constexpr int MAX_TRANSACTION_ID = 0x00ffffff; +constexpr int INVALID_FD = -1; + +enum { + ERR_NONE = 0, + ERR_TRANSACTION_FAILED = 1, + ERR_UNKNOWN_OBJECT = 2, + ERR_FLATTEN_OBJECT = 3, + ERR_UNKNOWN_TRANSACTION = 4, + ERR_INVALID_DATA = 5, + ERR_NULL_OBJECT = 7, + ERR_UNKNOWN_REASON, + ERR_INVALID_REPLY, + ERR_INVALID_STATE, + IPC_SKELETON_ERR = 100, + IPC_SKELETON_NULL_OBJECT_ERR, + IPC_PROXY_ERR = 200, + IPC_PROXY_DEAD_OBJECT_ERR, + IPC_PROXY_NULL_INVOKER_ERR, + IPC_PROXY_TRANSACTION_ERR, + IPC_PROXY_INVALID_CODE_ERR, + IPC_STUB_ERR = 300, + IPC_STUB_WRITE_PARCEL_ERR, + IPC_STUB_INVOKE_THREAD_ERR, + IPC_STUB_INVALID_DATA_ERR, + IPC_STUB_CURRENT_NULL_ERR, + IPC_STUB_UNKNOW_TRANS_ERR, + IPC_STUB_CREATE_BUS_SERVER_ERR, + IPC_INVOKER_ERR = 400, + IPC_INVOKER_WRITE_TRANS_ERR, + IPC_INVOKER_TRANSLATE_ERR, + IPC_INVOKER_CONNECT_ERR, + IPC_INVOKER_ON_TRANSACT_ERR, + IPC_INVOKER_INVALID_DATA_ERR, + IPC_INVOKER_INVALID_REPLY_ERR, + RPC_BASE_INVOKER_ERR = 500, + RPC_BASE_INVOKER_INVALID_REPLY_ERR, + RPC_BASE_INVOKER_WAIT_REPLY_ERR, + RPC_BASE_INVOKER_CURRENT_NULL_ERR, + RPC_BASE_INVOKER_INVALID_DATA_ERR, + RPC_BASE_INVOKER_WRITE_TRANS_ERR, + RPC_BASE_INVOKER_SEND_REPLY_ERR, + RPC_DATABUS_INVOKER_ERR = 600, + RPC_DATABUS_INVOKER_INVALID_DATA_ERR, + RPC_DATABUS_INVOKER_CLOSED_PEER_ERR, + RPC_DATABUS_INVOKER_INVALID_STUB_INDEX, + DBINDER_SERVICE_ERR = 700, + DBINDER_SERVICE_INVALID_DATA_ERR, + DBINDER_SERVICE_NOTICE_DIE_ERR, + DBINDER_SERVICE_PROCESS_PROTO_ERR, + DBINDER_SERVICE_UNKNOW_TRANS_ERR, + DBINDER_SERVICE_ADD_DEATH_ERR, + DBINDER_SERVICE_REMOVE_DEATH_ERR, + DBINDER_SERVICE_WRONG_SESSION, + SESSION_WRONG_FD_ERR = 800, + SESSION_INVOKER_NULL_ERR, + SESSION_UNAUTHENTICATED_ERR, + SESSION_UNOPEN_ERR = -1, +}; +} // namespace OHOS +#endif // OHOS_IPC_IPC_TYPES_H diff --git a/interfaces/innerkits/ipc_core/include/iremote_broker.h b/interfaces/innerkits/ipc_core/include/iremote_broker.h new file mode 100755 index 00000000..4251a993 --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/iremote_broker.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IREMOTE_BROKER_H +#define OHOS_IPC_IREMOTE_BROKER_H + +#include +#include +#include "iremote_object.h" +#include "refbase.h" + +namespace OHOS { +template class BrokerCreator { +public: + BrokerCreator() = default; + ~BrokerCreator() = default; + sptr operator () (const sptr &object) + { + return static_cast(new T(object)); + }; +}; + +class IRemoteBroker : public virtual RefBase { +public: + IRemoteBroker() = default; + virtual ~IRemoteBroker() override = default; + virtual sptr AsObject() = 0; + static inline sptr AsImplement(const sptr &object) + { + return nullptr; + } +}; + +#define DECLARE_INTERFACE_DESCRIPTOR(DESCRIPTOR) \ + static inline const std::u16string metaDescriptor_ = { DESCRIPTOR }; \ + static inline const std::u16string &GetDescriptor() \ + { \ + return metaDescriptor_; \ + } + +class BrokerRegistration { + using Constructor = std::function(const sptr &object)>; + +public: + static BrokerRegistration &Get(); + bool Register(const std::u16string &descriptor, const Constructor &creator); + void Unregister(const std::u16string &descriptor); + sptr NewInstance(const std::u16string &descriptor, const sptr &object); + +protected: + BrokerRegistration() = default; + ~BrokerRegistration(); + +private: + BrokerRegistration(const BrokerRegistration &) = delete; + BrokerRegistration(BrokerRegistration &&) = delete; + BrokerRegistration &operator = (const BrokerRegistration &) = delete; + BrokerRegistration &operator = (BrokerRegistration &&) = delete; + std::mutex creatorMutex_; + std::unordered_map creators_; +}; + +template class BrokerDelegator { +public: + BrokerDelegator(); + ~BrokerDelegator(); + +private: + BrokerDelegator(const BrokerDelegator &) = delete; + BrokerDelegator(BrokerDelegator &&) = delete; + BrokerDelegator &operator = (const BrokerDelegator &) = delete; + BrokerDelegator &operator = (BrokerDelegator &&) = delete; +}; + +template BrokerDelegator::BrokerDelegator() +{ + const std::u16string descriptor = T::GetDescriptor(); + BrokerRegistration ®istration = BrokerRegistration::Get(); + registration.Register(descriptor, BrokerCreator()); +} + +template BrokerDelegator::~BrokerDelegator() +{ + const std::u16string descriptor = T::GetDescriptor(); + BrokerRegistration ®istration = BrokerRegistration::Get(); + registration.Unregister(descriptor); +} + +template inline sptr iface_cast(const sptr &object) +{ + const std::u16string descriptor = INTERFACE::GetDescriptor(); + BrokerRegistration ®istration = BrokerRegistration::Get(); + sptr broker = registration.NewInstance(descriptor, object); + return static_cast(broker.GetRefPtr()); +} +} // namespace OHOS +#endif // OHOS_IPC_IREMOTE_BROKER_H diff --git a/interfaces/innerkits/ipc_core/include/iremote_object.h b/interfaces/innerkits/ipc_core/include/iremote_object.h new file mode 100755 index 00000000..3d73fa69 --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/iremote_object.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IREMOTE_OBJECT_H +#define OHOS_IPC_IREMOTE_OBJECT_H + +#include +#include +#include +#include +#include "ipc_types.h" +#include "message_parcel.h" +#include "message_option.h" + +namespace OHOS { +class IRemoteBroker; +inline std::u16string to_utf16(const std::string &str) +{ + return std::wstring_convert, char16_t> {}.from_bytes(str); +} + +class IRemoteObject : public virtual Parcelable, public virtual RefBase { +public: + enum { + IF_PROT_DEFAULT, /* Invoker family. */ + IF_PROT_BINDER = IF_PROT_DEFAULT, + IF_PROT_DATABUS, + }; + enum { + DATABUS_TYPE, + }; + class DeathRecipient : public RefBase { + public: + enum { + ADD_DEATH_RECIPIENT, + REMOVE_DEATH_RECIPIENT, + NOTICE_DEATH_RECIPIENT, + TEST_SERVICE_DEATH_RECIPIENT, + TEST_DEVICE_DEATH_RECIPIENT, + }; + virtual void OnRemoteDied(const wptr &object) = 0; + }; + + virtual int32_t GetObjectRefCount() = 0; + + virtual int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) = 0; + + virtual bool IsProxyObject() const; + + virtual bool CheckObjectLegality() const; + + virtual bool AddDeathRecipient(const sptr &recipient) = 0; + + virtual bool RemoveDeathRecipient(const sptr &recipient) = 0; + + virtual bool Marshalling(Parcel &parcel) const override; + + static IRemoteObject *Unmarshalling(Parcel &parcel); + + static bool Marshalling(Parcel &parcel, const sptr &object); + + virtual sptr AsInterface(); + + virtual int Dump(int fd, const std::vector &args) = 0; + + const std::u16string descriptor_; + + std::u16string GetObjectDescriptor() const; + +protected: + explicit IRemoteObject(std::u16string descriptor = nullptr); +}; +} // namespace OHOS +#endif // OHOS_IPC_IREMOTE_OBJECT_H diff --git a/interfaces/innerkits/ipc_core/include/iremote_proxy.h b/interfaces/innerkits/ipc_core/include/iremote_proxy.h new file mode 100755 index 00000000..fff5bc5f --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/iremote_proxy.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IREMOTE_PROXY_H +#define OHOS_IPC_IREMOTE_PROXY_H + +#include "iremote_broker.h" +#include "peer_holder.h" +#include "iremote_object.h" + +namespace OHOS { +template class IRemoteProxy : public PeerHolder, public INTERFACE { +public: + explicit IRemoteProxy(const sptr &object); + ~IRemoteProxy() override = default; + +protected: + sptr AsObject() override; +}; + +template +IRemoteProxy::IRemoteProxy(const sptr &object) : PeerHolder(object) +{ +} + +template sptr IRemoteProxy::AsObject() +{ + return Remote(); +} +} // namespace OHOS +#endif // OHOS_IPC_IREMOTE_PROXY_H diff --git a/interfaces/innerkits/ipc_core/include/iremote_stub.h b/interfaces/innerkits/ipc_core/include/iremote_stub.h new file mode 100755 index 00000000..3151a93a --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/iremote_stub.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IREMOTE_STUB_H +#define OHOS_IPC_IREMOTE_STUB_H + +#include +#include "iremote_broker.h" +#include "ipc_object_stub.h" + +namespace OHOS { +template class IRemoteStub : public IPCObjectStub, public INTERFACE { +public: + IRemoteStub(); + virtual ~IRemoteStub() = default; + sptr AsObject() override; + sptr AsInterface() override; +}; + +template IRemoteStub::IRemoteStub() : IPCObjectStub(INTERFACE::GetDescriptor()) {} + +template sptr IRemoteStub::AsInterface() +{ + return this; +} + +template sptr IRemoteStub::AsObject() +{ + return this; +} +} // namespace OHOS +#endif // OHOS_IPC_IREMOTE_STUB_H diff --git a/interfaces/innerkits/ipc_core/include/jni_help.h b/interfaces/innerkits/ipc_core/include/jni_help.h new file mode 100755 index 00000000..fb286bfd --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/jni_help.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_JNI_HELP_H +#define OHOS_IPC_JNI_HELP_H + +#include +#include +#include + +namespace OHOS { +jobject JNIHelperGetJavaRemoteObject(JNIEnv *env, const sptr &target); +} // namespace OHOS +#endif // OHOS_IPC_JNI_HELP_H diff --git a/interfaces/innerkits/ipc_core/include/message_option.h b/interfaces/innerkits/ipc_core/include/message_option.h new file mode 100755 index 00000000..7aa96519 --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/message_option.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_MESSAGE_OPTION_H +#define OHOS_IPC_MESSAGE_OPTION_H + +#include +namespace OHOS { +class MessageOption { +public: + enum { + TF_SYNC = 0x00, + TF_ASYNC = 0x01, + TF_STATUS_CODE = 0x08, + TF_ACCEPT_FDS = 0x10, + TF_WAIT_TIME = 0x4, + }; + MessageOption(int flags = TF_SYNC, int waitTime = TF_WAIT_TIME); + ~MessageOption() = default; + void SetFlags(int flags); + int GetFlags() const; + void SetWaitTime(int waitTime); + int GetWaitTime() const; + +private: + uint32_t flags_; + int waitTime_; +}; +using MessageOptionPtr = std::shared_ptr; +} // namespace OHOS +#endif // OHOS_IPC_MESSAGE_OPTION_H \ No newline at end of file diff --git a/interfaces/innerkits/ipc_core/include/message_parcel.h b/interfaces/innerkits/ipc_core/include/message_parcel.h new file mode 100755 index 00000000..8542b860 --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/message_parcel.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_MESSAGE_PARCEL_H +#define OHOS_IPC_MESSAGE_PARCEL_H + +#include +#include "parcel.h" +#include "refbase.h" +#include + +namespace OHOS { +class IRemoteObject; +class MessageParcel : public Parcel { +public: + MessageParcel(); + ~MessageParcel(); + explicit MessageParcel(Allocator *allocator); + bool WriteRemoteObject(const sptr &object); + sptr ReadRemoteObject(); + bool WriteFileDescriptor(int fd); + int ReadFileDescriptor(); + bool ContainFileDescriptors() const; + bool WriteInterfaceToken(std::u16string name); + std::u16string ReadInterfaceToken(); + bool WriteRawData(const void *data, size_t size); + const void *ReadRawData(size_t size); + bool RestoreRawData(std::shared_ptr rawData, size_t size); + const void *GetRawData() const; + size_t GetRawDataSize() const; + size_t GetRawDataCapacity() const; + void WriteNoException(); + int32_t ReadException(); + bool WriteAshmem(sptr ashmem); + sptr ReadAshmem(); + void ClearFileDescriptor(); + void SetClearFdFlag() + { + needCloseFd_ = true; + }; + +private: + static constexpr size_t MAX_RAWDATA_SIZE = 128 * 1024 * 1024; // 128M + static constexpr size_t MIN_RAWDATA_SIZE = 32 * 1024; // 32k + bool needCloseFd_ = false; + std::vector> holders_; + int writeRawDataFd_; + int readRawDataFd_; + void *kernelMappedWrite_; + void *kernelMappedRead_; + std::shared_ptr rawData_; + size_t rawDataSize_; +}; +} // namespace OHOS +#endif // OHOS_IPC_MESSAGE_PARCEL_H diff --git a/interfaces/innerkits/ipc_core/include/peer_holder.h b/interfaces/innerkits/ipc_core/include/peer_holder.h new file mode 100755 index 00000000..9ca9c7bf --- /dev/null +++ b/interfaces/innerkits/ipc_core/include/peer_holder.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_PEER_HOLDER_H +#define OHOS_IPC_PEER_HOLDER_H + +#include "iremote_object.h" + +namespace OHOS { +class PeerHolder { +protected: + PeerHolder(const sptr &object); + + ~PeerHolder() = default; + + sptr Remote(); + +private: + const sptr remoteObject_; +}; +} // namespace OHOS +#endif // OHOS_IPC_PEER_HOLDER_H diff --git a/interfaces/innerkits/ipc_single/BUILD.gn b/interfaces/innerkits/ipc_single/BUILD.gn new file mode 100755 index 00000000..7e9610a2 --- /dev/null +++ b/interfaces/innerkits/ipc_single/BUILD.gn @@ -0,0 +1,58 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +IPC_CORE_ROOT = "$SUBSYSTEM_DIR/ipc/native" + +config("libipc_single_private_config") { + cflags_cc = [ + "-DCONFIG_IPC_SINGLE", + "-O2", + ] +} +ohos_shared_library("ipc_single") { + include_dirs = [ "$SUBSYSTEM_DIR/utils/include" ] + sources = [ + "$IPC_CORE_ROOT/src/core/source/ipc_file_descriptor.cpp", + "$IPC_CORE_ROOT/src/core/source/ipc_object_proxy.cpp", + "$IPC_CORE_ROOT/src/core/source/ipc_object_stub.cpp", + "$IPC_CORE_ROOT/src/core/source/ipc_process_skeleton.cpp", + "$IPC_CORE_ROOT/src/core/source/ipc_skeleton.cpp", + "$IPC_CORE_ROOT/src/core/source/ipc_thread_pool.cpp", + "$IPC_CORE_ROOT/src/core/source/ipc_thread_skeleton.cpp", + "$IPC_CORE_ROOT/src/core/source/ipc_workthread.cpp", + "$IPC_CORE_ROOT/src/core/source/iremote_broker.cpp", + "$IPC_CORE_ROOT/src/core/source/iremote_object.cpp", + "$IPC_CORE_ROOT/src/core/source/message_option.cpp", + "$IPC_CORE_ROOT/src/core/source/message_parcel.cpp", + "$IPC_CORE_ROOT/src/core/source/peer_holder.cpp", + "$IPC_CORE_ROOT/src/mock/source/binder_connector.cpp", + "$IPC_CORE_ROOT/src/mock/source/binder_debug.cpp", + "$IPC_CORE_ROOT/src/mock/source/binder_invoker.cpp", + "$IPC_CORE_ROOT/src/mock/source/invoker_factory.cpp", + "$IPC_CORE_ROOT/src/mock/source/invoker_rawdata.cpp", + ] + + configs = [ + "$SUBSYSTEM_DIR:ipc_util_config", + ":libipc_single_private_config", + ] + public_configs = [ "$SUBSYSTEM_DIR:ipc_util_config" ] + deps = [ "//utils/native/base:utils" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + subsystem_name = "communication" + part_name = "ipc" +} diff --git a/interfaces/innerkits/libdbinder/BUILD.gn b/interfaces/innerkits/libdbinder/BUILD.gn new file mode 100755 index 00000000..b059cdda --- /dev/null +++ b/interfaces/innerkits/libdbinder/BUILD.gn @@ -0,0 +1,66 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +DBINDER_ROOT = "$SUBSYSTEM_DIR/services/dbinder" + +config("libdbinder_config") { + visibility = [ ":*" ] + cflags = [] + if (target_cpu == "arm") { + cflags = [ "-DBINDER_IPC_32BIT" ] + } + if (is_standard_system) { + cflags += [ "-DCONFIG_STANDARD_SYSTEM" ] + } + include_dirs = [ + "//utils/native/base/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_core/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/libdbinder/include", + "$DBINDER_ROOT/dbinder_service/include", + ] +} + +config("libdbinder_private_config") { + visibility = [ ":*" ] + cflags_cc = [ + "-DLOG_TAG=\"libdbinder\"", + "-O2", + ] +} + +ohos_shared_library("libdbinder") { + include_dirs = [ "$SUBSYSTEM_DIR/utils/include" ] + sources = [ + "$DBINDER_ROOT/dbinder_service/src/dbinder_death_recipient.cpp", + "$DBINDER_ROOT/dbinder_service/src/dbinder_sa_death_recipient.cpp", + "$DBINDER_ROOT/dbinder_service/src/dbinder_service.cpp", + "$DBINDER_ROOT/dbinder_service/src/dbinder_service_stub.cpp", + "$DBINDER_ROOT/dbinder_service/src/socket/dbinder_remote_listener.cpp", + ] + public_configs = [ ":libdbinder_config" ] + configs = [ ":libdbinder_private_config" ] + deps = [ + "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_core:ipc_core", + "//utils/native/base:utils", + ] + external_deps = [ + "dsoftbus_standard:softbus_client", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + subsystem_name = "communication" + part_name = "ipc" +} diff --git a/interfaces/innerkits/libdbinder/include/dbinder_service.h b/interfaces/innerkits/libdbinder/include/dbinder_service.h new file mode 100755 index 00000000..0b09341c --- /dev/null +++ b/interfaces/innerkits/libdbinder/include/dbinder_service.h @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_SERVICES_DBINDER_DBINDER_SERVICE_H +#define OHOS_IPC_SERVICES_DBINDER_DBINDER_SERVICE_H + +#include +#include +#include +#include +#include +#include +#include + +#include "ipc_object_proxy.h" +#include "ipc_object_stub.h" +#include "dbinder_service_stub.h" + +namespace OHOS { +class DBinderRemoteListener; + +constexpr int DEVICEID_LENGTH = 64; +constexpr int SERVICENAME_LENGTH = 200; +constexpr int VERSION_NUM = 1; +constexpr int ENCRYPT_HEAD_LEN = 28; +constexpr int ENCRYPT_LENGTH = 4; + +struct DeviceIdInfo { + uint16_t afType; + uint16_t reserved; + char fromDeviceId[DEVICEID_LENGTH + 1]; + char toDeviceId[DEVICEID_LENGTH + 1]; +}; + +struct DHandleEntryHead { + uint32_t len; + uint32_t version; +}; + +struct DHandleEntryTxRx { + struct DHandleEntryHead head; + uint32_t transType; + uint32_t dBinderCode; + uint16_t fromPort; + uint16_t toPort; + uint64_t stubIndex; + uint32_t seqNumber; + binder_uintptr_t binderObject; + struct DeviceIdInfo deviceIdInfo; + binder_uintptr_t stub; + uint16_t serviceNameLength; + char serviceName[SERVICENAME_LENGTH + 1]; + uint32_t pid; + uint32_t uid; +}; + +struct SessionInfo { + uint32_t type; + uint16_t toPort; + uint16_t fromPort; + uint64_t stubIndex; + uint32_t socketFd; + std::string serviceName; + struct DeviceIdInfo deviceIdInfo; +}; + +enum DBinderCode { + MESSAGE_AS_INVOKER = 1, + MESSAGE_AS_REPLY = 2, + MESSAGE_AS_OBITUARY = 3, +}; + +enum AfType { + IPV4_TYPE = 1, + IPV6_TYPE = 2, + DATABBUS_TYPE = 3, +}; + +struct ThreadLockInfo { + std::mutex mutex; + std::condition_variable condition; + bool ready = false; +}; + +class DBinderService : public virtual RefBase { +public: + DBinderService(); + virtual ~DBinderService(); +public: + static sptr GetInstance(); + bool StartDBinderService(); + sptr MakeRemoteBinder(const std::u16string &serviceName, + const std::string &deviceID, binder_uintptr_t binderObject, uint64_t pid = 0); + bool RegisterRemoteProxy(std::u16string serviceName, sptr binderObject); + bool OnRemoteMessageTask(const struct DHandleEntryTxRx *message); + std::shared_ptr QuerySessionObject(binder_uintptr_t stub); + bool DetachDeathRecipient(sptr object); + bool AttachDeathRecipient(sptr object, sptr deathRecipient); + sptr QueryDeathRecipient(sptr object); + bool DetachCallbackProxy(sptr object); + bool AttachCallbackProxy(sptr object, DBinderServiceStub *dbStub); + int32_t NoticeServiceDie(const std::u16string &serviceName, const std::string &deviceID); + int32_t NoticeDeviceDie(const std::string &deviceID); + bool DetachBusNameObject(IPCObjectProxy *proxy); + std::string CreateDatabusName(int uid, int pid); + bool DetachProxyObject(binder_uintptr_t binderObject); + +private: + static std::shared_ptr GetRemoteListener(); + static bool StartRemoteListener(); + static void StopRemoteListener(); + static std::string ConvertToSecureDeviceID(const std::string &deviceID); + std::u16string GetRegisterService(binder_uintptr_t binderObject); + bool InvokerRemoteDBinder(const sptr stub, uint32_t seqNumber); + bool OnRemoteReplyMessage(const struct DHandleEntryTxRx *replyMessage); + void MakeSessionByReplyMessage(const struct DHandleEntryTxRx *replyMessage); + bool OnRemoteInvokerMessage(const struct DHandleEntryTxRx *message); + void WakeupThreadByStub(uint32_t seqNumber); + void DetachThreadLockInfo(uint32_t seqNumber); + bool AttachThreadLockInfo(uint32_t seqNumber, std::shared_ptr object); + std::shared_ptr QueryThreadLockInfo(uint32_t seqNumber); + bool AttachProxyObject(sptr object, binder_uintptr_t binderObject); + sptr QueryProxyObject(binder_uintptr_t binderObject); + bool DetachSessionObject(binder_uintptr_t stub); + bool AttachSessionObject(std::shared_ptr object, binder_uintptr_t stub); + sptr FindOrNewProxy(binder_uintptr_t binderObject); + bool SendEntryToRemote(const sptr stub, uint32_t seqNumber); + uint16_t AllocFreeSocketPort(); + std::string GetLocalDeviceID(); + bool CheckBinderObject(const sptr &stub, binder_uintptr_t binderObject); + bool HasDBinderStub(binder_uintptr_t binderObject); + bool IsSameStubObject(const sptr &stub, const std::u16string &service, + const std::string &device); + sptr FindDBinderStub(const std::u16string &service, const std::string &device); + bool DeleteDBinderStub(const std::u16string &service, const std::string &device); + sptr FindOrNewDBinderStub(const std::u16string &service, + const std::string &device, binder_uintptr_t binderObject); + void ProcessCallbackProxy(sptr dbStub); + bool NoticeCallbackProxy(sptr dbStub); + std::list FindServicesByDeviceID(const std::string &deviceID); + int32_t NoticeServiceDieInner(const std::u16string &serviceName, const std::string &deviceID); + uint32_t GetRemoteTransType(); + bool OnRemoteInvokerDataBusMessage(IPCObjectProxy *proxy, struct DHandleEntryTxRx *replyMessage, + std::string &remoteDeviceId, int pid, int uid); + bool IsDeviceIdIllegal(const std::string &deviceID); + bool AttachBusNameObject(IPCObjectProxy *proxy, const std::string &name); + std::string QueryBusNameObject(IPCObjectProxy *proxy); + std::string GetDatabusNameByProxy(IPCObjectProxy *proxy); + uint32_t GetSeqNumber(); + +private: + DISALLOW_COPY_AND_MOVE(DBinderService); + static std::mutex instanceMutex_; + static constexpr int WAIT_FOR_REPLY_MAX_SEC = 4; + static constexpr int RETRY_TIMES = 2; + static std::shared_ptr remoteListener_; + static bool mainThreadCreated_; + static sptr instance_; + + std::shared_mutex remoteBinderMutex_; + std::shared_mutex busNameMutex_; + std::shared_mutex proxyMutex_; + std::shared_mutex deathRecipientMutex_; + std::shared_mutex sessionMutex_; + + std::mutex handleEntryMutex_; + std::mutex threadLockMutex_; + std::mutex callbackProxyMutex_; + std::mutex deathNotificationMutex_; + + uint32_t seqNumber_ = 0; /* indicate make remote binder message sequence number, and can be overflow */ + std::list> DBinderStubRegisted_; + std::map mapRemoteBinderObjects_; + std::map> threadLockInfo_; + std::map> proxyObject_; + std::map> sessionObject_; + std::map, DBinderServiceStub *> noticeProxy_; + std::map, sptr> deathRecipients_; + std::map busNameObject_; +}; +} // namespace OHOS +#endif // OHOS_IPC_SERVICES_DBINDER_DBINDER_SERVICE_H diff --git a/interfaces/innerkits/libdbinder/include/dbinder_service_stub.h b/interfaces/innerkits/libdbinder/include/dbinder_service_stub.h new file mode 100755 index 00000000..e6f4f171 --- /dev/null +++ b/interfaces/innerkits/libdbinder/include/dbinder_service_stub.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_SERVICES_DBINDER_DBINDER_STUB_H +#define OHOS_IPC_SERVICES_DBINDER_DBINDER_STUB_H + +#include +#include +#include "ipc_object_stub.h" + +namespace OHOS { +#ifdef BINDER_IPC_32BIT +typedef unsigned int binder_uintptr_t; +#else +typedef unsigned long long binder_uintptr_t; +#endif + +class DBinderServiceStub : public IPCObjectStub { +public: + explicit DBinderServiceStub(const std::string& serviceName, const std::string& deviceID, + binder_uintptr_t binderObject); + ~DBinderServiceStub(); + int32_t ProcessProto(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + const std::string& GetServiceName(); + const std::string& GetDeviceID(); + binder_uintptr_t GetBinderObject() const; + +private: + const std::string serviceName_; + const std::string deviceID_; + binder_uintptr_t binderObject_; + int32_t ProcessDeathRecipient(MessageParcel &data, MessageParcel &reply); + int32_t AddDbinderDeathRecipient(MessageParcel &data, MessageParcel &reply); + int32_t RemoveDbinderDeathRecipient(MessageParcel &data, MessageParcel &reply); +}; +} // namespace OHOS +#endif // OHOS_IPC_SERVICES_DBINDER_DBINDER_STUB_H diff --git a/ipc/native/src/core/include/buffer_object.h b/ipc/native/src/core/include/buffer_object.h new file mode 100755 index 00000000..938fcb8c --- /dev/null +++ b/ipc/native/src/core/include/buffer_object.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_BUFFER_OBJECT_H +#define OHOS_IPC_BUFFER_OBJECT_H + +#include +#include +#include +#include +#include + +#include "nocopyable.h" + +namespace OHOS { +constexpr int SOCKET_DEFAULT_BUFF_SIZE = 4 * 1024; +constexpr int SOCKET_MAX_BUFF_SIZE = 1024 * 1024; +constexpr int SOCKET_BUFF_RESERVED_SIZE = 256; +constexpr size_t MAX_RAWDATA_SIZE = 128 * 1024 * 1024; // 128M + +constexpr uint32_t SOCKET_BUFF_SIZE_USER_S = 4 * 1024; +constexpr uint32_t SOCKET_BUFF_SIZE_USER_M = 16 * 1024; +constexpr uint32_t SOCKET_BUFF_SIZE_USER_L = 64 * 1024; +constexpr uint32_t SOCKET_BUFF_SIZE_USER_HUGE = 1024 * 1024; + +class BufferObject { +public: + explicit BufferObject(); + + ~BufferObject(); + + void UpdateReceiveBuffer(); + void UpdateSendBuffer(); + char *GetSendBufferAndLock(uint32_t size); + char *GetReceiveBufferAndLock(uint32_t size); + void ReleaseSendBufferLock(); + void ReleaseReceiveBufferLock(); + ssize_t GetReceiveBufferWriteCursor() const; + void SetReceiveBufferWriteCursor(ssize_t newWriteCursor); + ssize_t GetReceiveBufferReadCursor() const; + void SetReceiveBufferReadCursor(ssize_t newReadCursor); + ssize_t GetSendBufferWriteCursor() const; + void SetSendBufferWriteCursor(ssize_t newWriteCursor); + ssize_t GetSendBufferReadCursor() const; + void SetSendBufferReadCursor(ssize_t newReadCursor); + uint32_t GetNeedBufferSize(uint32_t size) const; + uint32_t GetSendBufferSize() const; + uint32_t GetRecvBufferSize() const; + +private: + DISALLOW_COPY_AND_MOVE(BufferObject); + ssize_t recvBufferCursorW_ = 0; + ssize_t recvBufferCursorR_ = 0; + ssize_t sendBufferCursorW_ = 0; + ssize_t sendBufferCursorR_ = 0; + char *receiveBuffer_ = nullptr; + char *sendBuffer_ = nullptr; + std::mutex sendMutex_; + std::mutex recvMutex_; + uint32_t sendBuffSize_ = 0; + uint32_t recvBuffSize_ = 0; +}; +} // namespace OHOS +#endif // OHOS_IPC_BUFFER_OBJECT_H diff --git a/ipc/native/src/core/include/comm_auth_info.h b/ipc/native/src/core/include/comm_auth_info.h new file mode 100755 index 00000000..0125d423 --- /dev/null +++ b/ipc/native/src/core/include/comm_auth_info.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_COMMAUTHINFO_H +#define OHOS_IPC_COMMAUTHINFO_H + +#include "iremote_object.h" +#include "ipc_object_stub.h" + +namespace OHOS { +class CommAuthInfo { +public: + CommAuthInfo(IRemoteObject *stub, int pid, int uid, const std::string &deviceId); + virtual ~CommAuthInfo(); + const IRemoteObject *GetStubObject() const; + int GetRemotePid() const; + int GetRemoteUid() const; + std::string GetRemoteDeviceId() const; + +private: + IRemoteObject *stub_; + int remotePid_; + int remoteUid_; + std::string deviceId_; +}; +} // namespace OHOS +#endif // OHOS_IPC_COMMAUTHINFO_H \ No newline at end of file diff --git a/ipc/native/src/core/include/databus_session_callback.h b/ipc/native/src/core/include/databus_session_callback.h new file mode 100755 index 00000000..d03f9138 --- /dev/null +++ b/ipc/native/src/core/include/databus_session_callback.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_DBINDER_DATABUS_SESSION_CALLBACK_H +#define OHOS_IPC_DBINDER_DATABUS_SESSION_CALLBACK_H + +#include "ISessionListener.h" + +using Communication::SoftBus::ISessionListener; +using Communication::SoftBus::Session; + +namespace OHOS { +static const std::string DBINDER_SERVER_PKG_NAME = "DBinderBus"; + +class DatabusSessionCallback : public ISessionListener { +public: + explicit DatabusSessionCallback() = default; + ~DatabusSessionCallback() = default; + + int OnSessionOpened(std::shared_ptr session) override; + void OnSessionClosed(std::shared_ptr session) override; + void OnMessageReceived(std::shared_ptr session, const char* data, ssize_t len) override {} + void OnBytesReceived(std::shared_ptr session, const char *data, ssize_t len) override; + bool OnDataAvailable(std::shared_ptr session, uint32_t status) override + { + return true; + }; +}; +} // namespace OHOS +#endif // OHOS_IPC_DBINDER_DATABUS_SESSION_CALLBACK_H diff --git a/ipc/native/src/core/include/dbinder_error_code.h b/ipc/native/src/core/include/dbinder_error_code.h new file mode 100755 index 00000000..acd35e4a --- /dev/null +++ b/ipc/native/src/core/include/dbinder_error_code.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_DBINDER_ERROR_CODE_H +#define OHOS_IPC_DBINDER_ERROR_CODE_H + +#include +#ifndef BUILD_PUBLIC_VERSION +#include "hiview.h" +#include "hievent.h" +#endif + +namespace OHOS { +class DbinderErrorCode { +public: + static const int SYSTEM_ENVIRONMENT_ERROR = 950000601; + static const int NETWORK_ERROR = 950000602; + static const int SKELETON_ERROR = 950000603; + static const int DBINDER_SERVICE_ERROR = 950000604; + static const int TRANSMISSION_ERROR = 950000605; + static const int COMMON_DRIVER_ERROR = 950000606; + static const int KERNEL_DRIVER_ERROR = 950000607; + static const int SOCKET_DRIVER_ERROR = 950000608; + + inline static const std::string ERROR_TYPE = "ErrType"; + inline static const std::string ERROR_CODE = "ErrCode"; + + // 601 + enum SystemEnvironmentError { + CREATE_EPOLL = 1, + BIND_EPOLL, + REMOVE_EPOLL, + }; + + // 602 + enum NetworkError { + WRONG_DEVICE_ID = 1, + WRONG_SUBSCRIPTION, + }; + + // 603 + enum SkeletonError { + WRONG_KERNEL_DRIVER = 1, + WRONG_SOCKET_DRIVER, + WRONG_TYPE_PROXY, + UPDATE_SESSION_FAILURE, + RELEASE_FD_FAILURE, + RELEASE_SESSION_FAILURE, + UNKNOWN_CMD, + }; + + // 604 + enum DbinderServiceError { + START_DBS_FAILURE = 1, + CLOSE_DBS_FAILURE, + WRONG_INPUT_PARAMETER, + LOCAL_OBJECT_SEND_MESSAGE_FAILURE, + RECEIVE_MESSAGE_FAILURE, + INVOKE_LISTENER_FAILURE, + ALLOCATE_INDEX_FAILURE, + REMOTE_OBJECT_SEND_MESSAGE_FAILURE, + INITIATE_DATABUS_FAILURE, + DATABUS_SEND_FAILURE, + DATABUS_RECEIVE_FAILURE, + CLOSE_DATABUS_FAILURE, + OPERATE_MESSAGE_FAILURE, + }; + + // 605 + enum TransmissionError { + RECEIVE_PKT_LOSS = 1, + SEND_PKT_LOSS, + HANDLE_OVERMUCH_THREADS, + OVERSIZE_PKT, + }; + + // 606 + enum CommonDriverType { + IPC_DRIVER = 1, + RPC_DRIVER, + }; + enum CommonDriverError { + TRANSACT_DATA_FAILURE = 1, + HANDLE_RECV_DATA_FAILURE, + SET_DEATH_RECIPIENT_FAILURE, + REMOVE_DEATH_RECIPIENT_FAILURE, + HANDLE_DEATH_RECIPIENT_FAILURE, + FLATTEN_OBJECT_FAILURE, + UNFLATTEN_OBJECT_FAILURE, + }; + + // 607 + enum KernelDriverError { + INITIATE_IPC_DRIVER_FAILURE = 1, + OPEN_IPC_DRIVER_FAILURE, + WRITE_IPC_DRIVER_FAILURE, + }; + + // 608 + enum SocketDriverError { + OPEN_RPC_DRIVER_FAILURE = 1, + CONNECT_RPC_REMOTE_FAILURE, + SEND_RPC_DATA_FAILURE, + RECEIVE_RPC_DATA_FAILURE, + INVOKE_RPC_THREAD_FAILURE, + }; +}; + +#ifndef BUILD_PUBLIC_VERSION +inline void ReportEvent(int code, const std::string &type, int num) +{ + if (code == 0 || type.empty() || num == 0) { + return; + } + HiEvent hiEvent(code); + hiEvent.PutInt(type, num); + HiView::Report(hiEvent); +} + +inline void ReportDriverEvent(int code, const std::string &type, int num, const std::string &errorType, int errorNum) +{ + if (code == 0 || type.empty() || num == 0 || errorType.empty() || errorNum == 0) { + return; + } + HiEvent hiEvent(code); + hiEvent.PutInt(type, num); + hiEvent.PutInt(errorType, errorNum); + HiView::Report(hiEvent); +} +#endif +} // namespace OHOS +#endif // OHOS_IPC_DBINDER_ERROR_CODE_H diff --git a/ipc/native/src/core/include/dbinder_session_object.h b/ipc/native/src/core/include/dbinder_session_object.h new file mode 100755 index 00000000..ff6c2d82 --- /dev/null +++ b/ipc/native/src/core/include/dbinder_session_object.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_DBINDER_SESSION_OBJECT_H +#define OHOS_IPC_DBINDER_SESSION_OBJECT_H + +#include +#include +#include "nocopyable.h" +#include "buffer_object.h" + +#include "Session.h" +#include "ISessionService.h" + +using Communication::SoftBus::ISessionService; +using Communication::SoftBus::Session; + +namespace OHOS { +constexpr int DEVICEID_LENGTH = 64; +constexpr int SERVICENAME_LENGTH = 200; + +/* struct FlatDBinderSession is for flat DatabusSessionObject to transfer to another device */ +struct FlatDBinderSession { + uint64_t stubIndex; + uint16_t deviceIdLength; + uint16_t serviceNameLength; + char deviceId[DEVICEID_LENGTH + 1]; + char serviceName[SERVICENAME_LENGTH + 1]; +}; + +class DBinderSessionObject { +public: + static uint32_t GetFlatSessionLen(); + explicit DBinderSessionObject(std::shared_ptr session, const std::string &serviceName, + const std::string &serverDeviceId); + + ~DBinderSessionObject(); + + void SetBusSession(std::shared_ptr session); + void SetServiceName(const std::string &serviceName); + void SetDeviceId(const std::string &serverDeviceId); + std::shared_ptr GetSessionBuff(); + std::shared_ptr GetBusSession() const; + std::string GetServiceName() const; + std::string GetDeviceId() const; + uint32_t GetSessionHandle() const; + +private: + DISALLOW_COPY_AND_MOVE(DBinderSessionObject); + /* Session is defined from softBus session, when import socket driver, we need use interface abstraction */ + std::shared_ptr session_; + std::mutex buffMutex_; + std::shared_ptr buff_; + std::string serviceName_; + std::string serverDeviceId_; +}; +} // namespace OHOS +#endif // OHOS_IPC_DBINDER_SESSION_OBJECT_H \ No newline at end of file diff --git a/ipc/native/src/core/include/ipc_debug.h b/ipc/native/src/core/include/ipc_debug.h new file mode 100755 index 00000000..9fb93b36 --- /dev/null +++ b/ipc/native/src/core/include/ipc_debug.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IPC_DEBUG_H +#define OHOS_IPC_IPC_DEBUG_H + +#include +#include +#include "hilog/log.h" +#include "string_ex.h" + +namespace OHOS { +// if need enable ipc debug log, use '#define CONFIG_IPC_DEBUG' +#define ZLOGW(TAG, ...) (void)HiviewDFX::HiLog::Warn(TAG, __VA_ARGS__) +#define ZLOGE(TAG, ...) (void)HiviewDFX::HiLog::Error(TAG, __VA_ARGS__) + +#if (defined CONFIG_IPC_DEBUG) +#define ZLOGI(TAG, ...) (void)HiviewDFX::HiLog::Info(TAG, __VA_ARGS__) +#else +#define ZLOGI(TAG, ...) +#endif /* CONFIG_IPC_DEBUG */ + +using ErrorMap = std::map; +class ErrorBase { +public: + virtual ~ErrorBase() = default; + inline const std::string &GetErrorDesc(uint32_t error); + virtual ErrorMap &GetErrorMap() = 0; +}; + +inline const std::string &ErrorBase::GetErrorDesc(uint32_t error) +{ + static const std::string unknowCommand = "UNKNOWN COMMAND"; + ErrorMap::iterator found = GetErrorMap().find(error); + if (found == GetErrorMap().end()) { + return unknowCommand; + } else { + return found->second; + } +} + +class IPCError : public ErrorBase { +public: + IPCError() = default; + ~IPCError() = default; + static const std::string &ToString(int value); + virtual ErrorMap &GetErrorMap() override; +}; +} // namespace OHOS +#endif // OHOS_IPC_IPC_DEBUG_H diff --git a/ipc/native/src/core/include/ipc_process_skeleton.h b/ipc/native/src/core/include/ipc_process_skeleton.h new file mode 100755 index 00000000..f362f28d --- /dev/null +++ b/ipc/native/src/core/include/ipc_process_skeleton.h @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IPC_PROCESS_SKELETON_H +#define OHOS_IPC_IPC_PROCESS_SKELETON_H + +#include +#include +#include +#include "refbase.h" +#include "iremote_object.h" +#include "ipc_thread_pool.h" +#include "nocopyable.h" +#include "ipc_object_proxy.h" +#include "ipc_object_stub.h" +#include "invoker_rawdata.h" +#include "sys_binder.h" + +#ifndef CONFIG_IPC_SINGLE +#include "dbinder_session_object.h" +#include "Session.h" +#include "ISessionService.h" +#include "stub_refcount_object.h" +#include "comm_auth_info.h" + +using Communication::SoftBus::ISessionService; +using Communication::SoftBus::Session; +#endif + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +#ifndef CONFIG_IPC_SINGLE +struct SocketThreadLockInfo { + std::mutex mutex; + std::condition_variable condition; + bool ready = false; +}; + +struct ThreadMessageInfo { + std::thread::id threadId; + uint32_t flags; + binder_size_t bufferSize; + binder_size_t offsetsSize; + binder_uintptr_t offsets; + uint32_t socketId; + void *buffer; +}; + +struct ThreadProcessInfo { + uint32_t listenFd; + uint32_t packageSize; + std::shared_ptr buffer; +}; +#endif + +class IPCProcessSkeleton : public virtual RefBase { +public: + enum { + LISTEN_THREAD_CREATE_OK, // Invoker family. + LISTEN_THREAD_CREATE_FAILED, + LISTEN_THREAD_CREATED_ALREADY, + LISTEN_THREAD_CREATED_TIMEOUT + }; + ~IPCProcessSkeleton() override; + + static IPCProcessSkeleton *GetCurrent(); + +#ifndef CONFIG_IPC_SINGLE + static uint32_t ConvertChannelID2Int(int64_t databusChannelId); +#endif + bool SetMaxWorkThread(int maxThreadNum); + + sptr GetRegistryObject(); + + bool SpawnThread(int policy = IPCWorkThread::SPAWN_PASSIVE, int proto = IRemoteObject::IF_PROT_DEFAULT); + + std::u16string MakeHandleDescriptor(int handle); + + IRemoteObject *FindOrNewObject(int handle); + bool IsContainsObject(IRemoteObject *object); + IRemoteObject *QueryObject(const std::u16string &descriptor); + IRemoteObject *QueryObjectInner(const std::u16string &descriptor); + bool AttachObject(IRemoteObject *object); + bool AttachObjectInner(IRemoteObject *object); + bool DetachObject(IRemoteObject *object); + + bool OnThreadTerminated(const std::string &threadName); + + bool SetRegistryObject(sptr &object); + bool AttachRawData(uint32_t fd, std::shared_ptr rawData); + bool DetachRawData(uint32_t fd); + std::shared_ptr QueryRawData(uint32_t fd); + +#ifndef CONFIG_IPC_SINGLE + sptr GetSAMgrObject(); + bool ProxyDetachDBinderSession(uint32_t handle); + bool ProxyAttachDBinderSession(uint32_t handle, std::shared_ptr object); + std::shared_ptr ProxyQueryDBinderSession(uint32_t handle); + bool QueryProxyBySessionHandle(uint32_t handle, std::vector &proxyHandle); + std::shared_ptr QuerySessionByInfo(const std::string &name, const std::string &deviceId); + + bool DetachThreadLockInfo(const std::thread::id &threadId); + bool AttachThreadLockInfo(std::shared_ptr object, const std::thread::id &threadId); + std::shared_ptr QueryThreadLockInfo(const std::thread::id &threadId); + void EraseThreadBySeqNumber(uint64_t seqNumber); + bool AddThreadBySeqNumber(uint64_t seqNumber, std::shared_ptr messageInfo); + std::shared_ptr QueryThreadBySeqNumber(uint64_t seqNumber); + bool AddSendThreadInWait(uint64_t seqNumber, std::shared_ptr messageInfo, int userWaitTime); + + std::thread::id GetIdleSocketThread(); + int GetSocketIdleThreadNum() const; + int GetSocketTotalThreadNum() const; + int PopSocketIdFromThread(const std::thread::id &threadId); + void WakeUpSocketIOThread(const std::thread::id &threadID); + void WakeUpThreadBySeqNumber(uint64_t seqNumber, uint32_t handle); + IRemoteObject *QueryStubByIndex(uint64_t stubIndex); + uint64_t AddStubByIndex(IRemoteObject *stubObject); + uint64_t GetSeqNumber(); + uint32_t GetDBinderIdleHandle(uint64_t stubIndex); + std::shared_ptr GetListenThreadLockInfo(); + std::string GetLocalDeviceID(); + + bool AttachCallbackStub(IPCObjectProxy *ipcProxy, sptr callbackStub); + bool DetachCallbackStub(IPCObjectStub *callbackStub); + sptr QueryCallbackStub(IPCObjectProxy *ipcProxy); + IPCObjectProxy *QueryCallbackProxy(IPCObjectStub *callbackStub); + bool DetachCallbackStubByProxy(IPCObjectProxy *ipcProxy); + uint32_t QueryHandleByDatabusSession(const std::string &name, const std::string &deviceId, uint64_t stubIndex); + bool StubDetachDBinderSession(uint32_t handle); + std::shared_ptr StubQueryDBinderSession(uint32_t handle); + bool StubAttachDBinderSession(uint32_t handle, std::shared_ptr object); + std::string GetDatabusName(); + bool CreateSoftbusServer(const std::string &name); + bool DetachHandleToIndex(uint32_t handle); + bool AttachHandleToIndex(uint32_t handle, uint64_t stubIndex); + uint64_t QueryHandleToIndex(uint32_t handle); + uint64_t QueryHandleToIndex(std::list &handleList, uint32_t &handle); + bool AttachStubRecvRefInfo(IRemoteObject *stub, int pid, const std::string &deviceId); + void DetachStubRecvRefInfo(int pid, const std::string &deviceId); + bool DetachStubRecvRefInfo(const IRemoteObject *stub, int pid, const std::string &deviceId); + void DetachStubRecvRefInfo(const IRemoteObject *stub); + std::list QueryStubRecvRefInfo(int pid, const std::string &deviceId); + void DetachStubRefInfo(const int pid, const std::string &deviceId); + void DetachStubRefInfo(IRemoteObject *stub, int pid, const std::string &deviceId); + bool AttachStubSendRefInfo(IRemoteObject *stub, int pid, const std::string &deviceId); + void DetachStubSendRefInfo(int pid, const std::string &deviceId); + void DetachStubSendRefInfo(IRemoteObject *stub, int pid, const std::string &deviceId); + void DetachStubSendRefInfo(IRemoteObject *stub); + bool IncStubRefTimes(IRemoteObject *stub); + bool DecStubRefTimes(IRemoteObject *stub); + bool DetachStubRefTimes(IRemoteObject *stub); + + bool AttachCommAuthInfo(IRemoteObject *stub, int pid, int uid, const std::string &deviceId); + void DetachCommAuthInfo(IRemoteObject *stub, int pid, int uid, const std::string &deviceId); + void DetachCommAuthInfoByStub(IRemoteObject *stub); + bool QueryIsAuth(int pid, int uid, const std::string &deviceId); + bool AddDataThreadToIdle(const std::thread::id &threadId); + bool DeleteDataThreadFromIdle(const std::thread::id &threadId); + std::thread::id GetIdleDataThread(); + void AddDataInfoToThread(const std::thread::id &threadId, std::shared_ptr processInfo); + std::shared_ptr PopDataInfoFromThread(const std::thread::id &threadId); + void WakeUpDataThread(const std::thread::id &threadID); + void AddDataThreadInWait(const std::thread::id &threadId); + bool IsSameRemoteObject(IRemoteObject *stub, int pid, int uid, const std::string &deviceId, + const std::shared_ptr &auth); + bool IsSameRemoteObject(int pid, int uid, const std::string &deviceId, const std::shared_ptr &auth); + uint64_t EraseStubIndex(IRemoteObject *stubObject); + bool DetachAppInfoToStubIndex(uint32_t pid, uint32_t uid, const std::string &deviceId, uint64_t stubIndex); + void DetachAppInfoToStubIndex(uint64_t stubIndex); + bool AttachAppInfoToStubIndex(uint32_t pid, uint32_t uid, const std::string &deviceId, uint64_t stubIndex); + bool QueryAppInfoToStubIndex(uint32_t pid, uint32_t uid, const std::string &deviceId, uint64_t stubIndex); +#endif + +public: + static constexpr int DEFAULT_WORK_THREAD_NUM = 16; + static constexpr uint32_t DBINDER_HANDLE_BASE = 100000; + static constexpr uint32_t DBINDER_HANDLE_RANG = 100; +#ifndef CONFIG_IPC_SINGLE + std::shared_ptr listenThreadReady_ = nullptr; + static constexpr int TRANS_TIME_INIT_VALUE = 1; + static constexpr int SEC_TO_MS = 1000; +#endif +private: + DISALLOW_COPY_AND_MOVE(IPCProcessSkeleton); + IPCProcessSkeleton(); + static IPCProcessSkeleton *instance_; + static std::mutex procMutex_; + std::shared_mutex mutex_; + std::shared_mutex rawDataMutex_; + std::map> objects_; + std::map isContainStub_; + std::map> rawData_; + IPCWorkThreadPool *threadPool_ = nullptr; + sptr registryObject_ = nullptr; + +#ifndef CONFIG_IPC_SINGLE + std::mutex databusProcMutex_; + std::mutex sessionNameMutex_; + std::mutex seqNumberMutex_; + std::mutex transTimesMutex_; + std::mutex stubSendRefMutex_; + std::mutex idleDataMutex_; + std::mutex dataQueueMutex_; + std::mutex findThreadMutex_; + + std::recursive_mutex proxyToSessionMutex_; + + std::shared_mutex databusSessionMutex_; + std::shared_mutex handleToIndexMutex_; + std::shared_mutex threadLockMutex_; + std::shared_mutex callbackStubMutex_; + std::shared_mutex stubObjectsMutex_; + std::shared_mutex stubRecvRefMutex_; + std::shared_mutex appInfoToIndexMutex_; + std::shared_mutex commAuthMutex_; + + std::map> seqNumberToThread_; + std::map stubObjects_; + std::map> threadLockInfo_; + std::map> proxyToSession_; + std::map> dbinderSessionObjects_; + std::map handleToStubIndex_; + std::map> noticeStub_; + std::map transTimes_; + std::map>> dataInfoQueue_; // key is threadId + std::map> appInfoToStubIndex_; + + std::list idleDataThreads_; + std::list> stubRecvRefs_; + std::list> stubSendRefs_; + std::list> commAuth_; + + uint32_t dBinderHandle_ = DBINDER_HANDLE_BASE; /* dbinder handle start at 100000 */ + uint64_t seqNumber_ = 0; + std::string sessionName_ = std::string(""); + uint64_t randNum_; +#endif +}; +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS +#endif // OHOS_IPC_IPC_PROCESS_SKELETON_H diff --git a/ipc/native/src/core/include/ipc_thread_pool.h b/ipc/native/src/core/include/ipc_thread_pool.h new file mode 100755 index 00000000..5323c419 --- /dev/null +++ b/ipc/native/src/core/include/ipc_thread_pool.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IPC_WORK_THREAD_POOL_H +#define OHOS_IPC_IPC_WORK_THREAD_POOL_H + +#include +#include +#include +#include +#include +#include +#include "hilog/log.h" +#include "log_tags.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +class IPCWorkThreadPool { +public: + IPCWorkThreadPool(const IPCWorkThreadPool &) = delete; + + IPCWorkThreadPool(IPCWorkThreadPool &&) = delete; + + ~IPCWorkThreadPool(); + + IPCWorkThreadPool &operator = (const IPCWorkThreadPool &) = delete; + + IPCWorkThreadPool &operator = (IPCWorkThreadPool &&) = delete; + + bool SpawnThread(int policy = IPCWorkThread::SPAWN_PASSIVE, int proto = IRemoteObject::IF_PROT_DEFAULT); + + bool RemoveThread(const std::string &threadName); + + void StopAllThreads(); + + explicit IPCWorkThreadPool(int maxThreadNum); + + int GetMaxThreadNum() const; + + void UpdateMaxThreadNum(int maxThreadNum); + int GetSocketIdleThreadNum() const; + int GetSocketTotalThreadNum() const; + +private: + static constexpr int PROTO_NUM = 2; + std::string MakeThreadName(int proto); + std::map> threads_; + std::atomic threadSequence_; + int maxThreadNum_; + int idleThreadNum_; + int idleSocketThreadNum_; + std::mutex mutex_; + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCWorkThreadPool" }; +}; +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS +#endif // OHOS_IPC_IPC_WORK_THREAD_POOL_H diff --git a/ipc/native/src/core/include/ipc_thread_skeleton.h b/ipc/native/src/core/include/ipc_thread_skeleton.h new file mode 100755 index 00000000..95e76f9d --- /dev/null +++ b/ipc/native/src/core/include/ipc_thread_skeleton.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IPC_THREAD_SKELETON_H +#define OHOS_IPC_IPC_THREAD_SKELETON_H + +#include +#include +#include +#include "iremote_invoker.h" +#include "binder_invoker.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +class IPCThreadSkeleton { +public: + IPCThreadSkeleton(); + + ~IPCThreadSkeleton(); + + static void TlsDestructor(void *args); + static void MakeTlsKey(); + + static IPCThreadSkeleton *GetCurrent(); + + static IRemoteInvoker *GetRemoteInvoker(int proto); + + static IRemoteInvoker *GetDefaultInvoker(); + + static IRemoteInvoker *GetActiveInvoker(); + + static IRemoteInvoker *GetProxyInvoker(IRemoteObject *object); + + // Joint Current thread into IPC Work Group + void JoinWorkThread(int proto); + // Quit current thread from IPC work group. + void StopWorkThread(int proto); + +private: + static pthread_key_t TLSKey_; + static pthread_once_t TLSKeyOnce_; + std::unordered_map invokers_; +}; +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS +#endif // OHOS_IPC_IPC_THREAD_SKELETON_H diff --git a/ipc/native/src/core/include/ipc_workthread.h b/ipc/native/src/core/include/ipc_workthread.h new file mode 100755 index 00000000..70377030 --- /dev/null +++ b/ipc/native/src/core/include/ipc_workthread.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IPC_WORK_THREAD_H +#define OHOS_IPC_IPC_WORK_THREAD_H + +#include +#include +#include "refbase.h" +#include "hilog/log.h" +#include "iremote_invoker.h" +#include "log_tags.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +class IPCWorkThread : public virtual RefBase { +public: + enum { + SPAWN_PASSIVE, + SPAWN_ACTIVE, + PROCESS_PASSIVE, + PROCESS_ACTIVE + }; + explicit IPCWorkThread(std::string threadName); + + ~IPCWorkThread(); + + void ThreadHandler(); + + void Start(int policy, int proto, std::string threadName); + + void StopWorkThread(); + int proto_ = IRemoteObject::IF_PROT_DEFAULT; + +private: + int policy_ = SPAWN_PASSIVE; + std::thread thread_; + const std::string threadName_; + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCWorkThread" }; +}; +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS +#endif // OHOS_IPC_IPC_WORK_THREAD_H diff --git a/ipc/native/src/core/include/stub_refcount_object.h b/ipc/native/src/core/include/stub_refcount_object.h new file mode 100755 index 00000000..8c0c4e63 --- /dev/null +++ b/ipc/native/src/core/include/stub_refcount_object.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_STUB_REFCOUNT_OBJECT_H +#define OHOS_IPC_STUB_REFCOUNT_OBJECT_H + +#include "iremote_object.h" + +namespace OHOS { +class StubRefCountObject { +public: + StubRefCountObject(IRemoteObject *stub, int remotePid, const std::string &deviceId); + virtual ~StubRefCountObject(); + IRemoteObject *GetStubObject() const; + int GetRemotePid() const; + std::string GetDeviceId() const; + +private: + IRemoteObject *stub_; + int remotePid_; + std::string deviceId_; +}; +} // namespace OHOS +#endif // OHOS_IPC_STUB_REFCOUNT_OBJECT_H diff --git a/ipc/native/src/core/source/buffer_object.cpp b/ipc/native/src/core/source/buffer_object.cpp new file mode 100755 index 00000000..92121e69 --- /dev/null +++ b/ipc/native/src/core/source/buffer_object.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "buffer_object.h" +#include "securec.h" +#include "sys_binder.h" + +namespace OHOS { +BufferObject::BufferObject() +{ +} + +BufferObject::~BufferObject() +{ + if (receiveBuffer_ != nullptr) { + delete[] receiveBuffer_; + receiveBuffer_ = nullptr; + } + if (sendBuffer_ != nullptr) { + delete[] sendBuffer_; + sendBuffer_ = nullptr; + } +} + +/* update buffer need get mutex first */ +void BufferObject::UpdateSendBuffer() +{ + if (sendBufferCursorW_ <= sendBufferCursorR_) { + sendBufferCursorW_ = 0; + sendBufferCursorR_ = 0; + return; + } + /* check whether buffer size is enough, if not, move write/read cursor to head */ + if (sendBuffSize_ - sendBufferCursorW_ < SOCKET_BUFF_RESERVED_SIZE) { + /* writeCursor always bigger than readCursor */ + if (sendBufferCursorW_ - sendBufferCursorR_ < sendBufferCursorR_) { + auto memcpyResult = memmove_s(sendBuffer_, sendBufferCursorW_ - sendBufferCursorR_, + sendBuffer_ + sendBufferCursorR_, sendBufferCursorW_ - sendBufferCursorR_); + if (memcpyResult != EOK) { + sendBufferCursorW_ = 0; // drop data in buffer, if memmove failed + } else { + sendBufferCursorW_ = sendBufferCursorW_ - sendBufferCursorR_; + } + sendBufferCursorR_ = 0; + } + } +} + +/* update buffer need get mutex first */ +void BufferObject::UpdateReceiveBuffer() +{ + if (recvBufferCursorW_ <= recvBufferCursorR_) { + recvBufferCursorR_ = 0; + recvBufferCursorW_ = 0; + return; + } + /* check whether buffer size is enough, if not, move write/read cursor to head */ + if (recvBuffSize_ - recvBufferCursorW_ < SOCKET_BUFF_RESERVED_SIZE) { + /* writeCursor always bigger than readCursor */ + if (recvBufferCursorW_ - recvBufferCursorR_ < recvBufferCursorR_) { + auto memcpyResult = memmove_s(receiveBuffer_, recvBufferCursorW_ - recvBufferCursorR_, + receiveBuffer_ + recvBufferCursorR_, recvBufferCursorW_ - recvBufferCursorR_); + if (memcpyResult != EOK) { + recvBufferCursorW_ = 0; // drop data in buffer, if memmove failed + } else { + recvBufferCursorW_ = recvBufferCursorW_ - recvBufferCursorR_; + } + recvBufferCursorR_ = 0; + } + } +} + +char *BufferObject::GetSendBufferAndLock(uint32_t size) +{ + uint32_t needSize = GetNeedBufferSize(size); + if (needSize == 0) { + return nullptr; + } + sendMutex_.lock(); + if (needSize > sendBuffSize_) { + char *newBuffer_ = new (std::nothrow) char[needSize]; + if (newBuffer_ == nullptr) { + sendMutex_.unlock(); + return nullptr; + } + + if ((sendBuffer_ != nullptr) && (sendBuffSize_ != 0)) { + int memcpyResult = memcpy_s(newBuffer_, needSize, sendBuffer_, sendBuffSize_); + if (memcpyResult != 0) { + delete[] newBuffer_; + sendMutex_.unlock(); + return nullptr; + } + } + + delete[] sendBuffer_; + sendBuffer_ = newBuffer_; + sendBuffSize_ = needSize; + } + + /* attention: need unlock mutex by caller */ + return sendBuffer_; +} + +char *BufferObject::GetReceiveBufferAndLock(uint32_t size) +{ + uint32_t needSize = GetNeedBufferSize(size); + if (needSize == 0) { + return nullptr; + } + recvMutex_.lock(); + if (needSize > recvBuffSize_) { + char *newBuffer_ = new (std::nothrow) char[needSize]; + if (newBuffer_ == nullptr) { + recvMutex_.unlock(); + return nullptr; + } + + if ((receiveBuffer_ != nullptr) && (recvBuffSize_ != 0)) { + int memcpyResult = memcpy_s(newBuffer_, needSize, receiveBuffer_, recvBuffSize_); + if (memcpyResult != 0) { + delete[] newBuffer_; + recvMutex_.unlock(); + return nullptr; + } + } + + delete[] receiveBuffer_; + receiveBuffer_ = newBuffer_; + recvBuffSize_ = needSize; + } + + /* attention: need unlock mutex by caller */ + return receiveBuffer_; +} + +void BufferObject::ReleaseSendBufferLock() +{ + sendMutex_.unlock(); +} + +void BufferObject::ReleaseReceiveBufferLock() +{ + recvMutex_.unlock(); +} + +ssize_t BufferObject::GetReceiveBufferWriteCursor() const +{ + return recvBufferCursorW_; +} + +void BufferObject::SetReceiveBufferWriteCursor(ssize_t newWriteCursor) +{ + recvBufferCursorW_ = newWriteCursor; +} + +ssize_t BufferObject::GetReceiveBufferReadCursor() const +{ + return recvBufferCursorR_; +} + +void BufferObject::SetReceiveBufferReadCursor(ssize_t newReadCursor) +{ + recvBufferCursorR_ = newReadCursor; +} + +ssize_t BufferObject::GetSendBufferWriteCursor() const +{ + return sendBufferCursorW_; +} + +void BufferObject::SetSendBufferWriteCursor(ssize_t newWriteCursor) +{ + sendBufferCursorW_ = newWriteCursor; +} + +ssize_t BufferObject::GetSendBufferReadCursor() const +{ + return sendBufferCursorR_; +} + +void BufferObject::SetSendBufferReadCursor(ssize_t newReadCursor) +{ + sendBufferCursorR_ = newReadCursor; +} + +uint32_t BufferObject::GetNeedBufferSize(uint32_t size) const +{ + if (size <= SOCKET_BUFF_SIZE_USER_S) { + return SOCKET_BUFF_SIZE_USER_S; + } else if (size <= SOCKET_BUFF_SIZE_USER_M) { + return SOCKET_BUFF_SIZE_USER_M; + } else if (size <= SOCKET_BUFF_SIZE_USER_L) { + return SOCKET_BUFF_SIZE_USER_L; + } else if (size <= SOCKET_BUFF_SIZE_USER_HUGE) { + return SOCKET_BUFF_SIZE_USER_HUGE; + } else { + return 0; + } +} + +uint32_t BufferObject::GetSendBufferSize() const +{ + return sendBuffSize_; +} + +uint32_t BufferObject::GetRecvBufferSize() const +{ + return recvBuffSize_; +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/comm_auth_info.cpp b/ipc/native/src/core/source/comm_auth_info.cpp new file mode 100755 index 00000000..41eae672 --- /dev/null +++ b/ipc/native/src/core/source/comm_auth_info.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "comm_auth_info.h" + +namespace OHOS { +CommAuthInfo::CommAuthInfo(IRemoteObject *stub, int pid, int uid, const std::string &deviceId) + : stub_(stub), remotePid_(pid), remoteUid_(uid), deviceId_(deviceId) +{} + +CommAuthInfo::~CommAuthInfo() +{ + stub_ = nullptr; +} +const IRemoteObject *CommAuthInfo::GetStubObject() const +{ + return stub_; +} +int CommAuthInfo::GetRemotePid() const +{ + return remotePid_; +} +int CommAuthInfo::GetRemoteUid() const +{ + return remoteUid_; +} +std::string CommAuthInfo::GetRemoteDeviceId() const +{ + return deviceId_; +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/databus_session_callback.cpp b/ipc/native/src/core/source/databus_session_callback.cpp new file mode 100755 index 00000000..7d3e1a1f --- /dev/null +++ b/ipc/native/src/core/source/databus_session_callback.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "databus_session_callback.h" + +#include "ipc_thread_skeleton.h" +#include "ipc_process_skeleton.h" +#include "dbinder_databus_invoker.h" +#include "ipc_debug.h" +#include "log_tags.h" + +namespace OHOS { +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "DatabusSessionCallback" }; +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +int DatabusSessionCallback::OnSessionOpened(std::shared_ptr session) +{ + if (session->GetChannelId() < 0) { + DBINDER_LOGE("fail to open session because of wrong channel ID"); + return SESSION_WRONG_FD_ERR; + } + + if (!session->IsServerSide()) { + DBINDER_LOGI("active end"); + return 0; + } + + DBINDER_LOGI("passive end"); + DBinderDatabusInvoker *invoker = + reinterpret_cast(IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DATABUS)); + if (invoker == nullptr) { + DBINDER_LOGE("fail to get invoker"); + return SESSION_INVOKER_NULL_ERR; + } + + return invoker->OnReceiveNewConnection(session) ? 0 : SESSION_UNOPEN_ERR; +} + +void DatabusSessionCallback::OnSessionClosed(std::shared_ptr session) +{ + DBinderDatabusInvoker *invoker = + reinterpret_cast(IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DATABUS)); + if (invoker == nullptr) { + DBINDER_LOGE("fail to get invoker"); + return; + } + + invoker->OnDatabusSessionClosed(session); +} + +void DatabusSessionCallback::OnBytesReceived(std::shared_ptr session, const char *data, ssize_t len) +{ + DBinderDatabusInvoker *invoker = + reinterpret_cast(IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DATABUS)); + if (invoker == nullptr) { + DBINDER_LOGE("fail to get invoker"); + return; + } + + invoker->OnMessageAvailable(session, data, len); +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/dbinder_session_object.cpp b/ipc/native/src/core/source/dbinder_session_object.cpp new file mode 100755 index 00000000..8eaf190b --- /dev/null +++ b/ipc/native/src/core/source/dbinder_session_object.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_session_object.h" + +#include "ipc_process_skeleton.h" +#include "ISessionService.h" + +namespace OHOS { +DBinderSessionObject::DBinderSessionObject(std::shared_ptr session, const std::string &serviceName, + const std::string &serverDeviceId) + : session_(session), serviceName_(serviceName), serverDeviceId_(serverDeviceId) +{} + +DBinderSessionObject::~DBinderSessionObject() +{ + if (session_ != nullptr) { + std::shared_ptr manager = ISessionService::GetInstance(); + if (manager != nullptr) { + (void)manager->CloseSession(session_); + } + } + + session_ = nullptr; + buff_ = nullptr; +} + +void DBinderSessionObject::SetBusSession(std::shared_ptr session) +{ + session_ = session; +} + +std::shared_ptr DBinderSessionObject::GetBusSession() const +{ + return session_; +} + +std::shared_ptr DBinderSessionObject::GetSessionBuff() +{ + if (buff_ == nullptr) { + std::lock_guard lockGuard(buffMutex_); + if (buff_ == nullptr) { + std::shared_ptr temp = std::make_shared(); + buff_ = temp; + } + } + + return buff_; +} + +void DBinderSessionObject::SetServiceName(const std::string &serviceName) +{ + serviceName_ = serviceName; +} + +std::string DBinderSessionObject::GetServiceName() const +{ + return serviceName_; +} + +void DBinderSessionObject::SetDeviceId(const std::string &serverDeviceId) +{ + serverDeviceId_ = serverDeviceId; +} + +std::string DBinderSessionObject::GetDeviceId() const +{ + return serverDeviceId_; +} + +uint32_t DBinderSessionObject::GetFlatSessionLen() +{ + return sizeof(struct FlatDBinderSession); +} + +uint32_t DBinderSessionObject::GetSessionHandle() const +{ + if (session_ != nullptr) { + return IPCProcessSkeleton::ConvertChannelID2Int(session_->GetChannelId()); + } + return 0; +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/ipc_file_descriptor.cpp b/ipc/native/src/core/source/ipc_file_descriptor.cpp new file mode 100755 index 00000000..e4c1cccc --- /dev/null +++ b/ipc/native/src/core/source/ipc_file_descriptor.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_file_descriptor.h" + +#include "ipc_debug.h" +#include "ipc_thread_skeleton.h" +#include "log_tags.h" + +namespace OHOS { +using namespace OHOS::HiviewDFX; +#ifdef CONFIG_IPC_SINGLE +using namespace IPC_SINGLE; +#endif +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCFileDescriptor" }; + +IPCFileDescriptor::IPCFileDescriptor() : Parcelable(true), fd_(INVALID_FD) {} + +IPCFileDescriptor::IPCFileDescriptor(int fd) : Parcelable(true) +{ + fd_ = fd; +} + +IPCFileDescriptor::~IPCFileDescriptor() +{ + fd_ = INVALID_FD; +} + +int IPCFileDescriptor::GetFd() const +{ + return fd_; +} + +void IPCFileDescriptor::SetFd(int fd) +{ + fd_ = fd; +} + +bool IPCFileDescriptor::Marshalling(Parcel &parcel) const +{ + if (fd_ < 0) { + ZLOGE(LABEL, "%s:IPCFileDescriptor: fd %d is invalid", __func__, fd_); + return false; + } + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + if (invoker != nullptr) { + return invoker->WriteFileDescriptor(parcel, fd_, false); + } + + return false; +} + +bool IPCFileDescriptor::Marshalling(Parcel &parcel, const sptr &object) +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + + if (invoker != nullptr) { + return invoker->WriteFileDescriptor(parcel, object->GetFd(), false); + } + + return false; +} + +IPCFileDescriptor *IPCFileDescriptor::Unmarshalling(Parcel &parcel) +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + int fd = -1; + + if (invoker != nullptr) { + fd = invoker->ReadFileDescriptor(parcel); + } + + if (fd < 0) { + return nullptr; + } + + return new IPCFileDescriptor(fd); +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/ipc_object_proxy.cpp b/ipc/native/src/core/source/ipc_object_proxy.cpp new file mode 100755 index 00000000..1d524abd --- /dev/null +++ b/ipc/native/src/core/source/ipc_object_proxy.cpp @@ -0,0 +1,660 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_object_proxy.h" + +#include "dbinder_error_code.h" +#include "ipc_types.h" +#include "ipc_debug.h" +#include "ipc_thread_skeleton.h" +#include "ipc_process_skeleton.h" +#include "log_tags.h" +#include "securec.h" + +#ifndef CONFIG_IPC_SINGLE +#include "dbinder_databus_invoker.h" +#endif + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +using namespace IPC_SINGLE; +#endif + +static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCObjectProxy" }; +IPCObjectProxy::IPCObjectProxy(int handle, std::u16string descriptor, int proto) + : IRemoteObject(std::move(descriptor)), handle_(handle), proto_(proto), isFinishInit_(false), isRemoteDead_(false) +{} + +IPCObjectProxy::~IPCObjectProxy() +{ + ZLOGW(LABEL, "handle = %{public}u destroyed", handle_); +} + +int32_t IPCObjectProxy::GetObjectRefCount() +{ + MessageParcel dummy, reply; + MessageOption option; + option.SetFlags(MessageOption::TF_SYNC); + if (SendRequestInner(false, SYNCHRONIZE_REFERENCE, dummy, reply, option) == ERR_NONE) { + return reply.ReadInt32(); + } + return 0; +} + +int IPCObjectProxy::Dump(int fd, const std::vector &args) +{ + MessageParcel data, reply; + MessageOption option { MessageOption::TF_SYNC }; + data.WriteFileDescriptor(fd); + data.WriteString16Vector(args); + return SendRequestInner(false, DUMP_TRANSACTION, data, reply, option); +} + +int IPCObjectProxy::SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + if (code != DUMP_TRANSACTION && code > MAX_TRANSACTION_ID) { + return IPC_PROXY_INVALID_CODE_ERR; + } + + return SendRequestInner(false, code, data, reply, option); +} + +int IPCObjectProxy::SendLocalRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + return SendRequestInner(true, code, data, reply, option); +} + +int IPCObjectProxy::SendRequestInner(bool isLocal, uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + if (IsObjectDead()) { + return ERR_DEAD_OBJECT; + } + + IRemoteInvoker *invoker = nullptr; + if (isLocal) { + invoker = IPCThreadSkeleton::GetDefaultInvoker(); + } else { + invoker = IPCThreadSkeleton::GetRemoteInvoker(proto_); + } + if (invoker == nullptr) { + ZLOGE(LABEL, "%s: null invoker, type = %d", __func__, proto_); + return ERR_NULL_OBJECT; + } + + int status = invoker->SendRequest(handle_, code, data, reply, option); + if (status == ERR_DEAD_OBJECT) { + MarkObjectDied(); + } + return status; +} + +std::u16string IPCObjectProxy::GetInterfaceDescriptor() +{ + std::lock_guard lockGuard(initMutex_); + if (!remoteDescriptor_.empty()) { + return remoteDescriptor_; + } + if (handle_ == 0) { + ZLOGI(LABEL, "handle == 0, do nothing"); + return std::u16string(); + } + + MessageParcel data, reply; + MessageOption option; + + uint32_t err = SendRequestInner(false, INTERFACE_TRANSACTION, data, reply, option); + if (err != ERR_NONE) { + ZLOGE(LABEL, "INTERFACE_TRANSACTION transact return error = %{public}u", err); + return std::u16string(); + } + remoteDescriptor_ = reply.ReadString16(); + + return remoteDescriptor_; +} + +std::string IPCObjectProxy::GetPidAndUidInfo() +{ + MessageParcel data, reply; + MessageOption option; + + uint32_t err = SendRequestInner(false, GET_UIDPID_INFO, data, reply, option); + if (err != ERR_NONE) { + ZLOGE(LABEL, "GetPidAndUidInfo SendRequestInner return error = %{public}u", err); + return std::string(""); + } + return reply.ReadString(); +} + +std::string IPCObjectProxy::GetDataBusName() +{ + MessageParcel data, reply; + MessageOption option; + + uint32_t err = SendRequestInner(false, GRANT_DATABUS_NAME, data, reply, option); + if (err != ERR_NONE) { + ZLOGE(LABEL, "GetDataBusName transact return error = %{public}u", err); + return std::string(""); + } + + if (reply.ReadUint32() != IRemoteObject::IF_PROT_DATABUS) { + ZLOGE(LABEL, "GetDataBusName normal binder"); + return std::string(""); + } + + return reply.ReadString(); +} + +void IPCObjectProxy::OnFirstStrongRef(const void *objectId) +{ + return WaitForInit(); +} + +void IPCObjectProxy::WaitForInit() +{ +#ifndef CONFIG_IPC_SINGLE + int type = 0; +#endif + + { + bool acquire = true; + std::lock_guard lockGuard(initMutex_); + if (IsObjectDead()) { + ZLOGI(LABEL, "check a dead proxy, init again"); + isRemoteDead_ = false; + isFinishInit_ = false; + acquire = false; + } + + // check again is this object been initialized + if (isFinishInit_) { + return; + } + IRemoteInvoker *invoker = IPCThreadSkeleton::GetDefaultInvoker(); + if (invoker != nullptr && acquire == true) { + invoker->AcquireHandle(handle_); + } +#ifndef CONFIG_IPC_SINGLE + type = UpdateProto(); +#endif + isFinishInit_ = true; + } +#ifndef CONFIG_IPC_SINGLE + if (type == IRemoteObject::IF_PROT_DATABUS) { + IncRefToRemote(); + } +#endif +} + +void IPCObjectProxy::OnLastStrongRef(const void *objectId) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "OnLastStrongRef current is null"); + return; + } + + if (current->DetachObject(this)) { + IRemoteInvoker *invoker = IPCThreadSkeleton::GetDefaultInvoker(); + if (invoker != nullptr) { + invoker->ReleaseHandle(handle_); + } + } +#ifndef CONFIG_IPC_SINGLE + ReleaseProto(); +#endif +} + + +/* mutex_ should be called before set or get isRemoteDead_ status */ +void IPCObjectProxy::MarkObjectDied() +{ + isRemoteDead_ = true; +} + +bool IPCObjectProxy::IsObjectDead() const +{ + return isRemoteDead_; +} + +bool IPCObjectProxy::AddDeathRecipient(const sptr &recipient) +{ + std::lock_guard lock(mutex_); + if (IsObjectDead()) { + ZLOGI(LABEL, "%s: proxy is already dead", __func__); + return false; + } + + bool registerRecipient = false; + if (recipients_.empty()) { + registerRecipient = true; + } + recipients_.push_back(recipient); + + if (!registerRecipient || handle_ >= IPCProcessSkeleton::DBINDER_HANDLE_BASE) { + ZLOGI(LABEL, "%s: death recipient is already registered", __func__); + return true; + } + + IRemoteInvoker *invoker = IPCThreadSkeleton::GetDefaultInvoker(); + if (invoker == nullptr) { + ZLOGE(LABEL, "%s : invoker is null", __func__); + return false; + } + + /* 1. Subscribe to death notifications, whether the stub comes from kernel or remote; + * 2. Subscribe to additional death notifications, if remote object. + * If step 1 is failed, do not execute step 2 and return false directly. + * If step 1 is successful but step 2 is failed, return false. + */ + bool status = invoker->AddDeathRecipient(handle_, this); + if (!status) { + ZLOGE(LABEL, "%s: fail to add binder death recipient, status = %d", __func__, status); +#ifndef BUILD_PUBLIC_VERSION + ReportDriverEvent(DbinderErrorCode::COMMON_DRIVER_ERROR, DbinderErrorCode::ERROR_TYPE, + DbinderErrorCode::IPC_DRIVER, DbinderErrorCode::ERROR_CODE, DbinderErrorCode::SET_DEATH_RECIPIENT_FAILURE); +#endif + return status; + } +#ifndef CONFIG_IPC_SINGLE + if (proto_ == IRemoteObject::IF_PROT_DATABUS) { + status = AddDbinderDeathRecipient(); + ZLOGE(LABEL, "%s: fail to add dbinder death recipient, status = %d", __func__, status); +#ifndef BUILD_PUBLIC_VERSION + if (!status) { + ReportDriverEvent(DbinderErrorCode::COMMON_DRIVER_ERROR, DbinderErrorCode::ERROR_TYPE, + DbinderErrorCode::RPC_DRIVER, DbinderErrorCode::ERROR_CODE, + DbinderErrorCode::SET_DEATH_RECIPIENT_FAILURE); + } +#endif + } +#endif + return status; +} + +bool IPCObjectProxy::RemoveDeathRecipient(const sptr &recipient) +{ + std::lock_guard lock(mutex_); + + bool removeRecipient = false; + + if (!IsObjectDead()) { + auto it = find(recipients_.begin(), recipients_.end(), recipient); + if (it != recipients_.end()) { + recipients_.erase(it); + removeRecipient = true; + } + + if (!recipients_.empty()) { + removeRecipient = false; + } + } + + if ((handle_ >= IPCProcessSkeleton::DBINDER_HANDLE_BASE) && (removeRecipient == true)) { + ZLOGI(LABEL, "%s: death recipient is already unregistered", __func__); + return true; + } + + if (removeRecipient) { + IRemoteInvoker *invoker = IPCThreadSkeleton::GetDefaultInvoker(); + if (invoker == nullptr) { + ZLOGE(LABEL, "%s : invoker is null", __func__); + return false; + } + + bool dbinderStatus = true; + bool binderStatus = invoker->RemoveDeathRecipient(handle_, this); +#ifndef CONFIG_IPC_SINGLE + if (proto_ == IRemoteObject::IF_PROT_DATABUS) { + dbinderStatus = RemoveDbinderDeathRecipient(); + } +#endif + if (binderStatus && dbinderStatus) { + return true; + } + } + + return false; +} + +void IPCObjectProxy::SendObituary() +{ + { + std::lock_guard lock(mutex_); + MarkObjectDied(); + int recipientCount = recipients_.size(); + for (int i = 0; i < recipientCount; i++) { + sptr recipient = recipients_[i]; + ZLOGW(LABEL, "%s: handle = %{public}u call OnRemoteDied", __func__, handle_); + recipient->OnRemoteDied(this); + } + recipients_.clear(); + + if (recipientCount > 0) { + IRemoteInvoker *invoker = IPCThreadSkeleton::GetDefaultInvoker(); + if (invoker != nullptr) { + invoker->RemoveDeathRecipient(handle_, this); + } + } + } +#ifndef CONFIG_IPC_SINGLE + if (proto_ == IRemoteObject::IF_PROT_DATABUS) { + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "%s: get current fail", __func__); + return; + } + + current->DetachCallbackStubByProxy(this); + } +#endif +} + +int IPCObjectProxy::GetProto() const +{ + return proto_; +} + +int32_t IPCObjectProxy::NoticeServiceDie() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + data.WriteInt32(IRemoteObject::DeathRecipient::NOTICE_DEATH_RECIPIENT); + + int status = SendLocalRequest(DBINDER_OBITUARY_TRANSACTION, data, reply, option); + if (status != ERR_NONE || reply.ReadInt32() != ERR_NONE) { + ZLOGE(LABEL, "%s: send local request fail, status = %d", __func__, status); + return IPC_PROXY_TRANSACTION_ERR; + } + + return ERR_NONE; +} + +int IPCObjectProxy::InvokeListenThread(MessageParcel &data, MessageParcel &reply) +{ + MessageOption option; + return SendRequestInner(false, INVOKE_LISTEN_THREAD, data, reply, option); +} + +#ifndef CONFIG_IPC_SINGLE +int IPCObjectProxy::UpdateProto() +{ + int type = GetSessionFromDBinderService(); + SetProto(type); + return type; +} + +void IPCObjectProxy::IncRefToRemote() +{ + MessageParcel data, reply; + MessageOption option; + + int32_t err = SendRequestInner(false, DBINDER_INCREFS_TRANSACTION, data, reply, option); + if (err != ERR_NONE) { + ZLOGE(LABEL, "DBINDER_INCREFS_TRANSACTION transact return error = %{public}d", err); + // do nothing + } +} + + +void IPCObjectProxy::ReleaseProto() +{ + switch (GetProto()) { + case IRemoteObject::IF_PROT_BINDER: { + ZLOGW(LABEL, "it is normal binder, try to delete handle to index"); + ReleaseBinderProto(); + break; + } + case IRemoteObject::IF_PROT_DATABUS: { + ReleaseDatabusProto(); + break; + } + default: { + ZLOGE(LABEL, "ReleaseProto Invalid Type"); + break; + } + } + + return; +} + +void IPCObjectProxy::SetProto(int proto) +{ + proto_ = proto; +} + +int IPCObjectProxy::GetSessionFromDBinderService() +{ + MessageParcel data, reply; + MessageOption option; + uint32_t type = IRemoteObject::IF_PROT_BINDER; + + if (CheckHaveSession(type)) { + ZLOGE(LABEL, "GetSessionFromDBinderService type = %u", type); + return type; + } + + uint32_t err = SendRequestInner(true, GET_PROTO_INFO, data, reply, option); + if (err != ERR_NONE) { + ZLOGI(LABEL, "GET_PROTO_INFO transact return error = %{public}u", err); + return IRemoteObject::IF_PROT_BINDER; + } + + switch (reply.ReadUint32()) { + case IRemoteObject::IF_PROT_BINDER: { + ZLOGW(LABEL, "it is normal binder, not dbinder"); + break; + } + case IRemoteObject::IF_PROT_DATABUS: { + if (UpdateDatabusClientSession(handle_, reply)) { + ZLOGW(LABEL, "it is dbinder, not binder"); + return IRemoteObject::IF_PROT_DATABUS; + } + break; + } + default: { + ZLOGE(LABEL, "GetSessionFromDBinderService Invalid Type"); + break; + } + } + + return IRemoteObject::IF_PROT_BINDER; +} + +bool IPCObjectProxy::AddDbinderDeathRecipient() +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "%s: get current fail", __func__); + return false; + } + + if (current->QueryCallbackStub(this) != nullptr) { + ZLOGW(LABEL, "%s: already attach callback stub", __func__); + return true; + } + + sptr callbackStub = new IPCObjectStub(descriptor_); + if (!current->AttachCallbackStub(this, callbackStub)) { + ZLOGW(LABEL, "%s: already attach new callback stub", __func__); + return false; + } + + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + data.WriteInt32(IRemoteObject::DeathRecipient::ADD_DEATH_RECIPIENT); + data.WriteRemoteObject(callbackStub); + + int err = SendLocalRequest(DBINDER_OBITUARY_TRANSACTION, data, reply, option); + if (err != ERR_NONE || reply.ReadInt32() != ERR_NONE) { + ZLOGE(LABEL, "%s: send local request fail, err = %d", __func__, err); + (void)current->DetachCallbackStubByProxy(this); + return false; + } + + return true; +} + +bool IPCObjectProxy::RemoveDbinderDeathRecipient() +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "%s: get current fail", __func__); + return false; + } + + sptr callbackStub = current->QueryCallbackStub(this); + if (callbackStub == nullptr) { + ZLOGE(LABEL, "%s: get callbackStub fail", __func__); + return false; + } + + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + data.WriteInt32(IRemoteObject::DeathRecipient::REMOVE_DEATH_RECIPIENT); + data.WriteRemoteObject(callbackStub); + + int err = SendLocalRequest(DBINDER_OBITUARY_TRANSACTION, data, reply, option); + if (err != ERR_NONE || reply.ReadInt32() != ERR_NONE) { + ZLOGE(LABEL, "%s: send local request fail, err = %d", __func__, err); + // do nothing, even send request failed + } + + return current->DetachCallbackStubByProxy(this); +} + +bool IPCObjectProxy::CheckHaveSession(uint32_t &type) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "IPCProcessSkeleton is null, set type as binder"); + return false; + } + + std::shared_ptr session = current->ProxyQueryDBinderSession(handle_); + if (session == nullptr) { + ZLOGW(LABEL, "no databus session attach to this handle, maybe need update"); + return false; + } + type = IRemoteObject::IF_PROT_DATABUS; + return true; +} + +bool IPCObjectProxy::UpdateDatabusClientSession(int handle, MessageParcel &reply) +{ + DBinderDatabusInvoker *invoker = + reinterpret_cast(IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DATABUS)); + if (invoker == nullptr) { + ZLOGE(LABEL, "%s: invoker null", __func__); + return false; + } + + uint64_t stubIndex = reply.ReadUint64(); + std::string serviceName = reply.ReadString(); + std::string peerID = reply.ReadString(); + std::string localID = reply.ReadString(); + std::string localBusName = reply.ReadString(); + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "%s:current process skeleton is nullptr", __func__); + return false; + } + + std::shared_ptr connectSession = current->QuerySessionByInfo(serviceName, peerID); + if (connectSession == nullptr) { + connectSession = std::make_shared(nullptr, serviceName, peerID); + if (connectSession == nullptr) { + ZLOGE(LABEL, "new server session fail!"); + return false; + } + } + + if (!current->AttachHandleToIndex(handle, stubIndex)) { + ZLOGE(LABEL, "add stub index err stubIndex = %" PRIu64 ", handle = %d", stubIndex, handle); + return false; + } + + if (!current->CreateSoftbusServer(localBusName)) { + ZLOGE(LABEL, "create bus server fail name = %s, localID = %s", localBusName.c_str(), localID.c_str()); + return false; + } + + bool result = invoker->UpdateClientSession(handle, connectSession); + if (!result) { + ZLOGE(LABEL, "update server session object fail!"); + return false; + } + + return true; +} + +void IPCObjectProxy::ReleaseDatabusProto() +{ + if (handle_ == 0) { + ZLOGI(LABEL, "%s:handle == 0, do nothing", __func__); + return; + } + + if (GetProto() != IRemoteObject::IF_PROT_DATABUS) { + ZLOGI(LABEL, "not databus dbinder, need do nothing"); + return; + } + + MessageParcel data, reply; + MessageOption option = { MessageOption::TF_ASYNC }; + uint32_t err = SendRequestInner(false, DBINDER_DECREFS_TRANSACTION, data, reply, option); + if (err != ERR_NONE) { + ZLOGE(LABEL, "DBINDER_DECREFS_TRANSACTION transact return error = %{public}u", err); + // do nothing + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "release proto current is null"); + return; + } + + (void)current->ProxyDetachDBinderSession(handle_); + (void)current->DetachHandleToIndex(handle_); + return; +} + +void IPCObjectProxy::ReleaseBinderProto() +{ + if (handle_ == 0) { + ZLOGI(LABEL, "%s:handle == 0, do nothing", __func__); + return; + } + + if (GetProto() != IRemoteObject::IF_PROT_BINDER) { + ZLOGI(LABEL, "not binder proxy, need do nothing"); + return; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "release proto current is null"); + return; + } + + (void)current->DetachHandleToIndex(handle_); + return; +} +#endif +} // namespace OHOS diff --git a/ipc/native/src/core/source/ipc_object_stub.cpp b/ipc/native/src/core/source/ipc_object_stub.cpp new file mode 100755 index 00000000..70c5a388 --- /dev/null +++ b/ipc/native/src/core/source/ipc_object_stub.cpp @@ -0,0 +1,495 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_object_stub.h" +#include +#include "ipc_types.h" +#include "ipc_debug.h" +#include "ipc_process_skeleton.h" +#include "ipc_thread_skeleton.h" +#include "log_tags.h" +#include "ipc_skeleton.h" + +#ifndef CONFIG_IPC_SINGLE +#include "dbinder_databus_invoker.h" +#include "dbinder_error_code.h" +#include "ISessionService.h" +#endif + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +using namespace IPC_SINGLE; +#endif + +using namespace OHOS::HiviewDFX; +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCObjectStub" }; +#ifndef CONFIG_IPC_SINGLE +// Authentication information can be added only for processes with system permission. +static constexpr pid_t ALLOWED_UID = 10000; +// Only the samgr can obtain the UID and PID. +static constexpr pid_t SYSTEM_SERVER_UID = 1000; +#endif +static constexpr pid_t SHELL_UID = 2000; + +IPCObjectStub::IPCObjectStub(std::u16string descriptor) : IRemoteObject(descriptor) {} + +IPCObjectStub::~IPCObjectStub() +{ + ZLOGW(LABEL, "IPCObjectStub destroyed"); +} + +bool IPCObjectStub::IsDeviceIdIllegal(const std::string &deviceID) +{ + if (deviceID.empty() || deviceID.length() > DEVICEID_LENGTH) { + return true; + } + return false; +} + +int32_t IPCObjectStub::GetObjectRefCount() +{ + int kRefCount = 0; + int refCount = GetSptrRefCount(); + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + + if (invoker != nullptr) { + kRefCount = invoker->GetObjectRefCount(this); + } + + /* the kernel has already acquire the reference + * on this object, so we need to decrement by 1. + */ + if (kRefCount > 0) { + refCount += kRefCount - 1; + } + + return refCount; +} + +int IPCObjectStub::Dump(int fd, const std::vector &args) +{ + const size_t numArgs = args.size(); + ZLOGE(LABEL, "Invalid call on Stub:fd:%d, args:%zu", fd, numArgs); + return ERR_NONE; +} + +int IPCObjectStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int result = ERR_NONE; + switch (code) { +#ifndef CONFIG_IPC_SINGLE + case DBINDER_OBITUARY_TRANSACTION: { + if (IPCSkeleton::GetCallingUid() != SYSTEM_SERVER_UID) { + ZLOGE(LABEL, "%s: DBINDER_OBITUARY_TRANSACTION unauthenticated user ", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + if (data.ReadInt32() == IRemoteObject::DeathRecipient::NOTICE_DEATH_RECIPIENT) { + result = NoticeServiceDie(data, reply, option); + } else { + result = IPC_STUB_INVALID_DATA_ERR; + } + break; + } +#endif + default: + result = IPC_STUB_UNKNOW_TRANS_ERR; + ZLOGI(LABEL, "unknown OnRemoteRequest code = %{public}u", code); + break; + } + + return result; +} + +int IPCObjectStub::OnRemoteDump(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int result = ERR_NONE; + int fd = data.ReadFileDescriptor(); + std::vector args; + if (fd != INVALID_FD) { + if (data.ReadString16Vector(&args)) { + result = Dump(fd, args); + } + ::close(fd); + } else { + result = IPC_STUB_INVALID_DATA_ERR; + } + return result; +} + +int IPCObjectStub::SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int result = ERR_NONE; + switch (code) { + case PING_TRANSACTION: { + if (!reply.WriteInt32(ERR_NONE)) { + result = IPC_STUB_WRITE_PARCEL_ERR; + } + break; + } + case INTERFACE_TRANSACTION: { + std::u16string descriptor = GetObjectDescriptor(); + if (!reply.WriteString16(descriptor)) { + ZLOGE(LABEL, "write to parcel fail"); + result = IPC_STUB_WRITE_PARCEL_ERR; + } + break; + } + case SYNCHRONIZE_REFERENCE: { + int refCount = GetObjectRefCount(); + // when handle transaction the invoker would try to acquire + // the object's reference to defense the object being released + // so the actual we should decrement the temporary reference. + --refCount; + reply.WriteInt32(refCount); + break; + } + case DUMP_TRANSACTION: { + pid_t uid = IPCSkeleton::GetCallingUid(); + if (!IPCSkeleton::IsLocalCalling() || (uid != 0 && uid != SHELL_UID)) { + ZLOGE(LABEL, "do not allow dump"); + break; + } + result = OnRemoteDump(code, data, reply, option); + break; + } +#ifndef CONFIG_IPC_SINGLE + case INVOKE_LISTEN_THREAD: { + if (!IPCSkeleton::IsLocalCalling() || IPCSkeleton::GetCallingUid() >= ALLOWED_UID) { + ZLOGE(LABEL, "%s: INVOKE_LISTEN_THREAD unauthenticated user ", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = InvokerThread(code, data, reply, option); + break; + } + case GET_PROTO_INFO: { + result = ProcessProto(code, data, reply, option); + break; + } + case DBINDER_INCREFS_TRANSACTION: { + if (IPCSkeleton::IsLocalCalling()) { + ZLOGE(LABEL, "%s: cannot be called in same device", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = IncStubRefs(data, reply); + break; + } + case DBINDER_DECREFS_TRANSACTION: { + if (IPCSkeleton::IsLocalCalling()) { + ZLOGE(LABEL, "%s: cannot be called in same device", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = DecStubRefs(data, reply); + break; + } + case DBINDER_ADD_COMMAUTH: { + if (IPCSkeleton::IsLocalCalling() || IPCSkeleton::GetCallingUid() >= ALLOWED_UID) { + ZLOGE(LABEL, "%s: DBINDER_ADD_COMMAUTH unauthenticated user ", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = AddAuthInfo(data, reply); + break; + } + case GET_UIDPID_INFO: { + if (!IPCSkeleton::IsLocalCalling()) { + ZLOGE(LABEL, "GET_UIDPID_INFO message is not from sa manager"); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + std::string sessionName = GetDataBusName(); + if (sessionName.empty()) { + ZLOGE(LABEL, "sessionName is empty"); + result = IPC_STUB_CREATE_BUS_SERVER_ERR; + break; + } + if (!reply.WriteString(sessionName)) { + ZLOGE(LABEL, "write to parcel fail"); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + break; + } + case GRANT_DATABUS_NAME: { + if (!IPCSkeleton::IsLocalCalling() || getuid() != SYSTEM_SERVER_UID) { + ZLOGE(LABEL, "GRANT_DATABUS_NAME message is excluded in sa manager"); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = GrantDataBusName(code, data, reply, option); + break; + } +#endif + default: + result = OnRemoteRequest(code, data, reply, option); + break; + } + + return result; +} + +void IPCObjectStub::OnFirstStrongRef(const void *objectId) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + + if (current != nullptr) { + current->AttachObject(this); + } +} + +void IPCObjectStub::OnLastStrongRef(const void *objectId) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + + if (current != nullptr) { + current->DetachObject(this); +#ifndef CONFIG_IPC_SINGLE + current->DetachStubRecvRefInfo(this); + current->DetachStubSendRefInfo(this); + (void)current->DetachStubRefTimes(this); + current->DetachCommAuthInfoByStub(this); + uint64_t stubIndex = current->EraseStubIndex(reinterpret_cast(this)); + current->DetachAppInfoToStubIndex(stubIndex); +#endif + } +} + +bool IPCObjectStub::AddDeathRecipient(const sptr &recipient) +{ + return false; +} + +bool IPCObjectStub::RemoveDeathRecipient(const sptr &recipient) +{ + return false; +} + +pid_t IPCObjectStub::GetCallingPid() +{ + return IPCSkeleton::GetCallingPid(); +} + +pid_t IPCObjectStub::GetCallingUid() +{ + return IPCSkeleton::GetCallingUid(); +} + +int32_t IPCObjectStub::ProcessProto(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int result = ERR_NONE; + ZLOGE(LABEL, "IPCObjectStub::ProcessProto called, type = 0, normal stub object"); + if (!reply.WriteUint32(IRemoteObject::IF_PROT_BINDER)) { + ZLOGE(LABEL, "write to parcel fail"); + result = IPC_STUB_WRITE_PARCEL_ERR; + } + return result; +} + +#ifndef CONFIG_IPC_SINGLE +int32_t IPCObjectStub::InvokerThread(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + switch (data.ReadUint32()) { + case IRemoteObject::DATABUS_TYPE: { + if (InvokerDataBusThread(data, reply) != ERR_NONE) { + ZLOGE(LABEL, "Invoker databus thread fail"); + return IPC_STUB_INVOKE_THREAD_ERR; + } + break; + } + default: { + ZLOGE(LABEL, "InvokerThread Invalid Type"); + return IPC_STUB_INVALID_DATA_ERR; + } + } + + return ERR_NONE; +} + +int32_t IPCObjectStub::InvokerDataBusThread(MessageParcel &data, MessageParcel &reply) +{ + std::string deviceId = data.ReadString(); + uint32_t remotePid = data.ReadUint32(); + uint32_t remoteUid = data.ReadUint32(); + std::string remoteDeviceId = data.ReadString(); + std::string sessionName = data.ReadString(); + if (IsDeviceIdIllegal(deviceId) || IsDeviceIdIllegal(remoteDeviceId) || sessionName.empty()) { + ZLOGE(LABEL, "%s: device ID is invalid or session name nil", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "IPCProcessSkeleton is nullptr"); + return IPC_STUB_CURRENT_NULL_ERR; + } + if (!current->CreateSoftbusServer(sessionName)) { + ZLOGE(LABEL, "%s: fail to create databus server", __func__); + return IPC_STUB_CREATE_BUS_SERVER_ERR; + } + + uint64_t stubIndex = current->AddStubByIndex(this); + if (stubIndex == 0) { + ZLOGE(LABEL, "%s: add stub fail", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + if (!reply.WriteUint64(stubIndex) || !reply.WriteString(sessionName) || !reply.WriteString(deviceId)) { + ZLOGE(LABEL, "%s: write to parcel fail", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + if (!current->AttachAppInfoToStubIndex(remotePid, remoteUid, remoteDeviceId, stubIndex)) { + ZLOGE(LABEL, "fail to attach appinfo to stubIndex, maybe attach already"); + } + if (!current->AttachCommAuthInfo(this, remotePid, remoteUid, remoteDeviceId)) { + ZLOGE(LABEL, "fail to attach comm auth info"); + } + + return ERR_NONE; +} + +int32_t IPCObjectStub::NoticeServiceDie(MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "%s: current is null", __func__); + return IPC_STUB_CURRENT_NULL_ERR; + } + + IPCObjectProxy *ipcProxy = current->QueryCallbackProxy(this); + if (ipcProxy == nullptr) { + ZLOGE(LABEL, "%s: ipc proxy is null", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + + ipcProxy->SendObituary(); + + if (!current->DetachCallbackStub(this)) { + ZLOGE(LABEL, "%s: fail to detach callback stub", __func__); + // do nothing, RemoveDeathRecipient can delete this too + } + + return ERR_NONE; +} + +int32_t IPCObjectStub::IncStubRefs(MessageParcel &data, MessageParcel &reply) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "%s: current is null", __func__); + return IPC_STUB_CURRENT_NULL_ERR; + } + + std::string deviceId = IPCSkeleton::GetCallingDeviceID(); + if (deviceId.empty()) { + ZLOGE(LABEL, "%s: calling error", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + if (!current->AttachStubRecvRefInfo(this, IPCSkeleton::GetCallingPid(), deviceId)) { + ZLOGE(LABEL, "%s: attach stub ref info err, already in", __func__); + return ERR_NONE; + } + + if (!current->DecStubRefTimes(this)) { + this->IncStrongRef(this); + } + + return ERR_NONE; +} + +int32_t IPCObjectStub::DecStubRefs(MessageParcel &data, MessageParcel &reply) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "%s: current is null", __func__); + return IPC_STUB_CURRENT_NULL_ERR; + } + + std::string deviceId = IPCSkeleton::GetCallingDeviceID(); + current->DetachStubRefInfo(this, IPCSkeleton::GetCallingPid(), deviceId); + return ERR_NONE; +} + +int32_t IPCObjectStub::AddAuthInfo(MessageParcel &data, MessageParcel &reply) +{ + uint32_t remotePid = data.ReadUint32(); + uint32_t remoteUid = data.ReadUint32(); + std::string remoteDeviceId = data.ReadString(); + if (IsDeviceIdIllegal(remoteDeviceId)) { + ZLOGE(LABEL, "%s: remote deviceId is null", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + ZLOGE(LABEL, "%s: current is null", __func__); + return IPC_STUB_CURRENT_NULL_ERR; + } + + if (!current->AttachCommAuthInfo(this, remotePid, remoteUid, remoteDeviceId)) { + ZLOGE(LABEL, "fail to attach comm auth info fail"); + return IPC_STUB_INVALID_DATA_ERR; + } + return ERR_NONE; +} + +std::string IPCObjectStub::GetDataBusName() +{ + sptr object = IPCProcessSkeleton::GetCurrent()->GetSAMgrObject(); + if (object == nullptr) { + ZLOGE(LABEL, "get object is null"); + return std::string(""); + } + + IPCObjectProxy *samgr = reinterpret_cast(object.GetRefPtr()); + return samgr->GetDataBusName(); +} + +int32_t IPCObjectStub::GrantDataBusName(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int pid = IPCSkeleton::GetCallingPid(); + int uid = IPCSkeleton::GetCallingUid(); + std::string sessionName = CreateDatabusName(uid, pid); + if (sessionName.empty()) { + ZLOGE(LABEL, "pid/uid is invalid, pid = {public}%d, uid = {public}%d", pid, uid); + return IPC_STUB_INVALID_DATA_ERR; + } + if (!reply.WriteUint32(IRemoteObject::IF_PROT_DATABUS) || !reply.WriteString(sessionName)) { + ZLOGE(LABEL, "write to parcel fail"); + return IPC_STUB_INVALID_DATA_ERR; + } + + return ERR_NONE; +} + +std::string IPCObjectStub::CreateDatabusName(int uid, int pid) +{ + std::shared_ptr softbusManager = ISessionService::GetInstance(); + if (softbusManager == nullptr) { + ZLOGE(LABEL, "fail to get softbus service"); + return ""; + } + + std::string sessionName = "DBinder" + std::to_string(uid) + std::string("_") + std::to_string(pid); + if (softbusManager->GrantPermission(uid, pid, sessionName) != ERR_NONE) { + ZLOGE(LABEL, "fail to Grant Permission softbus name"); + return ""; + } + + return sessionName; +} +#endif +} // namespace OHOS diff --git a/ipc/native/src/core/source/ipc_process_skeleton.cpp b/ipc/native/src/core/source/ipc_process_skeleton.cpp new file mode 100755 index 00000000..ef9a066f --- /dev/null +++ b/ipc/native/src/core/source/ipc_process_skeleton.cpp @@ -0,0 +1,1229 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_process_skeleton.h" + +#include +#include +#include +#include "string_ex.h" +#include "ipc_debug.h" +#include "ipc_types.h" + +#include "ipc_thread_skeleton.h" +#include "sys_binder.h" +#include "log_tags.h" + +#ifndef CONFIG_IPC_SINGLE +#include "databus_session_callback.h" +#include "softbus_bus_center.h" +#endif + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +#ifndef CONFIG_IPC_SINGLE +using namespace Communication; +#endif +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC, "IPCProcessSkeleton" }; +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +std::mutex IPCProcessSkeleton::procMutex_; +IPCProcessSkeleton *IPCProcessSkeleton::instance_ = nullptr; + +IPCProcessSkeleton *IPCProcessSkeleton::GetCurrent() +{ + if (instance_ == nullptr) { + std::lock_guard lockGuard(procMutex_); + if (instance_ == nullptr) { + IPCProcessSkeleton *temp = new IPCProcessSkeleton(); + if (temp->SetMaxWorkThread(DEFAULT_WORK_THREAD_NUM)) { + temp->SpawnThread(IPCWorkThread::SPAWN_ACTIVE); + } + instance_ = temp; + } + } + + return instance_; +} + +IPCProcessSkeleton::IPCProcessSkeleton() +{ +#ifndef CONFIG_IPC_SINGLE + std::random_device randDevice; + std::default_random_engine baseRand { randDevice() }; + std::uniform_int_distribution<> range(1, DBINDER_HANDLE_BASE * DBINDER_HANDLE_RANG); + uint32_t temp = range(baseRand); + randNum_ = static_cast(temp); +#endif +} + +IPCProcessSkeleton::~IPCProcessSkeleton() +{ + std::lock_guard lockGuard(procMutex_); + delete threadPool_; + threadPool_ = nullptr; + + objects_.clear(); + isContainStub_.clear(); + rawData_.clear(); +#ifndef CONFIG_IPC_SINGLE + listenThreadReady_.reset(); + threadLockInfo_.clear(); + seqNumberToThread_.clear(); + stubObjects_.clear(); + proxyToSession_.clear(); + dbinderSessionObjects_.clear(); + noticeStub_.clear(); + transTimes_.clear(); + + std::shared_ptr manager = ISessionService::GetInstance(); + if (manager != nullptr) { + (void)manager->RemoveSessionServer(DBINDER_SERVER_PKG_NAME, sessionName_); + } +#endif +} + +sptr IPCProcessSkeleton::GetRegistryObject() +{ + if (registryObject_ == nullptr) { + registryObject_ = FindOrNewObject(REGISTRY_HANDLE); + } + + return registryObject_; +} + +std::u16string IPCProcessSkeleton::MakeHandleDescriptor(int handle) +{ + std::string descriptor = "IPCObjectProxy" + std::to_string(handle); + return to_utf16(descriptor); +} + +IRemoteObject *IPCProcessSkeleton::FindOrNewObject(int handle) +{ + IRemoteObject *remoteObject = nullptr; + std::u16string descriptor = MakeHandleDescriptor(handle); + { + std::unique_lock lockGuard(mutex_); + + remoteObject = QueryObjectInner(descriptor); + if (remoteObject == nullptr) { + if (handle == REGISTRY_HANDLE) { + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + if (invoker == nullptr) { + DBINDER_LOGE("fail to get invoker"); + return nullptr; + } + if (!invoker->PingService(REGISTRY_HANDLE)) { + DBINDER_LOGE("Registry is not exist"); + return nullptr; + } + } + + remoteObject = new IPCObjectProxy(handle, descriptor); + remoteObject->AttemptAcquire(this); + + if (!AttachObjectInner(remoteObject)) { + DBINDER_LOGE("attach object fail"); + delete remoteObject; + return nullptr; + } + return remoteObject; + } + } + + IPCObjectProxy *remoteProxy = reinterpret_cast(remoteObject); + remoteProxy->WaitForInit(); + return remoteObject; +} + +bool IPCProcessSkeleton::SetMaxWorkThread(int maxThreadNum) +{ + if (maxThreadNum <= 0) { + DBINDER_LOGE("Set Invalid thread Number %d", maxThreadNum); + return false; + } + + if (threadPool_ == nullptr) { + threadPool_ = new IPCWorkThreadPool(maxThreadNum); + } + + threadPool_->UpdateMaxThreadNum(maxThreadNum); + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + if (invoker != nullptr) { + return invoker->SetMaxWorkThread(maxThreadNum); + } + + return false; +} + +bool IPCProcessSkeleton::SetRegistryObject(sptr &object) +{ + if (object == nullptr) { + DBINDER_LOGE("object is null"); + return false; + } + + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + if (invoker == nullptr) { + DBINDER_LOGE("fail to get invoker"); + return false; + } + + bool ret = invoker->SetRegistryObject(object); + if (ret) { + registryObject_ = object; + } + + return ret; +} + +bool IPCProcessSkeleton::SpawnThread(int policy, int proto) +{ + if (threadPool_ != nullptr) { + return threadPool_->SpawnThread(policy, proto); + } + + /* can NOT reach here */ + return false; +} + +bool IPCProcessSkeleton::OnThreadTerminated(const std::string &threadName) +{ + if (threadPool_ != nullptr) { + return threadPool_->RemoveThread(threadName); + } + + return true; +} + +bool IPCProcessSkeleton::IsContainsObject(IRemoteObject *object) +{ + /* don't care mutex result even object is deleted */ + auto it = isContainStub_.find(object); + if (it != isContainStub_.end()) { + return it->second; + } + + return false; +} + +bool IPCProcessSkeleton::DetachObject(IRemoteObject *object) +{ + std::unique_lock lockGuard(mutex_); + // If it fails, clear it in the destructor. + (void)isContainStub_.erase(object); + + std::u16string descriptor = object->GetObjectDescriptor(); + if (descriptor.empty()) { + return false; + } + + return (objects_.erase(descriptor) > 0); +} + +bool IPCProcessSkeleton::AttachObject(IRemoteObject *object) +{ + std::unique_lock lockGuard(mutex_); + return AttachObjectInner(object); +} + +bool IPCProcessSkeleton::AttachObjectInner(IRemoteObject *object) +{ + // If it fails, it means it was added before. + (void)isContainStub_.insert(std::pair(object, true)); + std::u16string descriptor = object->GetObjectDescriptor(); + if (descriptor.empty()) { + return false; + } + + auto result = objects_.insert(std::pair>(descriptor, object)); + return result.second; +} + +IRemoteObject *IPCProcessSkeleton::QueryObject(const std::u16string &descriptor) +{ + if (descriptor.empty()) { + return nullptr; + } + + std::shared_lock lockGuard(mutex_); + return QueryObjectInner(descriptor); +} + +IRemoteObject *IPCProcessSkeleton::QueryObjectInner(const std::u16string &descriptor) +{ + auto it = objects_.find(descriptor); + if (it != objects_.end()) { + if (it->second == nullptr) { + return nullptr; + } + it->second->AttemptAcquire(this); + return it->second.GetRefPtr(); + } + + return nullptr; +} + +#ifndef CONFIG_IPC_SINGLE +sptr IPCProcessSkeleton::GetSAMgrObject() +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetDefaultInvoker(); + if (invoker == nullptr) { + return nullptr; + } + return invoker->GetSAMgrObject(); +} + +/* + * databus return int64_t channel id, but high 32bit only use 1bit channel type, we convert to int + * convert to 24bit channelID and 7bit channel type + * |---1bit---|------7bit----| ------------------------24bit------| + * | reserved | channel type | true channel id | + * don't care signed bit when convert,for we reserved high 1bit + */ +uint32_t IPCProcessSkeleton::ConvertChannelID2Int(int64_t databusChannelId) +{ + if (databusChannelId < 0) { + return 0; + } + uint32_t channelType = static_cast((databusChannelId >> 8) & 0X00000000FF000000ULL); + uint32_t channelID = static_cast(databusChannelId & 0X0000000000FFFFFFULL); + return (channelType | channelID); +} + +std::string IPCProcessSkeleton::GetLocalDeviceID() +{ + std::lock_guard lockGuard(databusProcMutex_); + + std::string pkgName = "dbinderService"; + NodeBasicInfo nodeBasicInfo; + if (GetLocalNodeDeviceInfo(pkgName.c_str(), &nodeBasicInfo) != 0) { + DBINDER_LOGE("Get local node device info failed"); + return ""; + } + std::string networkId(nodeBasicInfo.networkId); + return networkId; +} + +uint32_t IPCProcessSkeleton::GetDBinderIdleHandle(uint64_t stubIndex) +{ + std::unique_lock lockGuard(handleToIndexMutex_); + + if (dBinderHandle_ < DBINDER_HANDLE_BASE || dBinderHandle_ > DBINDER_HANDLE_BASE + DBINDER_HANDLE_BASE) { + dBinderHandle_ = DBINDER_HANDLE_BASE; + } + uint32_t tempHandle = dBinderHandle_; + uint32_t count = DBINDER_HANDLE_BASE; + bool insertResult = false; + do { + count--; + tempHandle++; + if (tempHandle > DBINDER_HANDLE_BASE + DBINDER_HANDLE_BASE) { + tempHandle = DBINDER_HANDLE_BASE; + } + insertResult = handleToStubIndex_.insert(std::pair(tempHandle, stubIndex)).second; + } while (insertResult == false && count > 0); + + if (count == 0 && insertResult == false) { + return 0; + } + dBinderHandle_ = tempHandle; + return dBinderHandle_; +} + +bool IPCProcessSkeleton::DetachHandleToIndex(uint32_t handle) +{ + std::unique_lock lockGuard(handleToIndexMutex_); + + return (handleToStubIndex_.erase(handle) > 0); +} + +bool IPCProcessSkeleton::AttachHandleToIndex(uint32_t handle, uint64_t stubIndex) +{ + std::unique_lock lockGuard(handleToIndexMutex_); + auto result = handleToStubIndex_.insert(std::pair(handle, stubIndex)); + return result.second; +} + +uint64_t IPCProcessSkeleton::QueryHandleToIndex(uint32_t handle) +{ + std::shared_lock lockGuard(handleToIndexMutex_); + + auto it = handleToStubIndex_.find(handle); + if (it != handleToStubIndex_.end()) { + return it->second; + } + + return 0; +} + +uint64_t IPCProcessSkeleton::QueryHandleToIndex(std::list &handleList, uint32_t &handle) +{ + std::shared_lock lockGuard(handleToIndexMutex_); + for (auto it = handleList.begin(); it != handleList.end(); it++) { + auto mapIndex = handleToStubIndex_.find(*it); + if (mapIndex != handleToStubIndex_.end()) { + handle = mapIndex->first; + return mapIndex->second; + } + } + return 0; +} + + +bool IPCProcessSkeleton::ProxyDetachDBinderSession(uint32_t handle) +{ + std::lock_guard lockGuard(proxyToSessionMutex_); + + return (proxyToSession_.erase(handle) > 0); +} + +bool IPCProcessSkeleton::ProxyAttachDBinderSession(uint32_t handle, std::shared_ptr object) +{ + std::lock_guard lockGuard(proxyToSessionMutex_); + auto result = proxyToSession_.insert(std::pair>(handle, object)); + return result.second; +} + +std::shared_ptr IPCProcessSkeleton::ProxyQueryDBinderSession(uint32_t handle) +{ + std::lock_guard lockGuard(proxyToSessionMutex_); + + auto it = proxyToSession_.find(handle); + if (it != proxyToSession_.end()) { + return it->second; + } + + return nullptr; +} + +bool IPCProcessSkeleton::QueryProxyBySessionHandle(uint32_t handle, std::vector &proxyHandle) +{ + std::lock_guard lockGuard(proxyToSessionMutex_); + + for (auto it = proxyToSession_.begin(); it != proxyToSession_.end(); it++) { + std::shared_ptr session = it->second->GetBusSession(); + if (session == nullptr) { + DBINDER_LOGE("session is null, handle = %{public}u", handle); + return false; + } + uint32_t sessionHandle = IPCProcessSkeleton::ConvertChannelID2Int(session->GetChannelId()); + if (sessionHandle == handle) { + proxyHandle.push_back(it->first); + } + } + + return true; +} + +uint32_t IPCProcessSkeleton::QueryHandleByDatabusSession(const std::string &name, const std::string &deviceId, + uint64_t index) +{ + std::list handleList; + bool found = false; + { + std::lock_guard lockGuard(proxyToSessionMutex_); + + for (auto it = proxyToSession_.begin(); it != proxyToSession_.end(); it++) { + if ((it->second->GetDeviceId().compare(deviceId) == 0) && + (it->second->GetServiceName().compare(name) == 0)) { + handleList.push_front(it->first); + found = true; // found one at the least + } + } + } + uint32_t handleFound = 0; + if (found == true && QueryHandleToIndex(handleList, handleFound) == index) { + return handleFound; + } + + return 0; +} + +std::shared_ptr IPCProcessSkeleton::QuerySessionByInfo(const std::string &name, + const std::string &deviceId) +{ + std::lock_guard lockGuard(proxyToSessionMutex_); + + for (auto it = proxyToSession_.begin(); it != proxyToSession_.end(); it++) { + if ((it->second->GetDeviceId().compare(deviceId) == 0) && (it->second->GetServiceName().compare(name) == 0)) { + return it->second; + } + } + + return nullptr; +} + +bool IPCProcessSkeleton::StubDetachDBinderSession(uint32_t handle) +{ + std::unique_lock lockGuard(databusSessionMutex_); + + return (dbinderSessionObjects_.erase(handle) > 0); +} + +bool IPCProcessSkeleton::StubAttachDBinderSession(uint32_t handle, std::shared_ptr object) +{ + std::unique_lock lockGuard(databusSessionMutex_); + auto result = + dbinderSessionObjects_.insert(std::pair>(handle, object)); + + return result.second; +} + +std::shared_ptr IPCProcessSkeleton::StubQueryDBinderSession(uint32_t handle) +{ + std::shared_lock lockGuard(databusSessionMutex_); + + auto it = dbinderSessionObjects_.find(handle); + if (it != dbinderSessionObjects_.end()) { + return it->second; + } + + return nullptr; +} + +bool IPCProcessSkeleton::DetachThreadLockInfo(const std::thread::id &threadId) +{ + std::unique_lock lockGuard(threadLockMutex_); + + return (threadLockInfo_.erase(threadId) > 0); +} + +bool IPCProcessSkeleton::AttachThreadLockInfo(std::shared_ptr object, + const std::thread::id &threadId) +{ + std::unique_lock lockGuard(threadLockMutex_); + auto result = + threadLockInfo_.insert(std::pair>(threadId, object)); + return result.second; +} + +std::shared_ptr IPCProcessSkeleton::QueryThreadLockInfo(const std::thread::id &threadId) +{ + std::shared_lock lockGuard(threadLockMutex_); + + auto it = threadLockInfo_.find(threadId); + if (it != threadLockInfo_.end()) { + return it->second; + } + + return nullptr; +} + + +bool IPCProcessSkeleton::AddDataThreadToIdle(const std::thread::id &threadId) +{ + std::lock_guard lockGuard(idleDataMutex_); + + idleDataThreads_.push_front(threadId); + return true; +} + +bool IPCProcessSkeleton::DeleteDataThreadFromIdle(const std::thread::id &threadId) +{ + std::lock_guard lockGuard(idleDataMutex_); + for (auto it = idleDataThreads_.begin(); it != idleDataThreads_.end(); it++) { + if ((*it) == threadId) { + it = idleDataThreads_.erase(it); + return true; + } + } + + /* not in idle state, also return true */ + return true; +} + +std::thread::id IPCProcessSkeleton::GetIdleDataThread() +{ + std::lock_guard lockGuard(idleDataMutex_); + + if (idleDataThreads_.size() == 0) { + return std::thread::id(); + } + + std::thread::id threadId = idleDataThreads_.back(); + return threadId; +} + +int IPCProcessSkeleton::GetSocketIdleThreadNum() const +{ + if (threadPool_ != nullptr) { + return threadPool_->GetSocketIdleThreadNum(); + } + + return 0; +} +int IPCProcessSkeleton::GetSocketTotalThreadNum() const +{ + if (threadPool_ != nullptr) { + return threadPool_->GetSocketTotalThreadNum(); + } + + return 0; +} + +void IPCProcessSkeleton::AddDataInfoToThread(const std::thread::id &threadId, + std::shared_ptr processInfo) +{ + std::lock_guard lockGuard(dataQueueMutex_); + + (dataInfoQueue_[threadId]).push_back(processInfo); +} + +std::shared_ptr IPCProcessSkeleton::PopDataInfoFromThread(const std::thread::id &threadId) +{ + std::lock_guard lockGuard(dataQueueMutex_); + + if ((dataInfoQueue_[threadId]).size() == 0) { + return 0; + } + + std::shared_ptr processInfo = (dataInfoQueue_[threadId]).front(); + + (dataInfoQueue_[threadId]).erase((dataInfoQueue_[threadId]).begin()); + return processInfo; +} + +void IPCProcessSkeleton::WakeUpDataThread(const std::thread::id &threadID) +{ + if (threadID != std::thread::id()) { + std::shared_ptr threadLockInfo = QueryThreadLockInfo(threadID); + if (threadLockInfo != nullptr) { + /* Wake up this IO thread to process socket stream + * Wake up the client processing thread + */ + std::unique_lock lock_unique(threadLockInfo->mutex); + threadLockInfo->ready = true; + threadLockInfo->condition.notify_one(); + } + } +} + +void IPCProcessSkeleton::AddDataThreadInWait(const std::thread::id &threadId) +{ + std::shared_ptr threadLockInfo; + + threadLockInfo = QueryThreadLockInfo(threadId); + if (threadLockInfo == nullptr) { + threadLockInfo = std::make_shared(); + if (!AttachThreadLockInfo(threadLockInfo, threadId)) { + DBINDER_LOGE("thread has added lock info"); + return; + } + } + + AddDataThreadToIdle(threadId); + std::unique_lock lock_unique(threadLockInfo->mutex); + threadLockInfo->condition.wait(lock_unique, [&threadLockInfo] { return threadLockInfo->ready; }); + threadLockInfo->ready = false; + /* corresponding thread will be waked up */ + DeleteDataThreadFromIdle(threadId); +} + +uint64_t IPCProcessSkeleton::GetSeqNumber() +{ + std::lock_guard lockGuard(seqNumberMutex_); + seqNumber_++; // can be overflow, and seqNumber do not use 0 + if (seqNumber_ == 0) { + seqNumber_++; + } + return seqNumber_; +} + +std::shared_ptr IPCProcessSkeleton::QueryThreadBySeqNumber(uint64_t seqNumber) +{ + std::lock_guard lockGuard(findThreadMutex_); + + auto it = seqNumberToThread_.find(seqNumber); + if (it != seqNumberToThread_.end()) { + return it->second; + } + + return nullptr; +} + +void IPCProcessSkeleton::EraseThreadBySeqNumber(uint64_t seqNumber) +{ + std::lock_guard lockGuard(findThreadMutex_); + seqNumberToThread_.erase(seqNumber); +} + + +bool IPCProcessSkeleton::AddThreadBySeqNumber(uint64_t seqNumber, std::shared_ptr messageInfo) +{ + std::lock_guard lockGuard(findThreadMutex_); + + auto result = + seqNumberToThread_.insert(std::pair>(seqNumber, messageInfo)); + + return result.second; +} + +void IPCProcessSkeleton::WakeUpThreadBySeqNumber(uint64_t seqNumber, uint32_t handle) +{ + std::shared_ptr messageInfo; + + messageInfo = QueryThreadBySeqNumber(seqNumber); + if (messageInfo == nullptr) { + DBINDER_LOGE("error! messageInfo is nullptr"); + return; + } + + if (handle != messageInfo->socketId) { + DBINDER_LOGE("error! handle is not equal messageInfo, handle = %{public}d, messageFd = %{public}u", handle, + messageInfo->socketId); + return; + } + + if (messageInfo->threadId != std::thread::id()) { + std::shared_ptr threadLockInfo = QueryThreadLockInfo(messageInfo->threadId); + if (threadLockInfo != nullptr) { + /* wake up this IO thread to process socket stream + * Wake up the client processing thread + */ + std::unique_lock lock_unique(threadLockInfo->mutex); + threadLockInfo->ready = true; + threadLockInfo->condition.notify_one(); + } + } +} + +bool IPCProcessSkeleton::AddSendThreadInWait(uint64_t seqNumber, std::shared_ptr messageInfo, + int userWaitTime) +{ + std::shared_ptr threadLockInfo; + + if (!AddThreadBySeqNumber(seqNumber, messageInfo)) { + DBINDER_LOGE("add seqNumber = %" PRIu64 " failed", seqNumber); + return false; + } + + threadLockInfo = QueryThreadLockInfo(messageInfo->threadId); + if (threadLockInfo == nullptr) { + threadLockInfo = std::make_shared(); + bool ret = AttachThreadLockInfo(threadLockInfo, messageInfo->threadId); + if (!ret) { + DBINDER_LOGE("AttachThreadLockInfo fail"); + return false; + } + } + + std::unique_lock lock_unique(threadLockInfo->mutex); + if (threadLockInfo->condition.wait_for(lock_unique, std::chrono::seconds(userWaitTime), + [&threadLockInfo] { return threadLockInfo->ready; }) == false) { + threadLockInfo->ready = false; + DBINDER_LOGE("socket thread timeout, seqNumber = %{public}" PRIu64 ", ipc wait time = %{public}d", seqNumber, + userWaitTime); + return false; + } + threadLockInfo->ready = false; + return true; +} + +IRemoteObject *IPCProcessSkeleton::QueryStubByIndex(uint64_t stubIndex) +{ + std::shared_lock lockGuard(stubObjectsMutex_); + + auto it = stubObjects_.find(stubIndex); + if (it != stubObjects_.end()) { + return it->second; + } + + return nullptr; +} + +uint64_t IPCProcessSkeleton::AddStubByIndex(IRemoteObject *stubObject) +{ + std::unique_lock lockGuard(stubObjectsMutex_); + + /* if stub has its index, return it directly */ + for (auto it = stubObjects_.begin(); it != stubObjects_.end(); it++) { + if (it->second == stubObject) { + return it->first; + } + } + uint64_t stubIndex = randNum_++; + auto result = stubObjects_.insert(std::pair(stubIndex, stubObject)); + if (result.second) { + return stubIndex; + } else { + return 0; + } +} + +uint64_t IPCProcessSkeleton::EraseStubIndex(IRemoteObject *stubObject) +{ + std::unique_lock lockGuard(stubObjectsMutex_); + + for (auto it = stubObjects_.begin(); it != stubObjects_.end(); it++) { + if (it->second == stubObject) { + uint64_t stubIndex = it->first; + stubObjects_.erase(it); + return stubIndex; + } + } + return 0; +} + +bool IPCProcessSkeleton::DetachAppInfoToStubIndex(uint32_t pid, uint32_t uid, const std::string &deviceId, + uint64_t stubIndex) +{ + std::string appInfo = deviceId + std::to_string(pid) + std::to_string(uid); + + std::unique_lock lockGuard(appInfoToIndexMutex_); + + auto it = appInfoToStubIndex_.find(appInfo); + if (it != appInfoToStubIndex_.end()) { + bool result = it->second.erase(stubIndex) > 0; + if (it->second.size() == 0) { + appInfoToStubIndex_.erase(it); + } + return result; + } + + return false; +} + +void IPCProcessSkeleton::DetachAppInfoToStubIndex(uint64_t stubIndex) +{ + std::unique_lock lockGuard(appInfoToIndexMutex_); + + for (auto it = appInfoToStubIndex_.begin(); it != appInfoToStubIndex_.end();) { + (void)it->second.erase(stubIndex); + if (it->second.size() == 0) { + it = appInfoToStubIndex_.erase(it); + } else { + it++; + } + } +} + +bool IPCProcessSkeleton::AttachAppInfoToStubIndex(uint32_t pid, uint32_t uid, const std::string &deviceId, + uint64_t stubIndex) +{ + std::string appInfo = deviceId + std::to_string(pid) + std::to_string(uid); + + std::unique_lock lockGuard(appInfoToIndexMutex_); + + auto it = appInfoToStubIndex_.find(appInfo); + if (it != appInfoToStubIndex_.end()) { + auto result = it->second.insert(std::pair(stubIndex, true)); + return result.second; + } + + std::map mapItem { { stubIndex, true } }; + auto result = appInfoToStubIndex_.insert(std::pair>(appInfo, mapItem)); + return result.second; +} + +bool IPCProcessSkeleton::QueryAppInfoToStubIndex(uint32_t pid, uint32_t uid, const std::string &deviceId, + uint64_t stubIndex) +{ + std::string appInfo = deviceId + std::to_string(pid) + std::to_string(uid); + + std::shared_lock lockGuard(appInfoToIndexMutex_); + + auto it = appInfoToStubIndex_.find(appInfo); + if (it != appInfoToStubIndex_.end()) { + auto it2 = it->second.find(stubIndex); + if (it2 != it->second.end()) { + return true; + } + } + + return false; +} + +std::shared_ptr IPCProcessSkeleton::GetListenThreadLockInfo() +{ + return listenThreadReady_; +} + +bool IPCProcessSkeleton::AttachCallbackStub(IPCObjectProxy *ipcProxy, sptr callbackStub) +{ + std::unique_lock lockGuard(callbackStubMutex_); + auto result = noticeStub_.insert(std::pair>(ipcProxy, callbackStub)); + return result.second; +} + +bool IPCProcessSkeleton::DetachCallbackStub(IPCObjectStub *callbackStub) +{ + std::unique_lock lockGuard(callbackStubMutex_); + for (auto it = noticeStub_.begin(); it != noticeStub_.end(); it++) { + if (it->second.GetRefPtr() == callbackStub) { + noticeStub_.erase(it); + return true; + } + } + return false; +} + +bool IPCProcessSkeleton::DetachCallbackStubByProxy(IPCObjectProxy *ipcProxy) +{ + std::unique_lock lockGuard(callbackStubMutex_); + + return (noticeStub_.erase(ipcProxy) > 0); +} + +sptr IPCProcessSkeleton::QueryCallbackStub(IPCObjectProxy *ipcProxy) +{ + std::shared_lock lockGuard(callbackStubMutex_); + auto it = noticeStub_.find(ipcProxy); + if (it != noticeStub_.end()) { + return it->second; + } + + return nullptr; +} + +IPCObjectProxy *IPCProcessSkeleton::QueryCallbackProxy(IPCObjectStub *callbackStub) +{ + std::shared_lock lockGuard(callbackStubMutex_); + for (auto it = noticeStub_.begin(); it != noticeStub_.end(); it++) { + if (it->second.GetRefPtr() == callbackStub) { + return it->first; + } + } + + return nullptr; +} + +std::string IPCProcessSkeleton::GetDatabusName() +{ + std::lock_guard lockGuard(sessionNameMutex_); + + return sessionName_; +} + +bool IPCProcessSkeleton::CreateSoftbusServer(const std::string &name) +{ + std::lock_guard lockGuard(sessionNameMutex_); + + if (!sessionName_.empty()) { + return true; + } + + if (name.empty()) { + DBINDER_LOGE("get wrong session name = %s", name.c_str()); + return false; + } + + std::shared_ptr manager = ISessionService::GetInstance(); + if (manager == nullptr) { + DBINDER_LOGE("fail to get softbus manager"); + return false; + } + + std::shared_ptr callback = std::make_shared(); + if (callback == nullptr) { + DBINDER_LOGE("fail to create softbus callbacks"); + return false; + } + + int ret = manager->CreateSessionServer(DBINDER_SERVER_PKG_NAME, name, callback); + if (ret != 0) { + DBINDER_LOGE("fail to create softbus server"); + return false; + } + + sessionName_ = name; + SpawnThread(IPCWorkThread::PROCESS_ACTIVE, IRemoteObject::IF_PROT_DATABUS); + + return true; +} + +bool IPCProcessSkeleton::AttachRawData(uint32_t fd, std::shared_ptr rawData) +{ + std::unique_lock lockGuard(rawDataMutex_); + /* always discard the old one if exists */ + rawData_.erase(fd); + auto result = rawData_.insert(std::pair>(fd, rawData)); + return result.second; +} + +bool IPCProcessSkeleton::DetachRawData(uint32_t fd) +{ + std::unique_lock lockGuard(rawDataMutex_); + return (rawData_.erase(fd) > 0); +} + +std::shared_ptr IPCProcessSkeleton::QueryRawData(uint32_t fd) +{ + std::shared_lock lockGuard(rawDataMutex_); + auto it = rawData_.find(fd); + if (it != rawData_.end()) { + return it->second; + } + return nullptr; +} + +bool IPCProcessSkeleton::AttachStubRecvRefInfo(IRemoteObject *stub, int pid, const std::string &deviceId) +{ + auto check = [&stub, &pid, &deviceId](const std::shared_ptr &stubRef) { + return stubRef->GetRemotePid() == pid && stubRef->GetDeviceId().compare(deviceId) == 0 && + stubRef->GetStubObject() == stub; + }; + + std::unique_lock lockGuard(stubRecvRefMutex_); + auto it = std::find_if(stubRecvRefs_.begin(), stubRecvRefs_.end(), check); + if (it != stubRecvRefs_.end()) { + DBINDER_LOGE("fail to attach stub recv ref info, already in"); + return false; + } + + std::shared_ptr refCount = std::make_shared(stub, pid, deviceId); + stubRecvRefs_.push_front(refCount); + return true; +} + +void IPCProcessSkeleton::DetachStubRecvRefInfo(int pid, const std::string &deviceId) +{ + auto check = [&pid, &deviceId](const std::shared_ptr &stubRef) { + return stubRef->GetRemotePid() == pid && stubRef->GetDeviceId().compare(deviceId) == 0; + }; + + std::unique_lock lockGuard(stubRecvRefMutex_); + stubRecvRefs_.remove_if(check); +} + +bool IPCProcessSkeleton::DetachStubRecvRefInfo(const IRemoteObject *stub, int pid, const std::string &deviceId) +{ + std::unique_lock lockGuard(stubRecvRefMutex_); + for (auto it = stubRecvRefs_.begin(); it != stubRecvRefs_.end(); it++) { + std::shared_ptr object = (*it); + if ((object->GetRemotePid() == pid) && (object->GetDeviceId().compare(deviceId) == 0) && + (object->GetStubObject() == stub)) { + stubRecvRefs_.erase(it); + return true; + } + } + return false; +} + +void IPCProcessSkeleton::DetachStubRecvRefInfo(const IRemoteObject *stub) +{ + auto check = [&stub](const std::shared_ptr &stubRef) { + return stubRef->GetStubObject() == stub; + }; + + std::unique_lock lockGuard(stubRecvRefMutex_); + stubRecvRefs_.remove_if(check); +} + +std::list IPCProcessSkeleton::QueryStubRecvRefInfo(int pid, const std::string &deviceId) +{ + std::shared_lock lockGuard(stubRecvRefMutex_); + std::list stubList; + for (auto it = stubRecvRefs_.begin(); it != stubRecvRefs_.end(); it++) { + std::shared_ptr object = (*it); + if ((object->GetRemotePid() == pid) && (object->GetDeviceId().compare(deviceId) == 0)) { + stubList.push_back(object->GetStubObject()); + } + } + + return stubList; +} + +void IPCProcessSkeleton::DetachStubRefInfo(int pid, const std::string &deviceId) +{ + std::list stubList = QueryStubRecvRefInfo(pid, deviceId); + if (!stubList.empty()) { + for (auto it = stubList.begin(); it != stubList.end(); it++) { + (*it)->DecStrongRef(this); + } + } + DetachStubRecvRefInfo(pid, deviceId); + DetachStubSendRefInfo(pid, deviceId); +} + +void IPCProcessSkeleton::DetachStubRefInfo(IRemoteObject *stub, int pid, const std::string &deviceId) +{ + if (DetachStubRecvRefInfo(stub, pid, deviceId) == true) { + stub->DecStrongRef(this); + } + DetachStubSendRefInfo(stub, pid, deviceId); +} + +bool IPCProcessSkeleton::IncStubRefTimes(IRemoteObject *stub) +{ + std::lock_guard lockGuard(transTimesMutex_); + + auto it = transTimes_.find(stub); + if (it != transTimes_.end()) { + it->second++; + return true; + } + + auto result = transTimes_.insert(std::pair(stub, TRANS_TIME_INIT_VALUE)); + return result.second; +} + +bool IPCProcessSkeleton::DecStubRefTimes(IRemoteObject *stub) +{ + std::lock_guard lockGuard(transTimesMutex_); + + auto it = transTimes_.find(stub); + if (it != transTimes_.end()) { + if (it->second > 0) { + it->second--; + return true; + } + } + return false; +} + +bool IPCProcessSkeleton::DetachStubRefTimes(IRemoteObject *stub) +{ + std::lock_guard lockGuard(transTimesMutex_); + return (transTimes_.erase(stub) > 0); +} + +bool IPCProcessSkeleton::AttachStubSendRefInfo(IRemoteObject *stub, int pid, const std::string &deviceId) +{ + auto check = [&stub, &pid, &deviceId](const std::shared_ptr &stubRef) { + return stubRef->GetRemotePid() == pid && stubRef->GetDeviceId().compare(deviceId) == 0 && + stubRef->GetStubObject() == stub; + }; + + std::lock_guard lockGuard(stubSendRefMutex_); + auto it = std::find_if(stubSendRefs_.begin(), stubSendRefs_.end(), check); + if (it != stubSendRefs_.end()) { + DBINDER_LOGE("fail to attach stub sender ref info, already in"); + return false; + } + std::shared_ptr refCount = std::make_shared(stub, pid, deviceId); + stubSendRefs_.push_front(refCount); + + return true; +} + +void IPCProcessSkeleton::DetachStubSendRefInfo(IRemoteObject *stub) +{ + auto check = [&stub](const std::shared_ptr &stubRef) { + return stubRef->GetStubObject() == stub; + }; + + std::lock_guard lockGuard(stubSendRefMutex_); + stubSendRefs_.remove_if(check); +} + +void IPCProcessSkeleton::DetachStubSendRefInfo(int pid, const std::string &deviceId) +{ + auto check = [&pid, &deviceId](const std::shared_ptr &stubRef) { + return stubRef->GetRemotePid() == pid && stubRef->GetDeviceId().compare(deviceId) == 0; + }; + + std::lock_guard lockGuard(stubSendRefMutex_); + stubSendRefs_.remove_if(check); +} + +void IPCProcessSkeleton::DetachStubSendRefInfo(IRemoteObject *stub, int pid, const std::string &deviceId) +{ + auto check = [&pid, &deviceId, &stub](const std::shared_ptr &stubRef) { + return stubRef->GetRemotePid() == pid && stubRef->GetDeviceId().compare(deviceId) == 0 && + stubRef->GetStubObject() == stub; + }; + + std::lock_guard lockGuard(stubSendRefMutex_); + stubSendRefs_.remove_if(check); +} + +bool IPCProcessSkeleton::IsSameRemoteObject(IRemoteObject *stub, int pid, int uid, const std::string &deviceId, + const std::shared_ptr &auth) +{ + if ((auth->GetStubObject() == stub) && (auth->GetRemotePid() == pid) && (auth->GetRemoteUid() == uid) && + (auth->GetRemoteDeviceId().compare(deviceId) == 0)) { + return true; + } else { + return false; + } +} + +bool IPCProcessSkeleton::IsSameRemoteObject(int pid, int uid, const std::string &deviceId, + const std::shared_ptr &auth) +{ + if ((auth->GetRemotePid() == pid) && (auth->GetRemoteUid() == uid) && + (auth->GetRemoteDeviceId().compare(deviceId) == 0)) { + return true; + } else { + return false; + } +} + +bool IPCProcessSkeleton::AttachCommAuthInfo(IRemoteObject *stub, int pid, int uid, const std::string &deviceId) +{ + auto check = [&stub, &pid, &uid, &deviceId, this](const std::shared_ptr &auth) { + return IsSameRemoteObject(stub, pid, uid, deviceId, auth); + }; + + std::unique_lock lockGuard(commAuthMutex_); + auto it = std::find_if(commAuth_.begin(), commAuth_.end(), check); + if (it != commAuth_.end()) { + DBINDER_LOGI("AttachCommAuthInfo already"); + return true; + } + + std::shared_ptr authObject = std::make_shared(stub, pid, uid, deviceId); + commAuth_.push_front(authObject); + return true; +} + +void IPCProcessSkeleton::DetachCommAuthInfo(IRemoteObject *stub, int pid, int uid, const std::string &deviceId) +{ + auto check = [&stub, &pid, &uid, &deviceId, this](const std::shared_ptr &auth) { + return IsSameRemoteObject(stub, pid, uid, deviceId, auth); + }; + + std::unique_lock lockGuard(commAuthMutex_); + commAuth_.remove_if(check); +} + +bool IPCProcessSkeleton::QueryIsAuth(int pid, int uid, const std::string &deviceId) +{ + auto check = [&pid, &uid, &deviceId, this](const std::shared_ptr &auth) { + return IsSameRemoteObject(pid, uid, deviceId, auth); + }; + + std::shared_lock lockGuard(commAuthMutex_); + auto it = std::find_if(commAuth_.begin(), commAuth_.end(), check); + if (it != commAuth_.end()) { + return true; + } + DBINDER_LOGE("Query Comm Auth Fail"); + return false; +} + +void IPCProcessSkeleton::DetachCommAuthInfoByStub(IRemoteObject *stub) +{ + auto check = [&stub](const std::shared_ptr &auth) { return auth->GetStubObject() == stub; }; + std::unique_lock lockGuard(commAuthMutex_); + commAuth_.remove_if(check); +} +#endif +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS diff --git a/ipc/native/src/core/source/ipc_skeleton.cpp b/ipc/native/src/core/source/ipc_skeleton.cpp new file mode 100755 index 00000000..66dd3696 --- /dev/null +++ b/ipc/native/src/core/source/ipc_skeleton.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_skeleton.h" +#include "ipc_process_skeleton.h" +#include "ipc_thread_skeleton.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +using namespace IPC_SINGLE; +#endif + +void IPCSkeleton::JoinWorkThread() +{ + IPCThreadSkeleton *current = IPCThreadSkeleton::GetCurrent(); + if (current != nullptr) { + current->JoinWorkThread(IRemoteObject::IF_PROT_DEFAULT); + } +} + +void IPCSkeleton::StopWorkThread() +{ + IPCThreadSkeleton *current = IPCThreadSkeleton::GetCurrent(); + if (current != nullptr) { + current->StopWorkThread(IRemoteObject::IF_PROT_DEFAULT); + } +} + +bool IPCSkeleton::SetContextObject(sptr &object) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current != nullptr) { + return current->SetRegistryObject(object); + } + return false; +} + +sptr IPCSkeleton::GetContextObject() +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current != nullptr) { + return current->GetRegistryObject(); + } + return nullptr; +} + +bool IPCSkeleton::SetMaxWorkThreadNum(int maxThreadNum) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current != nullptr) { + // first thread have started at IPCProcessSkeleton instances + return current->SetMaxWorkThread(maxThreadNum); + } + return false; +} + +pid_t IPCSkeleton::GetCallingPid() +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetActiveInvoker(); + if (invoker != nullptr) { + return invoker->GetCallerPid(); + } + return getpid(); +} + +pid_t IPCSkeleton::GetCallingUid() +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetActiveInvoker(); + if (invoker != nullptr) { + return invoker->GetCallerUid(); + } + return getuid(); +} + +std::string IPCSkeleton::GetLocalDeviceID() +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetActiveInvoker(); + if (invoker != nullptr) { + return invoker->GetLocalDeviceID(); + } + return ""; +} + +std::string IPCSkeleton::GetCallingDeviceID() +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetActiveInvoker(); + if (invoker != nullptr) { + return invoker->GetCallerDeviceID(); + } + return ""; +} + +IPCSkeleton &IPCSkeleton::GetInstance() +{ + static IPCSkeleton skeleton; + return skeleton; +} + +bool IPCSkeleton::IsLocalCalling() +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetActiveInvoker(); + if (invoker != nullptr) { + return invoker->IsLocalCalling(); + } + return true; +} + +int IPCSkeleton::FlushCommands(IRemoteObject *object) +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetProxyInvoker(object); + if (invoker == nullptr) { + return IPC_SKELETON_NULL_OBJECT_ERR; + } + + return invoker->FlushCommands(object); +} + +std::string IPCSkeleton::ResetCallingIdentity() +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetActiveInvoker(); + if (invoker != nullptr) { + return invoker->ResetCallingIdentity(); + } + return ""; +} + +bool IPCSkeleton::SetCallingIdentity(std::string &identity) +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetActiveInvoker(); + if (invoker != nullptr) { + return invoker->SetCallingIdentity(identity); + } + + return true; +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/ipc_thread_pool.cpp b/ipc/native/src/core/source/ipc_thread_pool.cpp new file mode 100755 index 00000000..b04d5136 --- /dev/null +++ b/ipc/native/src/core/source/ipc_thread_pool.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_thread_pool.h" +#include +#include +#include "ipc_debug.h" +#include "log_tags.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC, "IPCWorkThreadPool" }; + +#define DBINDER_LOGI(fmt, args...) (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}d: " fmt, __LINE__, ##args) + +IPCWorkThreadPool::IPCWorkThreadPool(int maxThreadNum) + : threadSequence_(0), + maxThreadNum_(maxThreadNum + maxThreadNum), + idleThreadNum_(maxThreadNum), + idleSocketThreadNum_(maxThreadNum) +{} + +IPCWorkThreadPool::~IPCWorkThreadPool() +{ + StopAllThreads(); + threads_.clear(); +} + +void IPCWorkThreadPool::StopAllThreads() +{ + std::lock_guard lock(mutex_); + for (auto it = threads_.begin(); it != threads_.end(); it++) { + it->second->StopWorkThread(); + } +} + +bool IPCWorkThreadPool::SpawnThread(int policy, int proto) +{ + std::lock_guard lock(mutex_); + if (!(proto == IRemoteObject::IF_PROT_DEFAULT && idleThreadNum_ > 0) && + !(proto == IRemoteObject::IF_PROT_DATABUS && idleSocketThreadNum_ > 0)) { + return false; + } + std::string threadName = MakeThreadName(proto); + DBINDER_LOGI("SpawnThread Name= %{public}s", threadName.c_str()); + + if (threads_.find(threadName) == threads_.end()) { + sptr newThread = sptr(new IPCWorkThread(threadName)); + threads_[threadName] = newThread; + if (proto == IRemoteObject::IF_PROT_DEFAULT) { + idleThreadNum_--; + DBINDER_LOGI("SpawnThread, now idleThreadNum_ =%d", idleThreadNum_); + } + if (proto == IRemoteObject::IF_PROT_DATABUS) { + idleSocketThreadNum_--; + DBINDER_LOGI("SpawnThread, now idleSocketThreadNum_ =%d", idleSocketThreadNum_); + } + + newThread->Start(policy, proto, threadName); + return true; + } + return false; +} + +std::string IPCWorkThreadPool::MakeThreadName(int proto) +{ + int sequence = threadSequence_.fetch_add(1, std::memory_order_relaxed); + if (proto == IRemoteObject::IF_PROT_DATABUS) { + std::string threadName = "DRPC"; + return std::to_string(sequence) + threadName; + } else { + std::string threadName = "IPC"; + return std::to_string(sequence) + threadName; + } +} + +bool IPCWorkThreadPool::RemoveThread(const std::string &threadName) +{ + std::lock_guard lock(mutex_); + auto it = threads_.find(threadName); + if (it != threads_.end()) { + sptr workThread = it->second; + if (workThread == nullptr) { + return false; + } + if (workThread->proto_ == IRemoteObject::IF_PROT_DEFAULT) { + idleThreadNum_++; + } else if (workThread->proto_ == IRemoteObject::IF_PROT_DATABUS) { + idleSocketThreadNum_++; + } + threads_.erase(it); + DBINDER_LOGI("SpawnThread, now idleThreadNum_ =%d", idleSocketThreadNum_); + return true; + } + return false; +} + +int IPCWorkThreadPool::GetSocketIdleThreadNum() const +{ + return idleSocketThreadNum_; +} + +int IPCWorkThreadPool::GetSocketTotalThreadNum() const +{ + return maxThreadNum_ / PROTO_NUM; +} + +int IPCWorkThreadPool::GetMaxThreadNum() const +{ + return maxThreadNum_ / PROTO_NUM; +} + +void IPCWorkThreadPool::UpdateMaxThreadNum(int maxThreadNum) +{ + /* + * not support delete thread, because thread is in using + */ + int totalNum = maxThreadNum + maxThreadNum; + std::lock_guard lock(mutex_); + if (totalNum <= maxThreadNum_) { + return; + } + int diff = totalNum - maxThreadNum_; + maxThreadNum_ = totalNum; + idleThreadNum_ += diff / PROTO_NUM; + idleSocketThreadNum_ += diff / PROTO_NUM; +} +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namesapce OHOS + diff --git a/ipc/native/src/core/source/ipc_thread_skeleton.cpp b/ipc/native/src/core/source/ipc_thread_skeleton.cpp new file mode 100755 index 00000000..f2234f43 --- /dev/null +++ b/ipc/native/src/core/source/ipc_thread_skeleton.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_thread_skeleton.h" +#include "ipc_debug.h" +#include "dbinder_error_code.h" +#include "log_tags.h" +#include "ipc_object_proxy.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +using namespace OHOS::HiviewDFX; +pthread_key_t IPCThreadSkeleton::TLSKey_ = 0; +pthread_once_t IPCThreadSkeleton::TLSKeyOnce_ = PTHREAD_ONCE_INIT; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCThreadSkeleton" }; +void IPCThreadSkeleton::TlsDestructor(void *args) +{ + auto *current = static_cast(args); + auto it = current->invokers_.find(IRemoteObject::IF_PROT_BINDER); + if (it != current->invokers_.end()) { + ZLOGW(LABEL, "thread exit, flush commands"); + BinderInvoker *invoker = reinterpret_cast(it->second); + invoker->FlushCommands(nullptr); + invoker->ExitCurrentThread(); + } + delete current; +} + +void IPCThreadSkeleton::MakeTlsKey() +{ + pthread_key_create(&TLSKey_, IPCThreadSkeleton::TlsDestructor); +} + +IPCThreadSkeleton *IPCThreadSkeleton::GetCurrent() +{ + IPCThreadSkeleton *current = nullptr; + + pthread_once(&TLSKeyOnce_, IPCThreadSkeleton::MakeTlsKey); + + void *curTLS = pthread_getspecific(TLSKey_); + if (curTLS != nullptr) { + current = reinterpret_cast(curTLS); + } else { + current = new IPCThreadSkeleton(); + } + + return current; +} + +IPCThreadSkeleton::IPCThreadSkeleton() +{ + pthread_setspecific(TLSKey_, this); +} + +IPCThreadSkeleton::~IPCThreadSkeleton() +{ + ZLOGE(LABEL, "IPCThreadSkeleton delete"); + for (auto it = invokers_.begin(); it != invokers_.end();) { + delete it->second; + it = invokers_.erase(it); + } +} + +IRemoteInvoker *IPCThreadSkeleton::GetRemoteInvoker(int proto) +{ + IPCThreadSkeleton *current = IPCThreadSkeleton::GetCurrent(); + IRemoteInvoker *invoker = nullptr; + if (current == nullptr) { + return nullptr; + } + + auto it = current->invokers_.find(proto); + if (it != current->invokers_.end()) { + invoker = it->second; + } else { + InvokerFactory &factory = InvokerFactory::Get(); + invoker = factory.newInstance(proto); + if (invoker == nullptr) { + ZLOGE(LABEL, "invoker is NULL proto = %d", proto); + return nullptr; + } + + // non-thread safe, add lock to protect it. + current->invokers_.insert(std::make_pair(proto, invoker)); + } + + return invoker; +} + +IRemoteInvoker *IPCThreadSkeleton::GetActiveInvoker() +{ + IRemoteInvoker *binderInvoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_BINDER); + if ((binderInvoker != nullptr) && (binderInvoker->GetStatus() == IRemoteInvoker::ACTIVE_INVOKER)) { + return binderInvoker; + } +#ifndef CONFIG_IPC_SINGLE + IRemoteInvoker *dbinderInvoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DATABUS); + if ((dbinderInvoker != nullptr) && (dbinderInvoker->GetStatus() == IRemoteInvoker::ACTIVE_INVOKER)) { + return dbinderInvoker; + } +#endif + return nullptr; +} + +IRemoteInvoker *IPCThreadSkeleton::GetProxyInvoker(IRemoteObject *object) +{ + if (object == nullptr) { + ZLOGE(LABEL, "proxy is invalid"); + return nullptr; + } + if (!object->IsProxyObject()) { + return nullptr; + } + + IPCObjectProxy *proxy = reinterpret_cast(object); + return IPCThreadSkeleton::GetRemoteInvoker(proxy->GetProto()); +} + +IRemoteInvoker *IPCThreadSkeleton::GetDefaultInvoker() +{ + return GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); +} + +void IPCThreadSkeleton::JoinWorkThread(int prot) +{ + IRemoteInvoker *invoker = GetRemoteInvoker(prot); + if (invoker != nullptr) { + invoker->JoinThread(true); + } +} + +void IPCThreadSkeleton::StopWorkThread(int prot) +{ + IRemoteInvoker *invoker = GetRemoteInvoker(prot); + if (invoker != nullptr) { + invoker->StopWorkThread(); + } +} +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS diff --git a/ipc/native/src/core/source/ipc_workthread.cpp b/ipc/native/src/core/source/ipc_workthread.cpp new file mode 100755 index 00000000..52f020b7 --- /dev/null +++ b/ipc/native/src/core/source/ipc_workthread.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_workthread.h" +#include +#include "ipc_debug.h" +#include "ipc_process_skeleton.h" +#include "ipc_thread_skeleton.h" +#include "log_tags.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +IPCWorkThread::IPCWorkThread(std::string threadName) : threadName_(std::move(threadName)) {} + +IPCWorkThread::~IPCWorkThread() +{ + StopWorkThread(); +} + +void IPCWorkThread::ThreadHandler() +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(proto_); + DBINDER_LOGI("proto_=%d", proto_); + + if (invoker != nullptr) { + switch (policy_) { + case SPAWN_PASSIVE: + invoker->JoinThread(false); + break; + case SPAWN_ACTIVE: + invoker->JoinThread(true); + break; + case PROCESS_PASSIVE: + invoker->JoinProcessThread(false); + break; + case PROCESS_ACTIVE: + invoker->JoinProcessThread(true); + break; + default: + DBINDER_LOGI("policy_ = %{public}d", policy_); + break; + } + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current != nullptr) { + current->OnThreadTerminated(threadName_); + } +} + +void IPCWorkThread::StopWorkThread() +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(proto_); + if (invoker != nullptr) { + invoker->StopWorkThread(); + } +} + +void IPCWorkThread::Start(int policy, int proto, std::string threadName) +{ + policy_ = policy; + proto_ = proto; + + std::thread t(std::bind(&IPCWorkThread::ThreadHandler, this)); + std::string wholeName = threadName + std::to_string(getpid()) + "_" + std::to_string(gettid()); + DBINDER_LOGI("create thread = %{public}s, policy=%d, proto=%d", wholeName.c_str(), policy, proto); + thread_ = std::move(t); + thread_.detach(); +} +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS diff --git a/ipc/native/src/core/source/iremote_broker.cpp b/ipc/native/src/core/source/iremote_broker.cpp new file mode 100755 index 00000000..9a917fbb --- /dev/null +++ b/ipc/native/src/core/source/iremote_broker.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "iremote_broker.h" +#include +#include "ipc_debug.h" +#include "log_tags.h" + +namespace OHOS { +[[maybe_unused]] static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "BrokerRegistration" }; +BrokerRegistration &BrokerRegistration::Get() +{ + static BrokerRegistration instance; + return instance; +} + +BrokerRegistration::~BrokerRegistration() +{ + std::lock_guard lockGuard(creatorMutex_); + for (auto it = creators_.begin(); it != creators_.end();) { + it = creators_.erase(it); + } +} + +bool BrokerRegistration::Register(const std::u16string &descriptor, const Constructor &creator) +{ + if (descriptor.empty()) { + return false; + } + + std::lock_guard lockGuard(creatorMutex_); + auto it = creators_.find(descriptor); + if (it == creators_.end()) { + return creators_.insert({ descriptor, creator }).second; + } + return false; +} + +void BrokerRegistration::Unregister(const std::u16string &descriptor) +{ + std::lock_guard lockGuard(creatorMutex_); + if (!descriptor.empty()) { + auto it = creators_.find(descriptor); + if (it != creators_.end()) { + creators_.erase(it); + } + } +} + +sptr BrokerRegistration::NewInstance(const std::u16string &descriptor, const sptr &object) +{ + std::lock_guard lockGuard(creatorMutex_); + + sptr broker; + if (object != nullptr) { + if (object->IsProxyObject()) { + auto it = creators_.find(descriptor); + if (it != creators_.end()) { + broker = it->second(object); + } + } else { + broker = object->AsInterface().GetRefPtr(); + } + } + return broker; +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/iremote_object.cpp b/ipc/native/src/core/source/iremote_object.cpp new file mode 100755 index 00000000..0501c59b --- /dev/null +++ b/ipc/native/src/core/source/iremote_object.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "iremote_broker.h" +#include "ipc_types.h" +#include "ipc_debug.h" +#include "ipc_object_proxy.h" +#include "ipc_thread_skeleton.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +using namespace IPC_SINGLE; +#endif + +bool IRemoteObject::CheckObjectLegality() const +{ + return false; +} + +bool IRemoteObject::Marshalling(Parcel &parcel) const +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + + if (invoker != nullptr) { + return invoker->FlattenObject(parcel, this); + } + + return false; +} + +bool IRemoteObject::Marshalling(Parcel &parcel, const sptr &object) +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + if (invoker != nullptr) { + return invoker->FlattenObject(parcel, object); + } + + return false; +} + +IRemoteObject *IRemoteObject::Unmarshalling(Parcel &parcel) +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + + if (invoker != nullptr) { + return invoker->UnflattenObject(parcel); + } + + return nullptr; +} + +std::u16string IRemoteObject::GetObjectDescriptor() const +{ + return descriptor_; +} + +sptr IRemoteObject::AsInterface() +{ + return nullptr; +} + +bool IRemoteObject::IsProxyObject() const +{ + return true; +} + +IRemoteObject::IRemoteObject(std::u16string descriptor) : descriptor_(descriptor) +{ + ExtendObjectLifetime(); + asRemote_ = true; +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/message_option.cpp b/ipc/native/src/core/source/message_option.cpp new file mode 100755 index 00000000..9255d12c --- /dev/null +++ b/ipc/native/src/core/source/message_option.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "message_option.h" + +namespace OHOS { +static constexpr int MAX_WAIT_TIME = 3000; +MessageOption::MessageOption(int flags, int waitTime) : flags_(static_cast(flags)), waitTime_(waitTime) {} +void MessageOption::SetFlags(int flags) +{ + flags_ |= static_cast(flags); +} + +int MessageOption::GetFlags() const +{ + return flags_; +} + +void MessageOption::SetWaitTime(int waitTime) +{ + if (waitTime <= 0) { + waitTime_ = TF_WAIT_TIME; + } else if (waitTime > MAX_WAIT_TIME) { + waitTime_ = MAX_WAIT_TIME; + } else { + waitTime_ = waitTime; + } +} + +int MessageOption::GetWaitTime() const +{ + return waitTime_; +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/message_parcel.cpp b/ipc/native/src/core/source/message_parcel.cpp new file mode 100755 index 00000000..c02b915c --- /dev/null +++ b/ipc/native/src/core/source/message_parcel.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "message_parcel.h" +#include +#include + +#include "ipc_debug.h" +#include "iremote_object.h" +#include "ipc_file_descriptor.h" +#include "sys_binder.h" +#include "ashmem.h" +#include "securec.h" + +namespace OHOS { +MessageParcel::MessageParcel() + : Parcel(), + writeRawDataFd_(-1), + readRawDataFd_(-1), + kernelMappedWrite_(nullptr), + kernelMappedRead_(nullptr), + rawData_(nullptr), + rawDataSize_(0) +{} + +MessageParcel::MessageParcel(Allocator *allocator) + : Parcel(allocator), + writeRawDataFd_(-1), + readRawDataFd_(-1), + kernelMappedWrite_(nullptr), + kernelMappedRead_(nullptr), + rawData_(nullptr), + rawDataSize_(0) +{} + +MessageParcel::~MessageParcel() +{ + if (kernelMappedWrite_ != nullptr) { + ::munmap(kernelMappedWrite_, rawDataSize_); + kernelMappedWrite_ = nullptr; + } + if (kernelMappedRead_ != nullptr) { + ::munmap(kernelMappedRead_, rawDataSize_); + kernelMappedRead_ = nullptr; + } + + if (readRawDataFd_ > 0) { + ::close(readRawDataFd_); + readRawDataFd_ = -1; + } + if (writeRawDataFd_ > 0) { + ::close(writeRawDataFd_); + writeRawDataFd_ = -1; + } + + ClearFileDescriptor(); + + rawData_ = nullptr; + rawDataSize_ = 0; +} + +bool MessageParcel::WriteRemoteObject(const sptr &object) +{ + holders_.push_back(object); + return WriteObject(object); +} + +sptr MessageParcel::ReadRemoteObject() +{ + return ReadObject(); +} + +bool MessageParcel::WriteFileDescriptor(int fd) +{ + if (fd < 0) { + return false; + } + int dupFd = dup(fd); + if (dupFd < 0) { + return false; + } + sptr descriptor = new IPCFileDescriptor(dupFd); + return WriteObject(descriptor); +} + +int MessageParcel::ReadFileDescriptor() +{ + sptr descriptor = ReadObject(); + if (descriptor == nullptr) { + return -1; + } + int fd = descriptor->GetFd(); + if (fd < 0) { + return -1; + } + holders_.push_back(descriptor); + return dup(fd); +} + +void MessageParcel::ClearFileDescriptor() +{ + binder_size_t *object = reinterpret_cast(GetObjectOffsets()); + size_t objectNum = GetOffsetsSize(); + uintptr_t data = GetData(); + for (size_t i = 0; i < objectNum; i++) { + const flat_binder_object *flat = reinterpret_cast(data + object[i]); + if (flat->hdr.type == BINDER_TYPE_FD && flat->handle > 0) { + ::close(flat->handle); + } + } +} + +bool MessageParcel::ContainFileDescriptors() const +{ + binder_size_t *object = reinterpret_cast(GetObjectOffsets()); + size_t objectNum = GetOffsetsSize(); + uintptr_t data = GetData(); + for (size_t i = 0; i < objectNum; i++) { + const flat_binder_object *flat = reinterpret_cast(data + object[i]); + if (flat->hdr.type == BINDER_TYPE_FD) { + return true; + } + } + + return false; +} + +bool MessageParcel::WriteInterfaceToken(std::u16string name) +{ + constexpr int strictModePolicy = 0x100; + constexpr int workSource = 0; + size_t rewindPos = GetWritePosition(); + if (!WriteInt32(strictModePolicy)) { + return false; + } + + if (!WriteInt32(workSource)) { + if (!RewindWrite(rewindPos)) { + FlushBuffer(); + } + return false; + } + + return WriteString16(name); +} + +std::u16string MessageParcel::ReadInterfaceToken() +{ + [[maybe_unused]] int strictModePolicy = ReadInt32(); + [[maybe_unused]] int workSource = ReadInt32(); + return ReadString16(); +} + +bool MessageParcel::WriteRawData(const void *data, size_t size) +{ + if (data == nullptr || size > MAX_RAWDATA_SIZE) { + return false; + } + if (kernelMappedWrite_ != nullptr) { + return false; + } + if (!WriteInt32(size)) { + return false; + } + if (size <= MIN_RAWDATA_SIZE) { + return WriteUnpadBuffer(data, size); + } + int fd = AshmemCreate("Parcel RawData", size); + if (fd < 0) { + return false; + } + writeRawDataFd_ = fd; + + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + return false; + } + void *ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + return false; + } + if (!WriteFileDescriptor(fd)) { + ::munmap(ptr, size); + return false; + } + if (memcpy_s(ptr, size, data, size) != EOK) { + ::munmap(ptr, size); + return false; + } + kernelMappedWrite_ = ptr; + rawDataSize_ = size; + return true; +} + +bool MessageParcel::RestoreRawData(std::shared_ptr rawData, size_t size) +{ + if (rawData_ != nullptr || rawData == nullptr) { + return false; + } + rawData_ = rawData; + rawDataSize_ = size; + writeRawDataFd_ = 0; + return true; +} + +const void *MessageParcel::ReadRawData(size_t size) +{ + int32_t bufferSize = ReadInt32(); + if (static_cast(bufferSize) != size) { + return nullptr; + } + + if (static_cast(bufferSize) <= MIN_RAWDATA_SIZE) { + return ReadUnpadBuffer(size); + } + + /* if rawDataFd_ == 0 means rawData is received from remote + */ + if (rawData_ != nullptr && writeRawDataFd_ == 0) { + /* should read fd for move readCursor of parcel */ + if (ReadFileDescriptor()) { + // do nothing + } + if (rawDataSize_ != size) { + return nullptr; + } + return rawData_.get(); + } + int fd = ReadFileDescriptor(); + if (fd < 0) { + return nullptr; + } + readRawDataFd_ = fd; + + int ashmemSize = AshmemGetSize(fd); + if (ashmemSize < 0 || size_t(ashmemSize) < size) { + // do not close fd here. fd will be closed in FileDescriptor, ::close(fd) + return nullptr; + } + void *ptr = ::mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + // do not close fd here. fd will be closed in FileDescriptor, ::close(fd) + return nullptr; + } + kernelMappedRead_ = ptr; + rawDataSize_ = size; + return ptr; +} + +const void *MessageParcel::GetRawData() const +{ + if (rawData_ != nullptr) { + return rawData_.get(); + } + if (kernelMappedWrite_ != nullptr) { + return kernelMappedWrite_; + } + if (kernelMappedRead_ != nullptr) { + return kernelMappedRead_; + } + return nullptr; +} + +size_t MessageParcel::GetRawDataSize() const +{ + return rawDataSize_; +} + +size_t MessageParcel::GetRawDataCapacity() const +{ + return MAX_RAWDATA_SIZE; +} + +void MessageParcel::WriteNoException() +{ + WriteInt32(0); +} + +int32_t MessageParcel::ReadException() +{ + int32_t errorCode = ReadInt32(); + if (errorCode != 0) { + ReadString16(); + } + return errorCode; +} + +bool MessageParcel::WriteAshmem(sptr ashmem) +{ + int fd = ashmem->GetAshmemFd(); + int32_t size = ashmem->GetAshmemSize(); + if (fd < 0 || size <= 0) { + return false; + } + if (!WriteFileDescriptor(fd) || !WriteInt32(size)) { + return false; + } + return true; +} + +sptr MessageParcel::ReadAshmem() +{ + int fd = ReadFileDescriptor(); + if (fd < 0) { + return nullptr; + } + + int32_t size = ReadInt32(); + if (size <= 0) { + ::close(fd); + return nullptr; + } + return new Ashmem(fd, size); +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/peer_holder.cpp b/ipc/native/src/core/source/peer_holder.cpp new file mode 100755 index 00000000..c5c960e6 --- /dev/null +++ b/ipc/native/src/core/source/peer_holder.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "peer_holder.h" + +namespace OHOS { +PeerHolder::PeerHolder(const sptr &object) : remoteObject_(object) {} + +sptr PeerHolder::Remote() +{ + return remoteObject_; +} +} // namespace OHOS diff --git a/ipc/native/src/core/source/stub_refcount_object.cpp b/ipc/native/src/core/source/stub_refcount_object.cpp new file mode 100755 index 00000000..be265c8d --- /dev/null +++ b/ipc/native/src/core/source/stub_refcount_object.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "stub_refcount_object.h" + +namespace OHOS { +StubRefCountObject::StubRefCountObject(IRemoteObject *stub, int remotePid, const std::string &deviceId) + : stub_(stub), remotePid_(remotePid), deviceId_(deviceId) +{ +} + +StubRefCountObject::~StubRefCountObject() +{ + stub_ = nullptr; +} + +IRemoteObject *StubRefCountObject::GetStubObject() const +{ + return stub_; +} + +int StubRefCountObject::GetRemotePid() const +{ + return remotePid_; +} + +std::string StubRefCountObject::GetDeviceId() const +{ + return deviceId_; +} +} // namespace OHOS diff --git a/ipc/native/src/jni/include/jni_helper.h b/ipc/native/src/jni/include/jni_helper.h new file mode 100755 index 00000000..78b45ff1 --- /dev/null +++ b/ipc/native/src/jni/include/jni_helper.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_JNI_HELPERS_H +#define OHOS_IPC_JNI_HELPERS_H + +#include + +namespace OHOS { +class JNIEnvHelper { +public: + JNIEnvHelper(); + ~JNIEnvHelper(); + JNIEnv *Get(); + JNIEnv *operator->(); + static void nativeInit(JavaVM *vm); + +private: + JNIEnvHelper(const JNIEnvHelper &) = delete; + JNIEnvHelper &operator = (const JNIEnvHelper &) = delete; + +private: + JNIEnv *env_; + bool nativeThread_; + static JavaVM *javaVm_; +}; +void JniHelperThrowException(JNIEnv *env, const char *className, const char *msg); +void JniHelperThrowNullPointerException(JNIEnv *env, const char *msg); +void JniHelperThrowIllegalStateException(JNIEnv *env, const char *msg); + + +/* + * JNI may throws exception when native code call java scenario. + * we should convert local exception to native status code. + * Check and clear local exception. + */ +jboolean JniHelperCheckAndClearLocalException(JNIEnv *env); + +/* + * Get an int file descriptor from a java.io.FileDescriptor + */ +int JniHelperJavaIoGetFdFromFileDescriptor(JNIEnv *env, jobject fileDescriptor); + +/* + * Set the descriptor of a java.io.FileDescriptor + */ +void JniHelperJavaIoSetFdToFileDescriptor(JNIEnv *env, jobject fileDescriptor, int value); + +/* + * Create a java.io.FileDescriptor given an integer fd + */ +jobject JniHelperJavaIoCreateFileDescriptor(JNIEnv *env, int fd); + +int JniHelperRegisterNativeMethods(JNIEnv *env); +} // namespace OHOS +#endif // OHOS_IPC_JNI_HELPERS_H diff --git a/ipc/native/src/jni/include/jni_remote_object.h b/ipc/native/src/jni/include/jni_remote_object.h new file mode 100755 index 00000000..79de1f6b --- /dev/null +++ b/ipc/native/src/jni/include/jni_remote_object.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_JNI_REMOTE_OBJECT_H +#define OHOS_IPC_JNI_REMOTE_OBJECT_H + +#include +#include "refbase.h" +#include "iremote_object.h" + +namespace OHOS { +jobject GetJObjectFromRemoteObject(JNIEnv *env, const sptr &val); +sptr GetRemoteObjectFromJObject(JNIEnv *env, jobject obj); +} // namespace OHOS +#endif // OHOS_IPC_JNI_REMOTE_OBJECT_H diff --git a/ipc/native/src/jni/include/ohos_rpc_message_option.h b/ipc/native/src/jni/include/ohos_rpc_message_option.h new file mode 100755 index 00000000..4bcf2d56 --- /dev/null +++ b/ipc/native/src/jni/include/ohos_rpc_message_option.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_JNI_MESSAGE_OPTION_H +#define OHOS_IPC_JNI_MESSAGE_OPTION_H + +#include +#include +#include "message_option.h" + +namespace OHOS { +/* + * Get flags field from ohos.rpc.MessageOption. + */ +int JavaOhosRpcMessageOptionGetFlags(JNIEnv *env, jobject object); + +/* + * Set flags to ohos.rpc.MessageOption + */ +void JavaOhosRpcMessageOptionSetFlags(JNIEnv *env, jobject object, int flags); + +/* + * Get wait time field from ohos.rpc.MessageOption. + */ +int JavaOhosRpcMessageOptionGetWaitTime(JNIEnv *env, jobject object); + +/* + * Set wait time to ohos.rpc.MessageOption + */ +void JavaOhosRpcMessageOptionSetWaitTime(JNIEnv *env, jobject object, int waitTime); + +/* + * Create java object for ohos.rpc.MessageOption. + */ +jobject JavaOhosRpcMessageOptionNewJavaObject(JNIEnv *env, int flags, int waitTime); + +/* + * Get and create native instance of ohos.rpc.MessageOption. + */ +MessageOptionPtr JavaOhosRpcMessageOptionGetNative(JNIEnv *env, jobject object); + +/* + * register native methods for ohos.rpc.MessageOption. + */ +int JavaOhosRpcMessageOptionRegisterNativeMethods(JNIEnv *env); +} // namespace OHOS +#endif // OHOS_IPC_JNI_MESSAGE_OPTION_H \ No newline at end of file diff --git a/ipc/native/src/jni/include/ohos_rpc_message_parcel.h b/ipc/native/src/jni/include/ohos_rpc_message_parcel.h new file mode 100755 index 00000000..88e8fc56 --- /dev/null +++ b/ipc/native/src/jni/include/ohos_rpc_message_parcel.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_JNI_MESSAGE_PARCEL_H +#define OHOS_IPC_JNI_MESSAGE_PARCEL_H + +#include +#include "message_parcel.h" + +namespace OHOS { +/* + * register native methods for ohos.rpc.MessageParcel. + */ +int JavaOhosRpcMessageParcelRegisterNativeMethods(JNIEnv *env); +/* + * Get Native Message Parcel instance of ohos/rpc/MessageParcel + */ +MessageParcel *JavaOhosRpcMessageParcelGetNative(JNIEnv *env, jobject object); +} // namespace OHOS + +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeNewObject + * Signature: (J)J; + */ +jlong JNICALL Java_ohos_rpc_MessageParcel_nativeNewObject(JNIEnv *env, jobject object, jlong nativeObject); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeFreeObject + * Signature: (J)V; + */ +void JNICALL Java_ohos_rpc_MessageParcel_nativeFreeObject(JNIEnv *env, jobject object, jlong nativeObject); +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteRemoteObject + * Signature: (Lohos/rpc/IRemoteObject)Z + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteRemoteObject(JNIEnv *env, jobject parcel, jobject object); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadRemoteObject + * Signature: ()Lohos/rpc/IRemoteObject; + */ +jobject JNICALL Java_ohos_rpc_MessageParcel_nativeReadRemoteObject(JNIEnv *env, jobject object); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteFileDescriptor + * Signature: (LJava/io/FileDescriptor;)Z + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteFileDescriptor(JNIEnv *env, jobject object, jobject descriptor); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadFileDescriptor + * Signature: ()LJava/io/FileDescriptor; + */ +jobject JNICALL Java_ohos_rpc_MessageParcel_nativeReadFileDescriptor(JNIEnv *env, jobject object); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteInterfaceToken + * Signature: (LJava/io/String;)Z + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteInterfaceToken(JNIEnv *env, jobject object, jstring name, + jint len); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadInterfaceToken + * Signature: ()LJava/io/String; + */ +jobject JNICALL Java_ohos_rpc_MessageParcel_nativeReadInterfaceToken(JNIEnv *env, jobject object); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteRawData + * Signature: ()LJava/io/String; + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteRawData(JNIEnv *env, jobject object, jobject rawData, + jint size); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadRawData + * Signature: ()LJava/io/String; + */ +jbyteArray JNICALL Java_ohos_rpc_MessageParcel_nativeReadRawData(JNIEnv *env, jobject object, jint size); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeGetRawDataCapacity + * Signature: (V)I; + */ +jint JNICALL Java_ohos_rpc_MessageParcel_nativeGetRawDataCapacity(JNIEnv *env, jobject object); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeCloseFileDescriptor + * Signature: (LJava/io/FileDescriptor;)V + */ +void JNICALL Java_ohos_rpc_MessageParcel_nativeCloseFileDescriptor(JNIEnv *env, jobject object, jobject descriptor); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeDupFileDescriptor + * Signature: (LJava/io/FileDescriptor;)LJava/io/FileDescriptor; + */ +jobject JNICALL Java_ohos_rpc_MessageParcel_nativeDupFileDescriptor(JNIEnv *env, jobject object, jobject descriptor); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeContainFileDescriptors + * Signature: ()Z; + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeContainFileDescriptors(JNIEnv *env, jobject object); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteAshmem + * Signature: (J)Z + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteAshmem(JNIEnv *env, jobject object, jlong id); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadAshmem + * Signature: (V)J + */ +jlong JNICALL Java_ohos_rpc_MessageParcel_nativeReadAshmem(JNIEnv *env, jobject object); + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReleaseAshmem + * Signature: (J)V + */ +void JNICALL Java_ohos_rpc_MessageParcel_nativeReleaseAshmem(JNIEnv *env, jobject object, jlong id); +#ifdef __cplusplus +} +#endif +#endif // OHOS_IPC_JNI_MESSAGE_PARCEL_H diff --git a/ipc/native/src/jni/include/ohos_rpc_remote_object.h b/ipc/native/src/jni/include/ohos_rpc_remote_object.h new file mode 100755 index 00000000..fa26eaa4 --- /dev/null +++ b/ipc/native/src/jni/include/ohos_rpc_remote_object.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_JNI_REMOTE_OBJECT_H +#define OHOS_IPC_JNI_REMOTE_OBJECT_H + +#include +#include "refbase.h" +#include "iremote_object.h" + +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetContextObject + * Signature: (V)Lohos/rpc/IRemoteObject; + */ +jobject JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetContextObject(JNIEnv *env, jclass clazz); + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetCallingPid + * Signature: (V)I + */ +jint JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetCallingPid(JNIEnv *env, jclass clazz); + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetCallingUid + * Signature: (V)I + */ +jint JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetCallingUid(JNIEnv *env, jclass clazz); + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetCallingDeviceID + * Signature: (V)Lohos/rpc/IRemoteObject; + */ +jstring JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetCallingDeviceID(JNIEnv *env, jclass clazz); + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetLocalDeviceID + * Signature: (V)Lohos/rpc/IRemoteObject; + */ +jstring JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetLocalDeviceID(JNIEnv *env, jclass clazz); + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeIsLocalCalling + * Signature: (V)Z + */ +jboolean JNICALL Java_ohos_rpc_IPCSkeleton_nativeIsLocalCalling(JNIEnv *env, jclass clazz); + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeFlushCommands + * Signature: (Lohos/rpc/IRemoteObject;)I; + */ +jint JNICALL Java_ohos_rpc_IPCSkeleton_nativeFlushCommands(JNIEnv *env, jclass clazz, jobject object); + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeResetCallingIdentity + * Signature: (Lohos/rpc/IRemoteObject;)I; + */ +jstring JNICALL Java_ohos_rpc_IPCSkeleton_nativeResetCallingIdentity(JNIEnv *env, jclass clazz); + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeSetCallingIdentity + * Signature: (Lohos/rpc/IRemoteObject;)I; + */ +jboolean JNICALL Java_ohos_rpc_IPCSkeleton_nativeSetCallingIdentity(JNIEnv *env, jclass clazz, jstring identity, + jint len); + +/* + * Class: ohos.rpc.RemoteObject + * Method: nativeGetObjectHolder + * Signature: (Ljava/lang/String;I)J + */ +jlong JNICALL Java_ohos_rpc_RemoteObject_nativeGetObjectHolder(JNIEnv *env, jclass clazz, jstring value, jint len); + +/* + * Free local Object Holder of RemoteObject. + * Class: ohos.rpc.RemoteObject + * Method: nativeFreeObjectHolder + * Signature: (J)V + */ +void JNICALL Java_ohos_rpc_RemoteObject_nativeFreeObjectHolder(JNIEnv *env, jclass clazz, jlong holder); + +/* + * Get calling pid from native. + * Class: ohos.rpc.RemoteObject + * Method: nativeGetCallingPid + * Signature: (V)I + */ +jint JNICALL Java_ohos_rpc_RemoteObject_nativeGetCallingPid(JNIEnv *env, jclass object); + +/* + * Get calling UID from native. + * Class: ohos.rpc.RemoteObject + * Method: nativeGetCallingUid + * Signature: (V)I + */ +jint JNICALL Java_ohos_rpc_RemoteObject_nativeGetCallingUid(JNIEnv *env, jclass object); + +/* + * Class: ohos_rpc_RemoteProxy + * Method: nativeFreeProxyHolder + * Signature: (J)V + */ +void JNICALL Java_ohos_rpc_RemoteProxy_nativeFreeProxyHolder(JNIEnv *env, jclass clazz, jlong holder); + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeSendRequest + * Signature: (ILohos/rpc/MessageParcel;Lohos/rpc/Parcel;Lohos/rpc/MessageOption;)Z + */ +jboolean JNICALL Java_ohos_rpc_RemoteProxy_nativeSendRequest(JNIEnv *env, jobject object, jint code, jobject data, + jobject reply, jobject option); + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeAddDeathRecipient + * Signature: (Lohos/rpc/IRemoteObject$DeathRecipient;I)Z + */ +jboolean JNICALL Java_ohos_rpc_RemoteProxy_nativeAddDeathRecipient(JNIEnv *env, jobject clazz, jobject recipient, + jint flags); + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeRemoveDeathRecipient + * Signature: (Lohos/rpc/IRemoteObject$DeathRecipient;I)Z + */ +jboolean JNICALL Java_ohos_rpc_RemoteProxy_nativeRemoveDeathRecipient(JNIEnv *env, jobject clazz, jobject recipient, + jint flags); + +/* + * Class: ohos_rpc_RemoteProxy + * Method: nativeGetInterfaceDescriptor + * Signature: ()Ljava/lang/String; + */ +jstring JNICALL Java_ohos_rpc_RemoteProxy_nativeGetInterfaceDescriptor(JNIEnv *env, jobject clazz); + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeIsObjectDead + * Signature: (V)Z + */ +jboolean JNICALL Java_ohos_rpc_RemoteProxy_nativeIsObjectDead(JNIEnv *env, jobject object); + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeGetHandle + * Signature: (V)J + */ +jlong JNICALL Java_ohos_rpc_RemoteProxy_nativeGetHandle(JNIEnv *env, jobject object); + +#ifdef __cplusplus +} +#endif +namespace OHOS { +sptr Java_ohos_rpc_getNativeRemoteObject(JNIEnv *env, jobject object); + +jobject Java_ohos_rpc_getJavaRemoteObject(JNIEnv *env, const sptr target); +} // namespace OHOS +#endif // OHOS_IPC_JNI_REMOTE_OBJECT_H diff --git a/ipc/native/src/jni/source/jni_helper.cpp b/ipc/native/src/jni/source/jni_helper.cpp new file mode 100755 index 00000000..c6cf40e5 --- /dev/null +++ b/ipc/native/src/jni/source/jni_helper.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "jni_helper.h" +#include "ipc_debug.h" +#include "jni_help.h" +#include "ohos_rpc_remote_object.h" +#include "log_tags.h" + +namespace OHOS { +using namespace OHOS::HiviewDFX; + +struct JFileDescriptor { + jclass klazz; + jmethodID fileDescriptorCtor; + jfieldID descriptorField; +} g_jFileDescriptor; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCJniHelper" }; + +JavaVM *JNIEnvHelper::javaVm_ = nullptr; +// The JavaVM is a representation of the virtual machine on the JNI layer, +// one process has only one JavaVM, and all the threads share a JavaVM. +// JNIEnv is in effect only on the thread that it is created, +// cannot be passed across threads, different threads are independent of each other. +// In order to implement cross-threading calls, we need to transform between JNIENV and JavaVM +JNIEnvHelper::JNIEnvHelper() : env_ { nullptr }, nativeThread_ { false } +{ + if (javaVm_->GetEnv(reinterpret_cast(&env_), JNI_VERSION_1_4) == JNI_EDETACHED) { + javaVm_->AttachCurrentThread(reinterpret_cast(&env_), nullptr); + nativeThread_ = true; + } +} + +void JNIEnvHelper::nativeInit(JavaVM *vm) +{ + if (javaVm_ != nullptr) { + ZLOGE(LABEL, "Failed to init vm, javaVm_ has been initialized"); + return; + } + + javaVm_ = vm; +} + +JNIEnvHelper::~JNIEnvHelper() +{ + if (nativeThread_) { + javaVm_->DetachCurrentThread(); + } +} + +JNIEnv *JNIEnvHelper::Get() +{ + return env_; +} + +JNIEnv *JNIEnvHelper::operator->() +{ + return env_; +} + +void JniHelperThrowException(JNIEnv *env, const char *className, const char *msg) +{ + jclass clazz = env->FindClass(className); + if (!clazz) { + ZLOGE(LABEL, "Unable to find exception class %s", className); + /* ClassNotFoundException now pending */ + return; + } + + if (env->ThrowNew(clazz, msg) != JNI_OK) { + ZLOGE(LABEL, "Failed throwing '%s' '%s'", className, msg); + /* an exception, most likely OOM, will now be pending */ + } + + env->DeleteLocalRef(clazz); +} + +void JniHelperThrowNullPointerException(JNIEnv *env, const char *msg) +{ + JniHelperThrowException(env, "java/lang/NullPointerException", msg); +} + +void JniHelperThrowIllegalStateException(JNIEnv *env, const char *msg) +{ + JniHelperThrowException(env, "java/lang/IllegalStateException", msg); +} + +/* + * Get an int file descriptor from a java.io.FileDescriptor + */ +int JniHelperJavaIoGetFdFromFileDescriptor(JNIEnv *env, jobject fileDescriptor) +{ + return env->GetIntField(fileDescriptor, g_jFileDescriptor.descriptorField); +} + +/* + * Set the descriptor of a java.io.FileDescriptor + */ +void JniHelperJavaIoSetFdToFileDescriptor(JNIEnv *env, jobject fileDescriptor, int value) +{ + env->SetIntField(fileDescriptor, g_jFileDescriptor.descriptorField, value); +} + +/* + * JNI may throws exception when native code call java scenario. + * we should convert local exception to native status code. + * Check and clear local exception. + */ +jboolean JniHelperCheckAndClearLocalException(JNIEnv *env) +{ + jthrowable exception = env->ExceptionOccurred(); + if (exception != nullptr) { + ZLOGE(LABEL, "clean up JNI local ref"); + // clean up JNI local ref -- we don't return to Java code + env->ExceptionDescribe(); // for debug perpose. + env->ExceptionClear(); + env->DeleteLocalRef(exception); + return JNI_TRUE; + } + + return JNI_FALSE; +} + +/* + * Create a java.io.FileDescriptor given an integer fd + */ +jobject JniHelperJavaIoCreateFileDescriptor(JNIEnv *env, int fd) +{ + jobject descriptor = env->NewObject(g_jFileDescriptor.klazz, g_jFileDescriptor.fileDescriptorCtor); + JniHelperJavaIoSetFdToFileDescriptor(env, descriptor, fd); + return descriptor; +} + +int JniHelperRegisterNativeMethods(JNIEnv *env) +{ + g_jFileDescriptor.klazz = (jclass)env->NewGlobalRef(env->FindClass("java/io/FileDescriptor")); + if (g_jFileDescriptor.klazz == nullptr) { + return -1; + } + + g_jFileDescriptor.fileDescriptorCtor = env->GetMethodID(g_jFileDescriptor.klazz, "", "()V"); + if (g_jFileDescriptor.fileDescriptorCtor == nullptr) { + env->DeleteGlobalRef(g_jFileDescriptor.klazz); + return -1; + } + + g_jFileDescriptor.descriptorField = env->GetFieldID(g_jFileDescriptor.klazz, "descriptor", "I"); + if (g_jFileDescriptor.descriptorField == nullptr) { + env->DeleteGlobalRef(g_jFileDescriptor.klazz); + return -1; + } + + return 0; +} + +jobject JNIHelperGetJavaRemoteObject(JNIEnv *env, const sptr &target) +{ + if (env == nullptr) { + return nullptr; + } + return Java_ohos_rpc_getJavaRemoteObject(env, target); +} +} // namespace OHOS diff --git a/ipc/native/src/jni/source/ohos_rpc_message_option.cpp b/ipc/native/src/jni/source/ohos_rpc_message_option.cpp new file mode 100755 index 00000000..6b27c534 --- /dev/null +++ b/ipc/native/src/jni/source/ohos_rpc_message_option.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ohos_rpc_message_option.h" +#include "ipc_debug.h" +#include "log_tags.h" + +namespace OHOS { +struct JMessageOption { + jclass klazz; + jfieldID flagsField; + jfieldID waitTimeField; + jmethodID initMethod; +} g_jMessageOption; + +static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCJni" }; +/* + * Get flags field from ohos.rpc.MessageOption. + */ +int JavaOhosRpcMessageOptionGetFlags(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + if (g_jMessageOption.flagsField != nullptr) { + return env->GetIntField(object, g_jMessageOption.flagsField); + } + return 0; +} + +/* + * Get wait time field from ohos.rpc.MessageOption. + */ +int JavaOhosRpcMessageOptionGetWaitTime(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + if (g_jMessageOption.waitTimeField != nullptr) { + return env->GetIntField(object, g_jMessageOption.waitTimeField); + } + return 0; +} + +/* + * Set flags to ohos.rpc.MessageOption + */ +void JavaOhosRpcMessageOptionSetFlags(JNIEnv *env, jobject object, int flags) +{ + ZLOGI(LABEL, "%s", __func__); + env->SetIntField(object, g_jMessageOption.flagsField, flags); +} + +/* + * Set wait time to ohos.rpc.MessageOption + */ +void JavaOhosRpcMessageOptionSetWaitTime(JNIEnv *env, jobject object, int waitTime) +{ + ZLOGI(LABEL, "%s", __func__); + env->SetIntField(object, g_jMessageOption.waitTimeField, waitTime); +} + +/* + * Create java object for ohos.rpc.MessageOption. + */ +jobject JavaOhosRpcMessageOptionNewJavaObject(JNIEnv *env, int flags, int waitTime) +{ + ZLOGI(LABEL, "%s", __func__); + jobject option = env->NewObject(g_jMessageOption.klazz, g_jMessageOption.initMethod, flags, waitTime); + return option; +} + +/* + * Get and create native instance of ohos.rpc.MessageOption. + */ +MessageOptionPtr JavaOhosRpcMessageOptionGetNative(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + int flags = JavaOhosRpcMessageOptionGetFlags(env, object); + int waitTime = JavaOhosRpcMessageOptionGetWaitTime(env, object); + auto option = std::make_shared(); + option->SetFlags(flags); + option->SetWaitTime(waitTime); + return option; +} + +/* + * register native methods fopr ohos.rpc.MessageOption. + */ +int JavaOhosRpcMessageOptionRegisterNativeMethods(JNIEnv *env) +{ + ZLOGI(LABEL, "%s", __func__); + jclass klazz = (jclass)env->NewGlobalRef(env->FindClass("ohos/rpc/MessageOption")); + if (klazz == nullptr) { + ZLOGE(LABEL, "could not find class for MessageOption"); + return -1; + } + g_jMessageOption.klazz = (jclass)env->NewGlobalRef(klazz); + g_jMessageOption.initMethod = env->GetMethodID(g_jMessageOption.klazz, "", "(II)V"); + if (g_jMessageOption.initMethod == nullptr) { + ZLOGE(LABEL, "could not get initMethod from MessageOption"); + if (g_jMessageOption.klazz != nullptr) { + env->DeleteGlobalRef(g_jMessageOption.klazz); + } + env->DeleteGlobalRef(klazz); + return -1; + } + + g_jMessageOption.flagsField = env->GetFieldID(g_jMessageOption.klazz, "mFlags", "I"); + if (g_jMessageOption.flagsField == nullptr) { + ZLOGE(LABEL, "could not get flags fields from MessageOption"); + if (g_jMessageOption.klazz != nullptr) { + env->DeleteGlobalRef(g_jMessageOption.klazz); + } + env->DeleteGlobalRef(klazz); + return -1; + } + + g_jMessageOption.waitTimeField = env->GetFieldID(g_jMessageOption.klazz, "mWaitTime", "I"); + if (g_jMessageOption.waitTimeField == nullptr) { + ZLOGE(LABEL, "could not get mWaitTime fields from MessageOption"); + if (g_jMessageOption.klazz != nullptr) { + env->DeleteGlobalRef(g_jMessageOption.klazz); + } + env->DeleteGlobalRef(klazz); + return -1; + } + return 0; +} +} // namespace OHOS \ No newline at end of file diff --git a/ipc/native/src/jni/source/ohos_rpc_message_parcel.cpp b/ipc/native/src/jni/source/ohos_rpc_message_parcel.cpp new file mode 100755 index 00000000..29031817 --- /dev/null +++ b/ipc/native/src/jni/source/ohos_rpc_message_parcel.cpp @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ohos_rpc_message_parcel.h" +#include +#include +#include "ipc_debug.h" +#include "jni_helper.h" +#include "ohos_utils_parcel.h" +#include "ohos_rpc_remote_object.h" +#include "ipc_file_descriptor.h" +#include "log_tags.h" +#include "jkit_utils.h" +#include + +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +namespace OHOS { +struct JMessageParcel { + jclass klazz; + jfieldID nativeObject; + jfieldID nativeObjectOwner; +} g_jMessageParcel; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCJni" }; + +class AshmemSmartPointWrapper { +public: + explicit AshmemSmartPointWrapper(const sptr &ashmem) : ashmem_(ashmem) + { + if (ashmem == nullptr) { + ZLOGE(LABEL, "%s: ashmem is null", __func__); + } + } + ~AshmemSmartPointWrapper() = default; + + const sptr &GetAshmem() const + { + return ashmem_; + } + +private: + // make sure this is immutable + sptr const ashmem_; +}; + +/* + * Get Native Message Parcel instance of zindaneos/rpc/MessageParcel + */ +MessageParcel *JavaOhosRpcMessageParcelGetNative(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + jlong nativeObject = env->GetLongField(object, g_jMessageParcel.nativeObject); + return reinterpret_cast(nativeObject); +} + +sptr Java_ohos_rpc_Ashmem_getSptrAshmem(JNIEnv *env, jobject object, jlong id) +{ + if (id == 0) { + return nullptr; + } + AshmemSmartPointWrapper *wrapper = reinterpret_cast(id); + return wrapper->GetAshmem(); +} + +static const JNINativeMethod sMethods[] = { + /* Name, Signature, FunctionPointer */ + { "nativeNewObject", "(J)J", (void *)Java_ohos_rpc_MessageParcel_nativeNewObject }, + { "nativeFreeObject", "(J)V", (void *)Java_ohos_rpc_MessageParcel_nativeFreeObject }, + { "nativeWriteRemoteObject", "(Lohos/rpc/IRemoteObject;)Z", + (void *)Java_ohos_rpc_MessageParcel_nativeWriteRemoteObject }, + { "nativeReadRemoteObject", "()Lohos/rpc/IRemoteObject;", + (void *)Java_ohos_rpc_MessageParcel_nativeReadRemoteObject }, + { "nativeWriteFileDescriptor", "(Ljava/io/FileDescriptor;)Z", + (void *)Java_ohos_rpc_MessageParcel_nativeWriteFileDescriptor }, + { "nativeReadFileDescriptor", "()Ljava/io/FileDescriptor;", + (void *)Java_ohos_rpc_MessageParcel_nativeReadFileDescriptor }, + { "nativeWriteInterfaceToken", "(Ljava/lang/String;I)Z", + (void *)Java_ohos_rpc_MessageParcel_nativeWriteInterfaceToken }, + { "nativeReadInterfaceToken", "()Ljava/lang/String;", + (void *)Java_ohos_rpc_MessageParcel_nativeReadInterfaceToken }, + { "nativeWriteRawData", "([BI)Z", (void *)Java_ohos_rpc_MessageParcel_nativeWriteRawData }, + { "nativeReadRawData", "(I)[B", (void *)Java_ohos_rpc_MessageParcel_nativeReadRawData }, + { "nativeGetRawDataCapacity", "()I", (void *)Java_ohos_rpc_MessageParcel_nativeGetRawDataCapacity }, + { "nativeCloseFileDescriptor", "(Ljava/io/FileDescriptor;)V", + (void *)Java_ohos_rpc_MessageParcel_nativeCloseFileDescriptor }, + { "nativeDupFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", + (void *)Java_ohos_rpc_MessageParcel_nativeDupFileDescriptor }, + { "nativeContainFileDescriptors", "()Z", (void *)Java_ohos_rpc_MessageParcel_nativeContainFileDescriptors }, + { "nativeWriteAshmem", "(J)Z", (void *)Java_ohos_rpc_MessageParcel_nativeWriteAshmem }, + { "nativeReadAshmem", "()J", (void *)Java_ohos_rpc_MessageParcel_nativeReadAshmem }, + { "nativeReleaseAshmem", "(J)V", (void *)Java_ohos_rpc_MessageParcel_nativeReleaseAshmem }, +}; + +/* + * register native methods fopr ohos.rpc.MessageParcel. + */ +int JavaOhosRpcMessageParcelRegisterNativeMethods(JNIEnv *env) +{ + ZLOGI(LABEL, "%s", __func__); + jclass klazz = (jclass)env->NewGlobalRef(env->FindClass("ohos/rpc/MessageParcel")); + if (klazz == nullptr) { + ZLOGE(LABEL, "could not find class for MessageParcel"); + return -1; + } + g_jMessageParcel.klazz = (jclass)env->NewGlobalRef(klazz); + g_jMessageParcel.nativeObject = env->GetFieldID(g_jMessageParcel.klazz, "mNativeObject", "J"); + if (g_jMessageParcel.nativeObject == nullptr) { + ZLOGE(LABEL, "could not Get mNativeObject field for MessageParcel"); + if (g_jMessageParcel.klazz != nullptr) { + env->DeleteGlobalRef(g_jMessageParcel.klazz); + } + env->DeleteGlobalRef(klazz); + return -1; + } + g_jMessageParcel.nativeObjectOwner = env->GetFieldID(g_jMessageParcel.klazz, "mOwnsNativeObject", "Z"); + if (g_jMessageParcel.nativeObjectOwner == nullptr) { + ZLOGE(LABEL, "could not Get mOwnsNativeObject field for MessageParcel"); + if (g_jMessageParcel.klazz != nullptr) { + env->DeleteGlobalRef(g_jMessageParcel.klazz); + } + env->DeleteGlobalRef(klazz); + return -1; + } + return JkitRegisterNativeMethods(env, "ohos/rpc/MessageParcel", sMethods, NUM_METHODS(sMethods)); +} +} // namespace OHOS + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteRemoteObject + * Signature: (Lohos/rpc/IRemoteObject;)Z + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteRemoteObject(JNIEnv *env, jobject parcel, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, parcel); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for marshalling"); + return JNI_FALSE; + } + + sptr target = Java_ohos_rpc_getNativeRemoteObject(env, object); + if (target != nullptr) { + if (nativeParcel->WriteRemoteObject(target)) { + return JNI_TRUE; + } + } + return JNI_FALSE; +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadRemoteObject + * Signature: ()Lohos/rpc/IRemoteObject; + */ +jobject JNICALL Java_ohos_rpc_MessageParcel_nativeReadRemoteObject(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for unmarshalling"); + return nullptr; + } + + return Java_ohos_rpc_getJavaRemoteObject(env, nativeParcel->ReadRemoteObject()); +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteFileDescriptor + * Signature: (Ljava/io/FileDescriptor;)Z + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteFileDescriptor(JNIEnv *env, jobject object, jobject descriptor) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for marshalling"); + return JNI_FALSE; + } + + int fd = JniHelperJavaIoGetFdFromFileDescriptor(env, descriptor); + return fd > 0 ? nativeParcel->WriteFileDescriptor(fd) : JNI_FALSE; +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadFileDescriptor + * Signature: ()Ljava/io/FileDescriptor; + */ +jobject JNICALL Java_ohos_rpc_MessageParcel_nativeReadFileDescriptor(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "unable to get native parcel"); + return nullptr; + } + + int fd = nativeParcel->ReadFileDescriptor(); + if (fd != INVALID_FD) { + return JniHelperJavaIoCreateFileDescriptor(env, fd); + } + + ZLOGE(LABEL, "Got invalid fd from parcel"); + return nullptr; +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeContainFileDescriptors + * Signature: ()Z; + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeContainFileDescriptors(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "unable to get native parcel"); + return JNI_FALSE; + } + + bool result = nativeParcel->ContainFileDescriptors(); + return result ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteInterfaceToken + * Signature: (Ljava/lang/String;I)Z + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteInterfaceToken(JNIEnv *env, jobject object, jstring name, + jint len) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for marshalling"); + return JNI_FALSE; + } + + bool result = false; + const jchar *u16chars = env->GetStringCritical(name, 0); + if (u16chars != nullptr) { + const auto *u16Str = reinterpret_cast(u16chars); + result = nativeParcel->WriteInterfaceToken(std::u16string(u16Str, len)); + env->ReleaseStringCritical(name, u16chars); + } + + return result ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadInterfaceToken + * Signature: ()Ljava/lang/String; + */ +jobject JNICALL Java_ohos_rpc_MessageParcel_nativeReadInterfaceToken(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for marshalling"); + return JNI_FALSE; + } + + std::u16string name = nativeParcel->ReadInterfaceToken(); + return env->NewString(reinterpret_cast(name.data()), name.size()); +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteRawData + * Signature: ([BI)Z + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteRawData(JNIEnv *env, jobject object, jobject rawData, jint size) +{ + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for raw data"); + return JNI_FALSE; + } + + jbyte *ptr = static_cast(env->GetPrimitiveArrayCritical(static_cast(rawData), 0)); + if (ptr == nullptr) { + return JNI_FALSE; + } + bool result = nativeParcel->WriteRawData(ptr, size); + env->ReleasePrimitiveArrayCritical(static_cast(rawData), ptr, 0); + return result ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadRawData + * Signature: (I)[B + */ +jbyteArray JNICALL Java_ohos_rpc_MessageParcel_nativeReadRawData(JNIEnv *env, jobject object, jint size) +{ + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for rawData"); + return nullptr; + } + + const void *rawData = nativeParcel->ReadRawData(size); + if (rawData == nullptr) { + ZLOGE(LABEL, "read raw data failed"); + return nullptr; + } + jbyteArray bytes = env->NewByteArray(size); + if (bytes == nullptr) { + ZLOGE(LABEL, "NewByteArray failed"); + return nullptr; + } + jbyte *ptr = static_cast(env->GetPrimitiveArrayCritical(bytes, 0)); + if (ptr != nullptr) { + int result = memcpy_s(ptr, size, rawData, size); + env->ReleasePrimitiveArrayCritical(bytes, ptr, 0); + if (result != 0) { + ZLOGE(LABEL, "copy raw data failed"); + env->DeleteLocalRef(bytes); + return nullptr; + } + } + return bytes; +} + + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeGetRawDataCapacity + * Signature: ()I; + */ +jint JNICALL Java_ohos_rpc_MessageParcel_nativeGetRawDataCapacity(JNIEnv *env, jobject object) +{ + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for rawData"); + return 0; + } + + return static_cast(nativeParcel->GetRawDataCapacity()); +} + +/* + * Set mOwnsNativeObject filed to ohos.rpc.MessageParcel + */ +void JavaOhosRpcMessageOptionSetNativeObjectOwner(JNIEnv *env, jobject object, jboolean value) +{ + ZLOGI(LABEL, "%s", __func__); + env->SetBooleanField(object, g_jMessageParcel.nativeObjectOwner, value); +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeNewObject + * Signature: (J)J; + */ +jlong JNICALL Java_ohos_rpc_MessageParcel_nativeNewObject(JNIEnv *env, jobject object, jlong nativeObject) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeMessageParcel = nullptr; + if (nativeObject != 0) { + nativeMessageParcel = reinterpret_cast(nativeObject); + JavaOhosRpcMessageOptionSetNativeObjectOwner(env, object, JNI_FALSE); + } else { + JavaOhosRpcMessageOptionSetNativeObjectOwner(env, object, JNI_TRUE); + nativeMessageParcel = new MessageParcel(); + } + + if (nativeMessageParcel == nullptr) { + return 0L; + } + jclass superClass = env->GetSuperclass(g_jMessageParcel.klazz); + if (superClass == nullptr) { + ZLOGE(LABEL, "get supper class for MessageParcel failed"); + delete nativeMessageParcel; + return 0L; + } + + jmethodID superInit = env->GetMethodID(superClass, "", "(J)V"); + if (superInit == nullptr) { + ZLOGE(LABEL, "get supper method for MessageParcel failed"); + delete nativeMessageParcel; + return 0L; + } + Parcel *nativeParcel = static_cast(nativeMessageParcel); + ZLOGI(LABEL, "intSuperClass's native holder:%s", __func__); + env->CallNonvirtualVoidMethod(object, superClass, superInit, reinterpret_cast(nativeParcel)); + + return reinterpret_cast(nativeMessageParcel); +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeFreeObject + * Signature: (J)V; + */ +void JNICALL Java_ohos_rpc_MessageParcel_nativeFreeObject(JNIEnv *env, jobject object, jlong nativeObject) +{ + ZLOGI(LABEL, "%s", __func__); + std::unique_ptr nativeParcel(reinterpret_cast(nativeObject)); +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeCloseFileDescriptor + * Signature: (Ljava/io/FileDescriptor;)V + */ +void JNICALL Java_ohos_rpc_MessageParcel_nativeCloseFileDescriptor(JNIEnv *env, jobject object, jobject descriptor) +{ + ZLOGI(LABEL, "%s", __func__); + if (descriptor != nullptr) { + int fd = JniHelperJavaIoGetFdFromFileDescriptor(env, descriptor); + if (fd != INVALID_FD) { + close(fd); + JniHelperJavaIoSetFdToFileDescriptor(env, descriptor, INVALID_FD); + } + } +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeDupFileDescriptor + * Signature: (Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor; + */ +jobject JNICALL Java_ohos_rpc_MessageParcel_nativeDupFileDescriptor(JNIEnv *env, jobject object, jobject descriptor) +{ + ZLOGI(LABEL, "%s", __func__); + if (descriptor != nullptr) { + int fd = JniHelperJavaIoGetFdFromFileDescriptor(env, descriptor); + int dupFd = INVALID_FD; + if (fd != INVALID_FD) { + dupFd = dup(fd); + } + if (dupFd != INVALID_FD) { + return JniHelperJavaIoCreateFileDescriptor(env, dupFd); + } + } + return nullptr; +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeWriteAshmem + * Signature: (J)Z + */ +jboolean JNICALL Java_ohos_rpc_MessageParcel_nativeWriteAshmem(JNIEnv *env, jobject object, jlong id) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for raw data"); + return JNI_FALSE; + } + + sptr ashmem = Java_ohos_rpc_Ashmem_getSptrAshmem(env, object, id); + if (ashmem == nullptr) { + ZLOGE(LABEL, "%s: ashmem=null", __func__); + return JNI_FALSE; + } + + bool result = nativeParcel->WriteAshmem(ashmem); + return result ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReadAshmem + * Signature: (V)J + */ +jlong JNICALL Java_ohos_rpc_MessageParcel_nativeReadAshmem(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeParcel = JavaOhosRpcMessageParcelGetNative(env, object); + if (nativeParcel == nullptr) { + ZLOGE(LABEL, "could not get native parcel for rawData"); + return 0; + } + + sptr nativeAshmem = nativeParcel->ReadAshmem(); + if (nativeAshmem == nullptr) { + ZLOGE(LABEL, "read raw data failed"); + return 0; + } + + // memory is released in Java_ohos_rpc_MessageParcel_nativeReleaseAshmem + AshmemSmartPointWrapper *wrapper = new AshmemSmartPointWrapper(nativeAshmem); + return reinterpret_cast(wrapper); +} + +/* + * Class: ohos.rpc.MessageParcel + * Method: nativeReleaseAshmem + * Signature: (J)V + */ +void JNICALL Java_ohos_rpc_MessageParcel_nativeReleaseAshmem(JNIEnv *env, jobject object, jlong id) +{ + ZLOGI(LABEL, "%s", __func__); + if (id == 0) { + return; + } + std::unique_ptr nativeParcel(reinterpret_cast(id)); +} diff --git a/ipc/native/src/jni/source/ohos_rpc_remote_object.cpp b/ipc/native/src/jni/source/ohos_rpc_remote_object.cpp new file mode 100755 index 00000000..29c00f10 --- /dev/null +++ b/ipc/native/src/jni/source/ohos_rpc_remote_object.cpp @@ -0,0 +1,982 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ohos_rpc_remote_object.h" +#include +#include +#include "ipc_debug.h" +#include "jni_helper.h" +#include "ohos_utils_parcel.h" +#include "ohos_rpc_message_option.h" +#include "ohos_rpc_message_parcel.h" +#include "ipc_object_stub.h" +#include "ipc_object_proxy.h" +#include "ipc_thread_skeleton.h" +#include "ipc_skeleton.h" +#include "ipc_types.h" +#include "log_tags.h" +#include "jkit_utils.h" + +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +namespace OHOS { +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCJni" }; + +class JDeathRecipientList; +class JRemoteObjectHolder; +struct JRemoteObjectDesc { + jclass klass; + jmethodID methodDispatchRequest; + jfieldID fieldNativeHolder; + jmethodID methodDispatchDump; +}; + +struct JRemoteProxyDesc { + jclass klass; + jmethodID methodGetInstance; + jmethodID methodSendObituary; + jfieldID fieldNativeData; +}; + +class JRemoteProxyHolder { +public: + JRemoteProxyHolder(); + ~JRemoteProxyHolder(); + sptr list_; + sptr object_; +}; +/* + * the native RemoteObject act as bridger between java and native. + * It received the request from client and pass it Java Layer. + */ +class JRemoteObject : public IPCObjectStub { +public: + JRemoteObject(jobject object, const std::u16string &descriptor); + + ~JRemoteObject() override; + + bool CheckObjectLegality() const override; + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + int OnRemoteDump(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + jobject GetJObject() const; + +private: + jobject object_; +}; + +/* + * To ensure a better consistency of the life time of + * Java IPC Object and native object we designed + * a container to save the native object. + */ +class JRemoteObjectHolder : public RefBase { +public: + explicit JRemoteObjectHolder(const std::u16string &descriptor); + ~JRemoteObjectHolder(); + sptr Get(jobject object); + +private: + std::mutex mutex_; + std::u16string descriptor_; + sptr cachedObject_; +}; + +/* + * the native DeathRecipient container. + * As an recipient of Obituary of service death. + * and pass the message to Java Layer. + */ +class JDeathRecipient : public IRemoteObject::DeathRecipient { +public: + explicit JDeathRecipient(jobject object); + + void OnRemoteDied(const wptr &object) override; + + bool Matches(jobject object); + +protected: + virtual ~JDeathRecipient(); + +private: + std::mutex mutex_; + jobject refObject_; + jweak weakRefObject_ {}; +}; + +/* + * the native DeathRecipient container + */ +class JDeathRecipientList : public RefBase { + std::set> set_; + std::mutex mutex_; + +public: + JDeathRecipientList(); + + ~JDeathRecipientList(); + + bool Add(const sptr &recipient); + + bool Remove(const sptr &recipient); + + sptr Find(jobject recipient); +}; + +// Global variable definition. +static JRemoteProxyHolder *g_cachedProxyHolder; +static struct JRemoteObjectDesc g_jRemoteStub; +static struct JRemoteProxyDesc g_jRemoteProxy; +static std::mutex g_proxyMutex_; +static bool g_ipcNativeMethodsLoaded = false; + +JRemoteObject::JRemoteObject(jobject object, const std::u16string &descriptor) : IPCObjectStub(descriptor) +{ + JNIEnvHelper env; + if (env.Get() != nullptr && object != nullptr) { + object_ = env->NewGlobalRef(object); + } else { + object_ = nullptr; + } +} + +bool JRemoteObject::CheckObjectLegality() const +{ + return true; +} + +JRemoteObject::~JRemoteObject() +{ + JNIEnvHelper env; + if (env.Get() != nullptr && object_ != nullptr) { + env->DeleteGlobalRef(object_); + } +} + +jobject JRemoteObject::GetJObject() const +{ + return object_; +} + +int JRemoteObject::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + JNIEnvHelper env; + if (env.Get() == nullptr) { + return ERR_TRANSACTION_FAILED; + } + + if (code == DUMP_TRANSACTION) { + ZLOGE(LABEL, "DUMP_TRANSACTION data size:%zu", data.GetReadableBytes()); + } + + jobject javaOption = JavaOhosRpcMessageOptionNewJavaObject(env.Get(), option.GetFlags(), option.GetWaitTime()); + jboolean res = env->CallBooleanMethod(object_, g_jRemoteStub.methodDispatchRequest, code, + reinterpret_cast(&data), reinterpret_cast(&reply), javaOption); + + env->DeleteLocalRef(javaOption); + if (JniHelperCheckAndClearLocalException(env.Get())) { + ZLOGE(LABEL, "OnRemoteRequest found exception, res:%{public}d", res); + return ERR_UNKNOWN_TRANSACTION; + } + if (code == SYSPROPS_TRANSACTION) { + int result = IPCObjectStub::OnRemoteRequest(code, data, reply, option); + if (result != ERR_NONE) { + ZLOGE(LABEL, "OnRemoteRequest res:%{public}d", result); + return ERR_INVALID_DATA; + } + } + if (!res) { + ZLOGE(LABEL, "OnRemoteRequest res:%{public}d", res); + return ERR_UNKNOWN_TRANSACTION; + } + return ERR_NONE; +} + +int JRemoteObject::OnRemoteDump(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + JNIEnvHelper env; + if (env.Get() == nullptr) { + return ERR_TRANSACTION_FAILED; + } + + jobject javaOption = JavaOhosRpcMessageOptionNewJavaObject(env.Get(), option.GetFlags(), option.GetWaitTime()); + jboolean res = env->CallBooleanMethod(object_, g_jRemoteStub.methodDispatchDump, code, + reinterpret_cast(&data), reinterpret_cast(&reply), javaOption); + + if (JniHelperCheckAndClearLocalException(env.Get())) { + res = JNI_FALSE; + } + env->DeleteLocalRef(javaOption); + ZLOGI(LABEL, "OnRemoteDump res:%d", res); + return res ? ERR_NONE : ERR_UNKNOWN_TRANSACTION; +} + +JRemoteObjectHolder::JRemoteObjectHolder(const std::u16string &descriptor) + : descriptor_(descriptor), cachedObject_(nullptr) +{} + +JRemoteObjectHolder::~JRemoteObjectHolder() +{ + // free the reference of object. + cachedObject_ = nullptr; +} + +sptr JRemoteObjectHolder::Get(jobject object) +{ + std::lock_guard lockGuard(mutex_); + // grab an strong reference to the object, + // so it will not be freed util this reference released. + sptr remoteObject = nullptr; + if (cachedObject_ != nullptr) { + remoteObject = cachedObject_; + } + + if (remoteObject == nullptr) { + remoteObject = new JRemoteObject(object, descriptor_); + cachedObject_ = remoteObject; + } + return remoteObject; +} + +JRemoteProxyHolder::JRemoteProxyHolder() : list_(nullptr), object_(nullptr) {} + +JRemoteProxyHolder::~JRemoteProxyHolder() +{ + list_ = nullptr; + object_ = nullptr; +} + +JDeathRecipient::JDeathRecipient(jobject object) +{ + JNIEnvHelper env; + if (env.Get() != nullptr) { + refObject_ = env->NewGlobalRef(object); + } else { + refObject_ = nullptr; + } +} + +void JDeathRecipient::OnRemoteDied(const wptr &object) +{ + ZLOGI(LABEL, "OnRemoteDied called"); + if (refObject_ == nullptr) { + ZLOGE(LABEL, "Object has already removed"); + return; + } + + JNIEnvHelper env; + if (env.Get() == nullptr) { + return; + } + + env->CallStaticVoidMethod(g_jRemoteProxy.klass, g_jRemoteProxy.methodSendObituary, refObject_); + JniHelperCheckAndClearLocalException(env.Get()); + + weakRefObject_ = env->NewWeakGlobalRef(refObject_); + env->DeleteGlobalRef(refObject_); + std::lock_guard lockGuard(mutex_); + refObject_ = nullptr; +} + +bool JDeathRecipient::Matches(jobject object) +{ + JNIEnvHelper env; + if (env.Get() == nullptr) { + return false; + } + + bool result = false; + if (object != nullptr) { + std::lock_guard lockGuard(mutex_); + if (refObject_ != nullptr) { + result = env->IsSameObject(object, refObject_); + } + } else { + if (weakRefObject_ == nullptr) { + return false; + } + jobject me = env->NewLocalRef(weakRefObject_); + result = env->IsSameObject(object, me); + env->DeleteLocalRef(me); + } + return result; +} + +JDeathRecipient::~JDeathRecipient() +{ + JNIEnvHelper env; + + if (env.Get() != nullptr) { + if (refObject_ != nullptr) { + env->DeleteGlobalRef(refObject_); + } else { + if (weakRefObject_ != nullptr) { + env->DeleteWeakGlobalRef(weakRefObject_); + } + } + } +} + +JDeathRecipientList::JDeathRecipientList() {} + +JDeathRecipientList::~JDeathRecipientList() +{ + std::lock_guard lockGuard(mutex_); + set_.clear(); +} + +bool JDeathRecipientList::Add(const sptr &recipient) +{ + std::lock_guard lockGuard(mutex_); + auto ret = set_.insert(recipient); + return ret.second; +} + +bool JDeathRecipientList::Remove(const sptr &recipient) +{ + std::lock_guard lockGuard(mutex_); + return (set_.erase(recipient) > 0); +} + +sptr JDeathRecipientList::Find(jobject recipient) +{ + std::lock_guard lockGuard(mutex_); + + for (auto it = set_.begin(); it != set_.end(); it++) { + if ((*it)->Matches(recipient)) { + return *it; + } + } + return nullptr; +} + +JRemoteProxyHolder *Java_ohos_rpc_getRemoteProxyHolder(JNIEnv *env, jobject object) +{ + return reinterpret_cast(env->GetLongField(object, g_jRemoteProxy.fieldNativeData)); +} + +jobject Java_ohos_rpc_getJavaRemoteObject(JNIEnv *env, const sptr target) +{ + ZLOGI(LABEL, "%s", __func__); + if (target == nullptr) { + ZLOGE(LABEL, "RemoteObject is null"); + return nullptr; + } + + if (target->CheckObjectLegality()) { + ZLOGI(LABEL, "native Get RemoteObject"); + auto object = static_cast(target.GetRefPtr()); + return object->GetJObject(); + } + + std::lock_guard lockGuard(g_proxyMutex_); + JRemoteProxyHolder *cachedHolder = g_cachedProxyHolder; + if (cachedHolder == nullptr) { + cachedHolder = new JRemoteProxyHolder(); + } + + jobject object = env->CallStaticObjectMethod(g_jRemoteProxy.klass, g_jRemoteProxy.methodGetInstance, + reinterpret_cast(cachedHolder)); + + if (JniHelperCheckAndClearLocalException(env)) { + if (g_cachedProxyHolder == nullptr) { + delete cachedHolder; + } + return nullptr; + } + + JRemoteProxyHolder *objectHolder = Java_ohos_rpc_getRemoteProxyHolder(env, object); + // If the objects holder is same as the cached holder it should be a new create holder. + if (cachedHolder == objectHolder) { + objectHolder->object_ = target; + objectHolder->list_ = new JDeathRecipientList(); + g_cachedProxyHolder = nullptr; + } else { + g_cachedProxyHolder = cachedHolder; + } + return object; +} + +sptr Java_ohos_rpc_getNativeRemoteObject(JNIEnv *env, jobject object) +{ + ZLOGI(LABEL, "%s", __func__); + if (object != nullptr) { + if (env->IsInstanceOf(object, g_jRemoteStub.klass)) { + JRemoteObjectHolder *holder = + reinterpret_cast(env->GetLongField(object, g_jRemoteStub.fieldNativeHolder)); + return holder != nullptr ? holder->Get(object) : nullptr; + } + + if (env->IsInstanceOf(object, g_jRemoteProxy.klass)) { + JRemoteProxyHolder *holder = Java_ohos_rpc_getRemoteProxyHolder(env, object); + return holder != nullptr ? holder->object_ : nullptr; + } + } + return nullptr; +} +} // namespace OHOS + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetContextObject + * Signature: ()Lohos/rpc/IRemoteObject; + */ +jobject JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetContextObject(JNIEnv *env, jclass clazz) +{ + ZLOGI(LABEL, "%s", __func__); + sptr object = IPCSkeleton::GetContextObject(); + if (object == nullptr) { + ZLOGE(LABEL, "fatal error, could not get registry object"); + return nullptr; + } + return Java_ohos_rpc_getJavaRemoteObject(env, object); +} + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetCallingPid + * Signature: ()I; + */ +jint JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetCallingPid(JNIEnv *env, jclass clazz) +{ + pid_t pid = IPCSkeleton::GetCallingPid(); + return static_cast(pid); +} + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetCallingUid + * Signature: ()I; + */ +jint JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetCallingUid(JNIEnv *env, jclass clazz) +{ + uid_t uid = IPCSkeleton::GetCallingUid(); + return static_cast(uid); +} + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetCallingDeviceID + * Signature: (V)Ljava/lang/String; + */ +jstring JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetCallingDeviceID(JNIEnv *env, jclass clazz) +{ + std::string deviceId = IPCSkeleton::GetCallingDeviceID(); + return env->NewStringUTF(deviceId.c_str()); +} + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeGetLocalDeviceID + * Signature: (V)Ljava/lang/String; + */ +jstring JNICALL Java_ohos_rpc_IPCSkeleton_nativeGetLocalDeviceID(JNIEnv *env, jclass clazz) +{ + std::string deviceId = IPCSkeleton::GetLocalDeviceID(); + return env->NewStringUTF(deviceId.c_str()); +} + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeIsLocalCalling + * Signature: ()Z; + */ +jboolean JNICALL Java_ohos_rpc_IPCSkeleton_nativeIsLocalCalling(JNIEnv *env, jclass clazz) +{ + return (IPCSkeleton::IsLocalCalling() == true) ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeIsLocalCalling + * Signature: (Lohos/rpc/IRemoteObject;)I; + */ +jint JNICALL Java_ohos_rpc_IPCSkeleton_nativeFlushCommands(JNIEnv *env, jclass clazz, jobject object) +{ + sptr target = Java_ohos_rpc_getNativeRemoteObject(env, object); + return static_cast(IPCSkeleton::FlushCommands(target)); +} + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeResetCallingIdentity + * Signature: ()Ljava/lang/String; + */ +jstring JNICALL Java_ohos_rpc_IPCSkeleton_nativeResetCallingIdentity(JNIEnv *env, jclass clazz) +{ + std::string identity = IPCSkeleton::ResetCallingIdentity(); + return env->NewStringUTF(identity.c_str()); +} + +/* + * Class: ohos.rpc.IPCSkeleton + * Method: nativeSetCallingIdentity + * Signature: ((Ljava/lang/String;I)Z + */ +jboolean JNICALL Java_ohos_rpc_IPCSkeleton_nativeSetCallingIdentity(JNIEnv *env, jclass clazz, jstring identity, + jint len) +{ + const char *identityUtf = env->GetStringUTFChars(identity, JNI_FALSE); + + if (identityUtf != nullptr) { + std::string token = std::string(identityUtf, len); + env->ReleaseStringUTFChars(identity, identityUtf); + + return (IPCSkeleton::SetCallingIdentity(token) == true) ? JNI_TRUE : JNI_FALSE; + } + + return JNI_FALSE; +} + +/* + * Class: ohos.rpc.RemoteObject + * Method: nativeGetObjectHolder + * Signature: (Ljava/lang/String;I)J + */ +jlong JNICALL Java_ohos_rpc_RemoteObject_nativeGetObjectHolder(JNIEnv *env, jclass clazz, jstring value, jint len) +{ + std::u16string descriptor = std::u16string(); + if (value != nullptr) { + const jchar *jcharStr = env->GetStringCritical(value, 0); + if (jcharStr != nullptr) { + descriptor.assign(reinterpret_cast(jcharStr), reinterpret_cast(len)); + env->ReleaseStringCritical(value, jcharStr); + } + } + return (jlong)(new JRemoteObjectHolder(descriptor)); +} + +/* + * Get calling pid from native. + * Class: ohos.rpc.RemoteObject + * Method: nativeGetCallingPid + * Signature: ()I + */ +jint JNICALL Java_ohos_rpc_RemoteObject_nativeGetCallingPid(JNIEnv *env, jclass object) +{ + sptr nativeObject = Java_ohos_rpc_getNativeRemoteObject(env, object); + if ((nativeObject != nullptr) && (!nativeObject->IsProxyObject())) { + IPCObjectStub *target = reinterpret_cast(nativeObject.GetRefPtr()); + return target->GetCallingPid(); + } + return getpid(); +} + +/* + * Get calling uid from native. + * Class: ohos.rpc.RemoteObject + * Method: nativeGetCallingUid + * Signature: ()I + */ +jint JNICALL Java_ohos_rpc_RemoteObject_nativeGetCallingUid(JNIEnv *env, jclass object) +{ + sptr nativeObject = Java_ohos_rpc_getNativeRemoteObject(env, object); + if ((nativeObject != nullptr) && (!nativeObject->IsProxyObject())) { + IPCObjectStub *target = reinterpret_cast(nativeObject.GetRefPtr()); + return target->GetCallingUid(); + } + return getuid(); +} + +/* + * Free local Object Holder of RemoteObject. + * Class: ohos.rpc.RemoteObject + * Method: nativeFreeObjectHolder + * Signature: (J)V + */ +void JNICALL Java_ohos_rpc_RemoteObject_nativeFreeObjectHolder(JNIEnv *env, jclass clazz, jlong holder) +{ + // Delegate sptr to manage memory, + // it will automatically release managed memory when the life cycle ends. + ZLOGI(LABEL, "Call Free Object Holder"); + std::unique_ptr nativeHolder(reinterpret_cast(holder)); +} + +/* + * Free local Object Holder of RemoteObject. + * Class: ohos.rpc.RemoteProxy + * Method: nativeFreeProxyHolder + * Signature: (J)V + */ +void JNICALL Java_ohos_rpc_RemoteProxy_nativeFreeProxyHolder(JNIEnv *env, jclass clazz, jlong holder) +{ + // Delegate sptr to manage memory, + // it will automatically release managed memory when the life cycle ends. + ZLOGI(LABEL, "Call Free Proxy Holder"); + std::unique_ptr nativeHolder(reinterpret_cast(holder)); +} + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeSendRequest + * Signature: (ILohos/rpc/MessageParcel;Lohos/rpc/Parcel;Lohos/rpc/MessageOption;)Z + */ +jboolean JNICALL Java_ohos_rpc_RemoteProxy_nativeSendRequest(JNIEnv *env, jobject object, jint code, jobject data, + jobject reply, jobject option) +{ + ZLOGI(LABEL, "%s", __func__); + MessageParcel *nativeData = JavaOhosRpcMessageParcelGetNative(env, data); + if (nativeData == nullptr) { + JniHelperThrowNullPointerException(env, "data field is null"); + return JNI_FALSE; + } + + MessageParcel *nativeReply = JavaOhosRpcMessageParcelGetNative(env, reply); + if (nativeReply == nullptr) { + ZLOGE(LABEL, "Fail to get native parcel for reply"); + return JNI_FALSE; + } + + MessageOptionPtr nativeOption = JavaOhosRpcMessageOptionGetNative(env, option); + if (nativeOption == nullptr) { + ZLOGE(LABEL, "Fail to get native parcel for reply"); + return JNI_FALSE; + } + + JRemoteProxyHolder *holder = Java_ohos_rpc_getRemoteProxyHolder(env, object); + if (holder == nullptr) { + JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + return JNI_FALSE; + } + + sptr target = holder->object_; + if (target == nullptr) { + ZLOGE(LABEL, "Invalid proxy object"); + return JNI_FALSE; + } + + int result = target->SendRequest(code, *nativeData, *nativeReply, *nativeOption.get()); + ZLOGI(LABEL, "nativeSendRequest result %d", result); + + return (result == ERR_NONE) ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeAddDeathRecipient + * Signature: (Lohos/rpc/IRemoteObject$DeathRecipient;I)Z + */ +jboolean JNICALL Java_ohos_rpc_RemoteProxy_nativeAddDeathRecipient(JNIEnv *env, jobject object, jobject recipient, + jint flags) +{ + if (recipient == nullptr) { + JniHelperThrowNullPointerException(env, "the recipient is null"); + return JNI_FALSE; + } + + JRemoteProxyHolder *holder = Java_ohos_rpc_getRemoteProxyHolder(env, object); + if (holder == nullptr) { + JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + return JNI_FALSE; + } + + sptr target = holder->object_; + if ((target == nullptr) || !target->IsProxyObject()) { + ZLOGE(LABEL, "could not add recipient from invalid target"); + return JNI_FALSE; + } + + sptr nativeRecipient = new JDeathRecipient(recipient); + if (target->AddDeathRecipient(nativeRecipient)) { + JDeathRecipientList *list = holder->list_; + return (list->Add(nativeRecipient) ? JNI_TRUE : JNI_FALSE); + } + + return JNI_FALSE; +} + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeRemoveDeathRecipient + * Signature: (Lohos/rpc/IRemoteObject$DeathRecipient;I)Z + */ +jboolean JNICALL Java_ohos_rpc_RemoteProxy_nativeRemoveDeathRecipient(JNIEnv *env, jobject object, jobject recipient, + jint flags) +{ + if (recipient == nullptr) { + JniHelperThrowNullPointerException(env, "the recipient is null"); + return JNI_FALSE; + } + + JRemoteProxyHolder *holder = Java_ohos_rpc_getRemoteProxyHolder(env, object); + if (holder == nullptr) { + JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + return JNI_FALSE; + } + + sptr target = holder->object_; + if ((target == nullptr) || !target->IsProxyObject()) { + ZLOGE(LABEL, "could not remove recipient from invalid target"); + return JNI_FALSE; + } + + // list should not be null here, it should be alloc at create proxy object. + sptr list = holder->list_; + sptr nativeRecipient = list->Find(recipient); + if (nativeRecipient == nullptr) { + ZLOGE(LABEL, "recipient not found"); + return JNI_FALSE; + } + + target->RemoveDeathRecipient(nativeRecipient); + return (list->Remove(nativeRecipient) ? JNI_TRUE : JNI_FALSE); +} + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeGetInterfaceDescriptor + * Signature: ()Ljava/lang/String; + */ +jstring JNICALL Java_ohos_rpc_RemoteProxy_nativeGetInterfaceDescriptor(JNIEnv *env, jobject object) +{ + JRemoteProxyHolder *holder = Java_ohos_rpc_getRemoteProxyHolder(env, object); + if (holder == nullptr) { + JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + return env->NewStringUTF(""); + } + + IPCObjectProxy *target = reinterpret_cast(holder->object_.GetRefPtr()); + if (target == nullptr) { + ZLOGE(LABEL, "Invalid proxy object"); + return env->NewStringUTF(""); + } + std::u16string remoteDescriptor = target->GetInterfaceDescriptor(); + + return env->NewStringUTF(Str16ToStr8(remoteDescriptor).c_str()); +} + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeIsObjectDead + * Signature: ()Z + */ +jboolean JNICALL Java_ohos_rpc_RemoteProxy_nativeIsObjectDead(JNIEnv *env, jobject object) +{ + JRemoteProxyHolder *holder = Java_ohos_rpc_getRemoteProxyHolder(env, object); + if (holder == nullptr) { + JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + return JNI_TRUE; + } + + IPCObjectProxy *target = reinterpret_cast(holder->object_.GetRefPtr()); + if (target == nullptr) { + ZLOGE(LABEL, "Invalid proxy object"); + return JNI_TRUE; + } + + return (target->IsObjectDead() == true) ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: ohos.rpc.RemoteProxy + * Method: nativeGetHandle + * Signature: ()J + */ +jlong JNICALL Java_ohos_rpc_RemoteProxy_nativeGetHandle(JNIEnv *env, jobject object) +{ + JRemoteProxyHolder *holder = Java_ohos_rpc_getRemoteProxyHolder(env, object); + if (holder == nullptr) { + JniHelperThrowIllegalStateException(env, "Proxy has been finalized!"); + return 0; + } + + IPCObjectProxy *target = reinterpret_cast(holder->object_.GetRefPtr()); + if (target == nullptr) { + ZLOGE(LABEL, "Invalid proxy object"); + return 0; + } + + return (jlong)target->GetHandle(); +} + +static const JNINativeMethod sMethods[] = { + /* Name, Signature, FunctionPointer */ + { "nativeGetContextObject", "()Lohos/rpc/IRemoteObject;", + (void *)Java_ohos_rpc_IPCSkeleton_nativeGetContextObject }, + { "nativeGetCallingPid", "()I", (void *)Java_ohos_rpc_IPCSkeleton_nativeGetCallingPid }, + { "nativeGetCallingUid", "()I", (void *)Java_ohos_rpc_IPCSkeleton_nativeGetCallingUid }, + { "nativeGetCallingDeviceID", "()Ljava/lang/String;", (void *)Java_ohos_rpc_IPCSkeleton_nativeGetCallingDeviceID }, + { "nativeGetLocalDeviceID", "()Ljava/lang/String;", (void *)Java_ohos_rpc_IPCSkeleton_nativeGetLocalDeviceID }, + { "nativeIsLocalCalling", "()Z", (void *)Java_ohos_rpc_IPCSkeleton_nativeIsLocalCalling }, + { "nativeFlushCommands", "(Lohos/rpc/IRemoteObject;)I", (void *)Java_ohos_rpc_IPCSkeleton_nativeFlushCommands }, + { "nativeResetCallingIdentity", "()Ljava/lang/String;", + (void *)Java_ohos_rpc_IPCSkeleton_nativeResetCallingIdentity }, + { "nativeSetCallingIdentity", "(Ljava/lang/String;I)Z", + (void *)Java_ohos_rpc_IPCSkeleton_nativeSetCallingIdentity }, +}; + +static const JNINativeMethod sObjectMethods[] = { + /* Name, Signature, FunctionPointer */ + { "nativeGetObjectHolder", "(Ljava/lang/String;I)J", (void *)Java_ohos_rpc_RemoteObject_nativeGetObjectHolder }, + { "nativeFreeObjectHolder", "(J)V", (void *)Java_ohos_rpc_RemoteObject_nativeFreeObjectHolder }, + { "nativeGetCallingPid", "()I", (void *)Java_ohos_rpc_RemoteObject_nativeGetCallingPid }, + { "nativeGetCallingUid", "()I", (void *)Java_ohos_rpc_RemoteObject_nativeGetCallingUid }, +}; + +static const JNINativeMethod sProxyMethods[] = { + /* Name, Signature, FunctionPointer */ + { "nativeFreeProxyHolder", "(J)V", (void *)Java_ohos_rpc_RemoteProxy_nativeFreeProxyHolder }, + { "nativeGetInterfaceDescriptor", "()Ljava/lang/String;", + (void *)Java_ohos_rpc_RemoteProxy_nativeGetInterfaceDescriptor }, + { "nativeSendRequest", "(ILohos/rpc/MessageParcel;Lohos/rpc/MessageParcel;Lohos/rpc/MessageOption;)Z", + (void *)Java_ohos_rpc_RemoteProxy_nativeSendRequest }, + { "nativeAddDeathRecipient", "(Lohos/rpc/IRemoteObject$DeathRecipient;I)Z", + (void *)Java_ohos_rpc_RemoteProxy_nativeAddDeathRecipient }, + { "nativeRemoveDeathRecipient", "(Lohos/rpc/IRemoteObject$DeathRecipient;I)Z", + (void *)Java_ohos_rpc_RemoteProxy_nativeRemoveDeathRecipient }, + { "nativeIsObjectDead", "()Z", (void *)Java_ohos_rpc_RemoteProxy_nativeIsObjectDead }, + { "nativeGetHandle", "()J", (void *)Java_ohos_rpc_RemoteProxy_nativeGetHandle } +}; + +int JavaOhosRpcIpcSkeletonRegisterNativeMethods(JNIEnv *env) +{ + return JkitRegisterNativeMethods(env, "ohos/rpc/IPCSkeleton", sMethods, NUM_METHODS(sMethods)); +} + +int JavaOhosRpcRemoteObjectRegisterNativeMethods(JNIEnv *env) +{ + jclass clazz = env->FindClass("ohos/rpc/RemoteObject"); + if (clazz == nullptr) { + ZLOGE(LABEL, "Could not find class:RemoteObject"); + return -1; + } + + g_jRemoteStub.klass = (jclass)env->NewGlobalRef(clazz); + if (g_jRemoteStub.klass == nullptr) { + ZLOGE(LABEL, "JRemoteObject NewGlobalRef failed"); + return -1; + } + + g_jRemoteStub.methodDispatchRequest = env->GetMethodID(clazz, "dispatchRequest", "(IJJLohos/rpc/MessageOption;)Z"); + if (g_jRemoteStub.methodDispatchRequest == nullptr) { + ZLOGE(LABEL, "JRemoteObject get method execTransact failed"); + env->DeleteGlobalRef(g_jRemoteStub.klass); + return -1; + } + + g_jRemoteStub.methodDispatchDump = env->GetMethodID(clazz, "dispatchDump", "(IJJLohos/rpc/MessageOption;)Z"); + if (g_jRemoteStub.methodDispatchDump == nullptr) { + ZLOGE(LABEL, "JRemoteObject get method execTransact failed"); + env->DeleteGlobalRef(g_jRemoteStub.klass); + return -1; + } + + g_jRemoteStub.fieldNativeHolder = env->GetFieldID(clazz, "mNativeHolder", "J"); + if (g_jRemoteStub.fieldNativeHolder == nullptr) { + ZLOGE(LABEL, "JRemoteObject get field mNativeHolder failed"); + env->DeleteGlobalRef(g_jRemoteStub.klass); + return -1; + } + + return JkitRegisterNativeMethods(env, "ohos/rpc/RemoteObject", sObjectMethods, NUM_METHODS(sObjectMethods)); +} + +int JavaOhosRpcRemoteProxyRegisterNativeMethods(JNIEnv *env) +{ + jclass clazz = env->FindClass("ohos/rpc/RemoteProxy"); + if (clazz == nullptr) { + ZLOGE(LABEL, "Could not find class:RemoteProxy"); + return -1; + } + + g_jRemoteProxy.klass = (jclass)env->NewGlobalRef(clazz); + g_jRemoteProxy.methodGetInstance = env->GetStaticMethodID(clazz, "getInstance", "(J)Lohos/rpc/RemoteProxy;"); + if (g_jRemoteProxy.methodGetInstance == nullptr) { + ZLOGE(LABEL, "JRemoteProxy get method getInstance failed"); + env->DeleteGlobalRef(g_jRemoteProxy.klass); + return -1; + } + + g_jRemoteProxy.methodSendObituary = + env->GetStaticMethodID(clazz, "sendObituary", "(Lohos/rpc/IRemoteObject$DeathRecipient;)V"); + if (g_jRemoteProxy.methodSendObituary == nullptr) { + env->DeleteGlobalRef(g_jRemoteProxy.klass); + ZLOGE(LABEL, "JRemoteProxy get method sendObituary failed"); + return -1; + } + + g_jRemoteProxy.fieldNativeData = env->GetFieldID(clazz, "mNativeData", "J"); + if (g_jRemoteProxy.fieldNativeData == nullptr) { + env->DeleteGlobalRef(g_jRemoteProxy.klass); + ZLOGE(LABEL, "JRemoteProxy get field mNativeData failed"); + return -1; + } + + return JkitRegisterNativeMethods(env, "ohos/rpc/RemoteProxy", sProxyMethods, NUM_METHODS(sProxyMethods)); +} + +int RegisterJavaRpcNativeMethods(JNIEnv *env) +{ + if (JniHelperRegisterNativeMethods(env) < 0) { + ZLOGE(LABEL, "Register JniHelper Native Methods failed"); + return -1; + } + + if (JavaOhosRpcMessageOptionRegisterNativeMethods(env) < 0) { + ZLOGE(LABEL, "Register MessageOption Native Methods failed"); + return -1; + } + + if (JavaOhosRpcMessageParcelRegisterNativeMethods(env) < 0) { + ZLOGE(LABEL, "Register MessageParcel Native Methods failed"); + return -1; + } + + if (JavaOhosRpcIpcSkeletonRegisterNativeMethods(env) < 0) { + ZLOGE(LABEL, "Register IPCSkeleton Native Methods failed"); + return -1; + } + + if (JavaOhosRpcRemoteObjectRegisterNativeMethods(env) < 0) { + ZLOGE(LABEL, "Register JRemoteObject Native Methods failed"); + return -1; + } + + if (JavaOhosRpcRemoteProxyRegisterNativeMethods(env) < 0) { + ZLOGE(LABEL, "Register JRemoteProxy Native Methods failed"); + return -1; + } + + if (Java_ohos_utils_Parcel_registerNativeMethods(env) < 0) { + ZLOGE(LABEL, "Register JParcel Native Methods failed"); + return -1; + } + + return 0; +} + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + if (vm == nullptr) { + return -1; + } + if (!g_ipcNativeMethodsLoaded) { + JNIEnv *env = NULL; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { + return -1; + } + + if (RegisterJavaRpcNativeMethods(env) < 0) { + return -1; + } + + JNIEnvHelper::nativeInit(vm); + g_ipcNativeMethodsLoaded = true; + } + return JNI_VERSION_1_4; +} diff --git a/ipc/native/src/mock/include/binder_connector.h b/ipc/native/src/mock/include/binder_connector.h new file mode 100755 index 00000000..085a5b6a --- /dev/null +++ b/ipc/native/src/mock/include/binder_connector.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_BINDER_CONNECTOR_H +#define OHOS_IPC_BINDER_CONNECTOR_H + +#include +#include + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +class BinderConnector { +public: + static BinderConnector *GetInstance(); + BinderConnector(const std::string &deviceName); + ~BinderConnector(); + + int WriteBinder(unsigned long request, void *value); + void ExitCurrentThread(unsigned long request); + bool IsDriverAlive(); +private: + static BinderConnector *instance_; + static std::mutex skeletonMutex; + bool OpenDriver(); + int driverFD_; + void *vmAddr_; + const std::string deviceName_; +}; +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS +#endif // OHOS_IPC_BINDER_CONNECTOR_H diff --git a/ipc/native/src/mock/include/binder_debug.h b/ipc/native/src/mock/include/binder_debug.h new file mode 100755 index 00000000..e996396c --- /dev/null +++ b/ipc/native/src/mock/include/binder_debug.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_BINDER_DEBUG_H +#define OHOS_IPC_BINDER_DEBUG_H + +#include "ipc_debug.h" + +namespace OHOS { +class BinderDebug : public ErrorBase { +public: + BinderDebug() = default; + ~BinderDebug() = default; + static const std::string &ToString(int value); + virtual ErrorMap &GetErrorMap() override; +}; +} // namespace OHOS +#endif // OHOS_IPC_BINDER_DEBUG_H diff --git a/ipc/native/src/mock/include/binder_invoker.h b/ipc/native/src/mock/include/binder_invoker.h new file mode 100755 index 00000000..e2b5c5d9 --- /dev/null +++ b/ipc/native/src/mock/include/binder_invoker.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_BINDER_INVOKER_H +#define OHOS_IPC_BINDER_INVOKER_H + +#include +#include +#include "binder_connector.h" +#include "iremote_invoker.h" +#include "invoker_factory.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +class BinderInvoker : public IRemoteInvoker { +public: + class BinderAllocator : public DefaultAllocator { + void Dealloc(void *data) override; + + friend BinderInvoker; + }; + + BinderInvoker(); + + ~BinderInvoker() = default; + + bool AcquireHandle(int32_t handle) override; + + bool ReleaseHandle(int32_t handle) override; + + bool PingService(int32_t handle) override; + + bool AddDeathRecipient(int32_t handle, void *cookie) override; + + bool RemoveDeathRecipient(int32_t handle, void *cookie) override; + + int GetObjectRefCount(const IRemoteObject *object) override; + + bool SetMaxWorkThread(int maxThreadNum) override; + + void JoinThread(bool initiative) override; + + void JoinProcessThread(bool initiative) override; + + void FreeBuffer(void *data) override; + + void StopWorkThread() override; + + bool SetRegistryObject(sptr &object) override; + + int SendRequest(int handle, uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) override; + + int SendReply(MessageParcel &reply, uint32_t flags, int32_t result) override; + + bool FlattenObject(Parcel &parcel, const IRemoteObject *object) const override; + + IRemoteObject *UnflattenObject(Parcel &parcel) override; + + int ReadFileDescriptor(Parcel &parcel) override; + + bool WriteFileDescriptor(Parcel &parcel, int fd, bool takeOwnership) override; + + pid_t GetCallerPid() const override; + + uid_t GetCallerUid() const override; + + uint32_t GetStatus() const override; + + bool IsLocalCalling() override; + + void SetStatus(uint32_t status); + + std::string GetLocalDeviceID() override; + + std::string GetCallerDeviceID() const override; + + int FlushCommands(IRemoteObject *object) override; + + std::string ResetCallingIdentity() override; + + bool SetCallingIdentity(std::string &identity) override; + + void ExitCurrentThread(); + +#ifndef CONFIG_IPC_SINGLE + int TranslateProxy(uint32_t handle, uint32_t flag) override; + + int TranslateStub(binder_uintptr_t cookie, binder_uintptr_t ptr, uint32_t flag, int cmd) override; + + sptr GetSAMgrObject() override; +#endif + +protected: + bool isMainWorkThread; + bool stopWorkThread; + pid_t callerPid_; + pid_t callerUid_; + +private: + int TransactWithDriver(bool doRead = true); + + bool WriteTransaction(int cmd, uint32_t flags, int32_t handle, uint32_t code, const MessageParcel &data, + const int *status); + + int WaitForCompletion(MessageParcel *reply = nullptr, int32_t *acquireResult = nullptr); + + void OnAttemptAcquire(); + + void OnRemoveRecipientDone(); + + void StartWorkLoop(); + + void OnBinderDied(); + + void OnAcquireObject(uint32_t cmd); + + void OnReleaseObject(uint32_t cmd); + + void OnTransaction(const uint8_t *); + + int HandleCommands(uint32_t cmd); + + int HandleReply(MessageParcel *reply); + +private: + DISALLOW_COPY_AND_MOVE(BinderInvoker); + static constexpr int IPC_DEFAULT_PARCEL_SIZE = 256; + Parcel input_; + Parcel output_; + BinderConnector *binderConnector_; + uint32_t status_; + static inline InvokerDelegator delegator_ = { IRemoteObject::IF_PROT_BINDER }; +}; +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS +#endif // OHOS_IPC_BINDER_INVOKER_H diff --git a/ipc/native/src/mock/include/dbinder_base_invoker.h b/ipc/native/src/mock/include/dbinder_base_invoker.h new file mode 100755 index 00000000..dcc5067d --- /dev/null +++ b/ipc/native/src/mock/include/dbinder_base_invoker.h @@ -0,0 +1,1022 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_DBINDER_BASE_INVOKER_H +#define OHOS_IPC_DBINDER_BASE_INVOKER_H + +#include +#include +#include +#include +#include "securec.h" +#include "sys_binder.h" +#include "iremote_invoker.h" +#include "invoker_factory.h" + +#include "ipc_object_stub.h" +#include "ipc_object_proxy.h" +#include "ipc_process_skeleton.h" +#include "ipc_thread_skeleton.h" +#include "ipc_debug.h" +#ifndef CONFIG_STANDARD_SYSTEM +#include "hitrace_invoker.h" +#endif +#include "dbinder_error_code.h" +#include "log_tags.h" + +namespace OHOS { +using namespace OHOS::HiviewDFX; +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_BASE_INVOKER_LABEL = { LOG_CORE, LOG_ID_RPC, "DBinderBaseInvoker" }; + +#define DBINDER_BASE_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_BASE_INVOKER_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_BASE_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_BASE_INVOKER_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +template class DBinderBaseInvoker : public IRemoteInvoker { +public: + class DBinderSendAllocator : public DefaultAllocator { + void Dealloc(void *data) override; + + friend DBinderBaseInvoker; + }; + + class DBinderRecvAllocator : public DefaultAllocator { + void Dealloc(void *data) override; + + friend DBinderBaseInvoker; + }; + + virtual ~DBinderBaseInvoker() = default; + virtual std::shared_ptr QueryServerSessionObject(uint32_t handle) = 0; + virtual bool UpdateClientSession(uint32_t handle, std::shared_ptr sessionObject) = 0; + + virtual int SendRequest(int32_t handle, uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) override; + virtual bool AddDeathRecipient(int32_t handle, void *cookie) override; + virtual bool RemoveDeathRecipient(int32_t handle, void *cookie) override; + virtual int GetObjectRefCount(const IRemoteObject *object) override; + virtual bool SetMaxWorkThread(int maxThreadNum) override; + virtual int SendReply(MessageParcel &reply, uint32_t flags, int32_t result) override; + virtual bool PingService(int32_t handle) override; + virtual sptr GetSAMgrObject() override; + virtual bool SetRegistryObject(sptr &object) override; + virtual void FreeBuffer(void *data) override; + virtual std::shared_ptr WriteTransaction(int cmd, uint32_t flags, int32_t handle, int32_t socketId, + uint32_t code, MessageParcel &data, uint64_t &seqNumber, int status); + virtual int SendOrWaitForCompletion(int userWaitTime, uint64_t seqNumber, std::shared_ptr sessionOfPeer, + MessageParcel *reply = nullptr); + virtual void OnTransaction(std::shared_ptr processInfo); + virtual void StartProcessLoop(uint32_t handle, const char *buffer, uint32_t size); + virtual uint32_t QueryHandleBySession(std::shared_ptr session, uint64_t stubIndex) = 0; + virtual std::shared_ptr QueryClientSessionObject(uint32_t databusHandle) = 0; + virtual std::shared_ptr NewSessionOfBinderProxy(uint32_t handle, std::shared_ptr session) = 0; + virtual std::shared_ptr QuerySessionOfBinderProxy(uint32_t handle, std::shared_ptr session) = 0; + virtual std::shared_ptr CreateServerSessionObject(binder_uintptr_t binder, uint64_t &stubIndex, + std::shared_ptr sessionObject) = 0; + virtual uint32_t FlattenSession(char *sessionOffset, const std::shared_ptr connectSession, + uint64_t stubIndex) = 0; + virtual std::shared_ptr UnFlattenSession(char *sessionOffset, uint64_t &stubIndex) = 0; + virtual int OnSendMessage(std::shared_ptr sessionOfPeer) = 0; + virtual bool CreateProcessThread() = 0; + virtual uint64_t GetSeqNum() const = 0; + virtual void SetSeqNum(uint64_t seq) = 0; + virtual uint32_t GetClientFd() const = 0; + virtual void SetClientFd(uint32_t fd) = 0; + virtual void SetCallerPid(pid_t pid) = 0; + virtual void SetCallerUid(pid_t uid) = 0; + virtual void SetStatus(uint32_t status) = 0; + virtual void SetCallerDeviceID(const std::string &deviceId) = 0; + virtual int CheckAndSetCallerInfo(uint32_t listenFd, uint64_t stubIndex) = 0; + virtual int OnSendRawData(std::shared_ptr session, const void *data, size_t size) = 0; + bool CheckTransactionData(const dbinder_transaction_data *tr) const; + +private: + uint32_t TranslateBinderType(flat_binder_object *binderObject, char *sessionOffset, std::shared_ptr session); + uint32_t TranslateHandleType(flat_binder_object *binderObject, char *sessionOffset, std::shared_ptr session); + bool TranslateRemoteHandleType(flat_binder_object *binderObject, char *sessionOffset); + int HandleReply(uint64_t seqNumber, MessageParcel *reply); + bool SetSenderStubIndex(std::shared_ptr transData, uint32_t handle); + int WaitForReply(uint64_t seqNumber, MessageParcel *reply, uint32_t handle, int userWaitTime); + void ProcessTransaction(dbinder_transaction_data *tr, uint32_t listenFd); + void ProcessReply(dbinder_transaction_data *tr, uint32_t listenFd); + bool IRemoteObjectTranslate(char *dataBuffer, binder_size_t buffer_size, MessageParcel &data, uint32_t socketId, + std::shared_ptr sessionObject); + bool TranslateRawData(char *dataBuffer, MessageParcel &data, uint32_t socketId); + std::shared_ptr GetSessionObject(uint32_t handle, uint32_t socketId); + uint64_t GetUniqueSeqNumber(int cmd); + void ConstructTransData(dbinder_transaction_data &TransData, size_t totalSize, uint64_t seqNum, int cmd, __u32 code, + __u32 flags); + bool ProcessRawData(std::shared_ptr sessionObject, MessageParcel &data, uint64_t seqNum); + std::shared_ptr ProcessNormalData(std::shared_ptr sessionObject, MessageParcel &data, + int32_t handle, int32_t socketId, uint64_t seqNum, int cmd, __u32 code, __u32 flags, int status); + bool MoveTransData2Buffer(std::shared_ptr sessionObject, std::shared_ptr transData); + bool MoveMessageParcel2TransData(MessageParcel &data, std::shared_ptr sessionObject, + std::shared_ptr transData, int32_t socketId, int status); + std::shared_ptr MakeThreadProcessInfo(uint32_t handle, const char *buffer, uint32_t size); + std::shared_ptr MakeThreadMessageInfo(uint32_t handle); + uint32_t MakeRemoteHandle(std::shared_ptr session, uint64_t stubIndex); +}; + +template +uint32_t DBinderBaseInvoker::TranslateBinderType(flat_binder_object *binderObject, char *sessionOffset, + std::shared_ptr session) +{ + uint64_t stubIndex = 0; + std::shared_ptr sessionOfPeer = CreateServerSessionObject(binderObject->binder, stubIndex, session); + if (sessionOfPeer == nullptr) { + DBINDER_BASE_LOGE("send an wrong stub object"); + return 0; + } + binderObject->hdr.type = BINDER_TYPE_REMOTE_HANDLE; + binderObject->cookie = IRemoteObject::IF_PROT_DATABUS; + binderObject->binder = 0; + return FlattenSession(sessionOffset, sessionOfPeer, stubIndex); +} + +template +uint32_t DBinderBaseInvoker::TranslateHandleType(flat_binder_object *binderObject, char *sessionOffset, + std::shared_ptr session) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr"); + return 0; + } + std::shared_ptr sessionOfPeer = nullptr; + if (binderObject->cookie == IRemoteObject::IF_PROT_DATABUS) { + sessionOfPeer = QuerySessionOfBinderProxy(binderObject->handle, session); + } else if (binderObject->cookie == IRemoteObject::IF_PROT_BINDER) { + sessionOfPeer = NewSessionOfBinderProxy(binderObject->handle, session); + } + if (sessionOfPeer == nullptr) { + DBINDER_BASE_LOGE("send an wrong dbinder object"); + return 0; + } + + uint64_t stubIndex = current->QueryHandleToIndex(binderObject->handle); + if (stubIndex == 0) { + DBINDER_BASE_LOGE("stubIndex is zero"); + return 0; + } + binderObject->hdr.type = BINDER_TYPE_REMOTE_HANDLE; + + return FlattenSession(sessionOffset, sessionOfPeer, stubIndex); +} + +template uint32_t DBinderBaseInvoker::MakeRemoteHandle(std::shared_ptr session, uint64_t stubIndex) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr"); + return 0; + } + + uint32_t handle = current->GetDBinderIdleHandle(stubIndex); + DBINDER_BASE_LOGI("create new handle = %{public}d", handle); + if (handle == 0) { + DBINDER_BASE_LOGE("add stub index err stubIndex = %" PRIu64 ", handle = %d", stubIndex, handle); + return 0; + } + if (!UpdateClientSession(handle, session)) { + DBINDER_BASE_LOGE("session create failed"); + return 0; + } + return handle; +} + +template +bool DBinderBaseInvoker::TranslateRemoteHandleType(flat_binder_object *binderObject, char *sessionOffset) +{ + std::shared_ptr sessionOfPeer = nullptr; + uint64_t stubIndex = 0; + + if (binderObject->cookie == IRemoteObject::IF_PROT_DATABUS || + binderObject->cookie == IRemoteObject::IF_PROT_BINDER) { + sessionOfPeer = UnFlattenSession(sessionOffset, stubIndex); + } + if (sessionOfPeer == nullptr) { + DBINDER_BASE_LOGE("send a wrong dbinder object"); + return false; + } + + uint32_t handle = QueryHandleBySession(sessionOfPeer, stubIndex); + if (handle == 0) { + handle = MakeRemoteHandle(sessionOfPeer, stubIndex); + DBINDER_BASE_LOGI("create new handle = %{public}u", handle); + if (handle == 0) { + DBINDER_BASE_LOGE("failed to create new handle"); + return false; + } + } + binderObject->hdr.type = BINDER_TYPE_HANDLE; + binderObject->handle = handle; + return true; +} + +/* check data parcel contains object, if yes, get its session as payload of socket packet */ +template +bool DBinderBaseInvoker::IRemoteObjectTranslate(char *dataBuffer, binder_size_t buffer_size, MessageParcel &data, + uint32_t socketId, std::shared_ptr sessionObject) +{ + if (data.GetOffsetsSize() <= 0 || dataBuffer == nullptr) { + return true; + } + + uint32_t totalSize = 0; + uintptr_t *binderObjectsOffsets = reinterpret_cast(data.GetObjectOffsets()); + uint32_t offsetOfSession = buffer_size + data.GetOffsetsSize() * sizeof(binder_size_t); + char *flatOffset = dataBuffer + offsetOfSession; + + for (size_t i = 0; i < data.GetOffsetsSize(); i++) { + auto binderObject = reinterpret_cast(dataBuffer + *(binderObjectsOffsets + i)); + switch (binderObject->hdr.type) { + case BINDER_TYPE_BINDER: { + uint32_t flatSize = TranslateBinderType(binderObject, flatOffset + totalSize, sessionObject); + if (flatSize == 0) { + DBINDER_BASE_LOGE("send an wrong stub object"); + return false; + } + totalSize += flatSize; + break; + } + + case BINDER_TYPE_HANDLE: { + uint32_t flatSize = TranslateHandleType(binderObject, flatOffset + totalSize, sessionObject); + if (flatSize == 0) { + DBINDER_BASE_LOGE("send an wrong dbinder object"); + return false; + } + totalSize += flatSize; + break; + } + + case BINDER_TYPE_REMOTE_HANDLE: { + if (TranslateRemoteHandleType(binderObject, flatOffset + i * T::GetFlatSessionLen()) != true) { + DBINDER_BASE_LOGE("send a wrong dbinder object"); + return false; + } + break; + } + + case BINDER_TYPE_FD: { + binderObject->hdr.type = BINDER_TYPE_FDR; + binderObject->handle = -1; + break; + } + + case BINDER_TYPE_FDR: { + if (!TranslateRawData(dataBuffer, data, socketId)) { + DBINDER_BASE_LOGE("fail to translate big raw data"); + // do nothing + } + break; + } + default: { + DBINDER_BASE_LOGE("do not support this type of translation"); + // do nothing + break; + } + } + } + + return true; +} + +template +bool DBinderBaseInvoker::TranslateRawData(char *dataBuffer, MessageParcel &data, uint32_t socketId) +{ + if (data.GetOffsetsSize() <= 0 || socketId == 0) { + DBINDER_BASE_LOGI("no raw data to translate."); + return true; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr"); + return false; + } + std::shared_ptr receivedRawData = current->QueryRawData(socketId); + if (receivedRawData == nullptr) { + DBINDER_BASE_LOGE("cannot found rawData according to the socketId"); + return false; + } + std::shared_ptr rawData = receivedRawData->GetData(); + size_t rawSize = receivedRawData->GetSize(); + current->DetachRawData(socketId); + if (!data.RestoreRawData(rawData, rawSize)) { + DBINDER_BASE_LOGE("found rawData, but cannot restore them"); + return false; + } + return true; +} + +template std::shared_ptr DBinderBaseInvoker::GetSessionObject(uint32_t handle, uint32_t socketId) +{ + if (handle != 0) { + /* transact case */ + return QueryServerSessionObject(handle); + } else { + /* reply case */ + return QueryClientSessionObject(socketId); + } +} + +template uint64_t DBinderBaseInvoker::GetUniqueSeqNumber(int cmd) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr"); + return 0; + } + + if (cmd == BC_TRANSACTION) { + return current->GetSeqNumber(); + } else if (cmd == BC_REPLY) { + /* use sender sequence number */ + return GetSeqNum(); + } else { + return 0; + } +} + +template +void DBinderBaseInvoker::ConstructTransData(dbinder_transaction_data &TransData, size_t totalSize, uint64_t seqNum, + int cmd, __u32 code, __u32 flags) +{ + TransData.sizeOfSelf = totalSize; + TransData.magic = DBINDER_MAGICWORD; + TransData.version = VERSION_NUM; + TransData.cmd = cmd; + TransData.code = code; + TransData.flags = flags; + TransData.cookie = 0; + TransData.seqNumber = seqNum; + TransData.buffer_size = 0; + TransData.offsets_size = 0; + TransData.offsets = 0; +} + +template +bool DBinderBaseInvoker::ProcessRawData(std::shared_ptr sessionObject, MessageParcel &data, uint64_t seqNum) +{ + if (data.GetRawData() == nullptr || data.GetRawDataSize() == 0) { + return true; // do nothing, return true + } + + std::shared_ptr transData = nullptr; + size_t totalSize = sizeof(dbinder_transaction_data) + data.GetRawDataSize(); + transData.reset(reinterpret_cast(::operator new(totalSize))); + if (transData == nullptr) { + DBINDER_BASE_LOGE("fail to create raw buffer with length = %{public}zu", totalSize); + return false; + } + + ConstructTransData(*transData, totalSize, seqNum, BC_SEND_RAWDATA, 0, 0); + int result = memcpy_s(reinterpret_cast(transData.get()) + sizeof(dbinder_transaction_data), + totalSize - sizeof(dbinder_transaction_data), data.GetRawData(), data.GetRawDataSize()); + if (result != 0) { + DBINDER_BASE_LOGE("memcpy data fail size = %{public}zu", data.GetRawDataSize()); + return false; + } + result = OnSendRawData(sessionObject, transData.get(), totalSize); + if (result != 0) { + DBINDER_BASE_LOGE("fail to send raw data"); + // do nothing, need send normal MessageParcel + } + return true; +} + +template +bool DBinderBaseInvoker::MoveMessageParcel2TransData(MessageParcel &data, std::shared_ptr sessionObject, + std::shared_ptr transData, int32_t socketId, int status) +{ + if (data.GetDataSize() > 0) { + /* Send this parcel's data through the socket. */ + transData->buffer_size = data.GetDataSize(); + uint32_t useSize = transData->sizeOfSelf - sizeof(dbinder_transaction_data); + int memcpyResult = + memcpy_s(transData->buffer, useSize, reinterpret_cast(data.GetData()), transData->buffer_size); + if (data.GetOffsetsSize() > 0) { + memcpyResult += memcpy_s(transData->buffer + transData->buffer_size, useSize - transData->buffer_size, + reinterpret_cast(data.GetObjectOffsets()), data.GetOffsetsSize() * sizeof(binder_size_t)); + } + if (memcpyResult != 0) { + DBINDER_BASE_LOGE("parcel data memcpy_s failed"); + return false; + } + transData->offsets_size = data.GetOffsetsSize() * sizeof(binder_size_t); + transData->offsets = transData->buffer_size; + + if (!CheckTransactionData(transData.get())) { + DBINDER_BASE_LOGE("check trans data fail"); + return false; + } + if (!IRemoteObjectTranslate(reinterpret_cast(transData->buffer), transData->buffer_size, data, socketId, + sessionObject)) { + DBINDER_BASE_LOGE("translate object failed"); + return false; + } + } else { + transData->flags |= TF_STATUS_CODE; + transData->buffer_size = sizeof(binder_size_t); + transData->offsets_size = static_cast(status); + transData->offsets = transData->buffer_size; + } + return true; +} + +template +std::shared_ptr DBinderBaseInvoker::ProcessNormalData(std::shared_ptr sessionObject, + MessageParcel &data, int32_t handle, int32_t socketId, uint64_t seqNum, int cmd, __u32 code, __u32 flags, + int status) +{ + uint32_t sendSize = ((data.GetDataSize() > 0) ? data.GetDataSize() : sizeof(binder_size_t)) + + sizeof(struct dbinder_transaction_data) + data.GetOffsetsSize() * T::GetFlatSessionLen() + + data.GetOffsetsSize() * sizeof(binder_size_t); + + std::shared_ptr transData = nullptr; + transData.reset(reinterpret_cast(::operator new(sendSize))); + if (transData == nullptr) { + DBINDER_BASE_LOGE("new buffer failed of length = %{public}u", sendSize); + return nullptr; + } + ConstructTransData(*transData, sendSize, seqNum, cmd, code, flags); + + if (SetSenderStubIndex(transData, handle) != true) { + DBINDER_BASE_LOGE("set stubIndex failed, handle = %{public}d", handle); + return nullptr; + } + if (MoveMessageParcel2TransData(data, sessionObject, transData, socketId, status) != true) { + DBINDER_BASE_LOGE("move parcel to transData failed, handle = %{public}d", handle); + return nullptr; + } + return transData; +} + +template +bool DBinderBaseInvoker::MoveTransData2Buffer(std::shared_ptr sessionObject, + std::shared_ptr transData) +{ + std::shared_ptr sessionBuff = sessionObject->GetSessionBuff(); + if (sessionBuff == nullptr) { + DBINDER_BASE_LOGE("get session buffer fail"); + return false; + } + + uint32_t sendSize = transData->sizeOfSelf; + char *sendBuffer = sessionBuff->GetSendBufferAndLock(sendSize); + /* session buffer contain mutex, need release mutex */ + if (sendBuffer == nullptr) { + DBINDER_BASE_LOGE("buffer alloc failed in session"); + return false; + } + + sessionBuff->UpdateSendBuffer(); + ssize_t writeCursor = sessionBuff->GetSendBufferWriteCursor(); + ssize_t readCursor = sessionBuff->GetSendBufferReadCursor(); + if (writeCursor < 0 || readCursor < 0 || sendSize > sessionBuff->GetSendBufferSize() - writeCursor) { + sessionBuff->ReleaseSendBufferLock(); + DBINDER_BASE_LOGE("sender's data is large than idle buffer"); + return false; + } + if (memcpy_s(sendBuffer + writeCursor, sendSize, transData.get(), sendSize)) { + sessionBuff->ReleaseSendBufferLock(); + DBINDER_BASE_LOGE("fail to copy from tr to sendBuffer, parcelSize = %{public}u", sendSize); + return false; + } + + writeCursor += sendSize; + sessionBuff->SetSendBufferWriteCursor(writeCursor); + sessionBuff->SetSendBufferReadCursor(readCursor); + sessionBuff->ReleaseSendBufferLock(); + return true; +} + +template +std::shared_ptr DBinderBaseInvoker::WriteTransaction(int cmd, uint32_t flags, int32_t handle, int32_t socketId, + uint32_t code, MessageParcel &data, uint64_t &seqNumber, int status) +{ + std::shared_ptr sessionObject = GetSessionObject(handle, socketId); + if (sessionObject == nullptr) { + DBINDER_BASE_LOGE("session is not exist for listenFd = %d, handle = %d", socketId, handle); + return nullptr; + } + + uint64_t seqNum = GetUniqueSeqNumber(cmd); + if (seqNum == 0) { + DBINDER_BASE_LOGE("seqNum invalid"); + return nullptr; + } + /* save seqNum for wait thread */ + seqNumber = seqNum; + /* if MessageParcel has raw data, send raw data first, then send MessageParcel to peer */ + if (ProcessRawData(sessionObject, data, seqNum) != true) { + DBINDER_BASE_LOGE("send rawdata failed"); + return nullptr; + } + std::shared_ptr transData = + ProcessNormalData(sessionObject, data, handle, socketId, seqNum, cmd, code, flags, status); + if (transData == nullptr) { + DBINDER_BASE_LOGE("send normal data failed"); + return nullptr; + } + + if (MoveTransData2Buffer(sessionObject, transData) != true) { + DBINDER_BASE_LOGE("move transaction data to buffer failed"); + return nullptr; + } + return sessionObject; +} + +template int DBinderBaseInvoker::HandleReply(uint64_t seqNumber, MessageParcel *reply) +{ + if (reply == nullptr) { + DBINDER_BASE_LOGE("no need reply, free the buffer"); + return RPC_BASE_INVOKER_INVALID_REPLY_ERR; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr"); + return RPC_BASE_INVOKER_INVALID_REPLY_ERR; + } + std::shared_ptr messageInfo = current->QueryThreadBySeqNumber(seqNumber); + if (messageInfo == nullptr) { + DBINDER_BASE_LOGE("receive buffer is nullptr"); +#ifndef BUILD_PUBLIC_VERSION + ReportDriverEvent(DbinderErrorCode::COMMON_DRIVER_ERROR, DbinderErrorCode::ERROR_TYPE, + DbinderErrorCode::RPC_DRIVER, DbinderErrorCode::ERROR_CODE, DbinderErrorCode::HANDLE_RECV_DATA_FAILURE); +#endif + return RPC_BASE_INVOKER_INVALID_REPLY_ERR; + } + + if (messageInfo->flags & MessageOption::TF_STATUS_CODE) { + int32_t err = messageInfo->offsetsSize; + return err; + } + if (messageInfo->buffer == nullptr) { + DBINDER_BASE_LOGE("need reply message, but buffer is nullptr"); + return RPC_BASE_INVOKER_INVALID_REPLY_ERR; + } + auto allocator = new DBinderRecvAllocator(); + if (!reply->SetAllocator(allocator)) { + DBINDER_BASE_LOGE("SetAllocator failed"); + delete allocator; + return RPC_BASE_INVOKER_INVALID_REPLY_ERR; + } + reply->ParseFrom(reinterpret_cast(messageInfo->buffer), messageInfo->bufferSize); + + if (messageInfo->offsetsSize > 0) { + reply->InjectOffsets( + reinterpret_cast(reinterpret_cast(messageInfo->buffer) + messageInfo->offsets), + messageInfo->offsetsSize / sizeof(binder_size_t)); + } + + if (!IRemoteObjectTranslate(reinterpret_cast(messageInfo->buffer), messageInfo->bufferSize, *reply, + messageInfo->socketId, nullptr)) { + DBINDER_BASE_LOGE("translate object failed"); + return RPC_BASE_INVOKER_INVALID_REPLY_ERR; + } + + return ERR_NONE; +} + +template +bool DBinderBaseInvoker::SetSenderStubIndex(std::shared_ptr transData, uint32_t handle) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr"); + return false; + } + transData->cookie = (handle == 0) ? 0 : current->QueryHandleToIndex(handle); + return true; +} + +template void DBinderBaseInvoker::DBinderSendAllocator::Dealloc(void *data) {} + +template void DBinderBaseInvoker::DBinderRecvAllocator::Dealloc(void *data) +{ + delete[](unsigned char *) data; +} + +template +int DBinderBaseInvoker::WaitForReply(uint64_t seqNumber, MessageParcel *reply, uint32_t handle, int userWaitTime) +{ + /* if reply == nullptr, this is a one way message */ + if (reply == nullptr) { + return NO_ERROR; + } + + std::shared_ptr messageInfo = MakeThreadMessageInfo(handle); + if (messageInfo == nullptr) { + DBINDER_BASE_LOGE("make thread message info failed, no memory"); + return RPC_BASE_INVOKER_WAIT_REPLY_ERR; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr"); + return RPC_BASE_INVOKER_WAIT_REPLY_ERR; + } + /* wait for reply */ + if (!current->AddSendThreadInWait(seqNumber, messageInfo, userWaitTime)) { + DBINDER_BASE_LOGE("sender thread wait reply message time out"); + return RPC_BASE_INVOKER_WAIT_REPLY_ERR; + } + + int32_t err = HandleReply(seqNumber, reply); + current->EraseThreadBySeqNumber(seqNumber); + messageInfo->buffer = nullptr; + return err; +} + +template +int DBinderBaseInvoker::SendOrWaitForCompletion(int userWaitTime, uint64_t seqNumber, + std::shared_ptr sessionOfPeer, MessageParcel *reply) +{ + if (seqNumber == 0) { + DBINDER_BASE_LOGE("seqNumber can not be zero"); + return RPC_BASE_INVOKER_INVALID_DATA_ERR; + } + if (sessionOfPeer == nullptr) { + DBINDER_BASE_LOGE("current session is invalid"); + return RPC_BASE_INVOKER_INVALID_DATA_ERR; + } + int returnLen = OnSendMessage(sessionOfPeer); + if (returnLen != 0) { + DBINDER_BASE_LOGE("fail to send to remote session with error = %{public}d", returnLen); + // no return, for msg send failed maybe not mine + } + return WaitForReply(seqNumber, reply, sessionOfPeer->GetSessionHandle(), userWaitTime); +} + +template +int DBinderBaseInvoker::SendRequest(int32_t handle, uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + uint64_t seqNumber = 0; + int ret; + + uint32_t flags = option.GetFlags(); + int userWaitTime = option.GetWaitTime(); + MessageParcel &newData = const_cast(data); + size_t oldWritePosition = newData.GetWritePosition(); +#ifndef CONFIG_STANDARD_SYSTEM + HiTraceId traceId = HiTrace::GetId(); + // set client send trace point if trace is enabled + HiTraceId childId = HitraceInvoker::TraceClientSend(handle, code, newData, flags, traceId); +#endif + std::shared_ptr session = WriteTransaction(BC_TRANSACTION, flags, handle, 0, code, data, seqNumber, 0); + if (session == nullptr) { + newData.RewindWrite(oldWritePosition); + DBINDER_BASE_LOGE("seqNumber can not be zero,handle=%d", handle); +#ifndef BUILD_PUBLIC_VERSION + ReportDriverEvent(DbinderErrorCode::COMMON_DRIVER_ERROR, DbinderErrorCode::ERROR_TYPE, + DbinderErrorCode::RPC_DRIVER, DbinderErrorCode::ERROR_CODE, DbinderErrorCode::TRANSACT_DATA_FAILURE); +#endif + return RPC_BASE_INVOKER_WRITE_TRANS_ERR; + } + + if (flags & TF_ONE_WAY) { + ret = SendOrWaitForCompletion(userWaitTime, seqNumber, session, nullptr); + } else { + ret = SendOrWaitForCompletion(userWaitTime, seqNumber, session, &reply); + } +#ifndef CONFIG_STANDARD_SYSTEM + HitraceInvoker::TraceClientReceieve(handle, code, flags, traceId, childId); +#endif + // restore Parcel data + newData.RewindWrite(oldWritePosition); + return ret; +} + +template bool DBinderBaseInvoker::AddDeathRecipient(int32_t handle, void *cookie) +{ + return true; +} + +template bool DBinderBaseInvoker::RemoveDeathRecipient(int32_t handle, void *cookie) +{ + return true; +} + +template int DBinderBaseInvoker::GetObjectRefCount(const IRemoteObject *object) +{ + return 0; +} + +template bool DBinderBaseInvoker::SetMaxWorkThread(int maxThreadNum) +{ + return true; +} + +template int DBinderBaseInvoker::SendReply(MessageParcel &reply, uint32_t flags, int32_t result) +{ + uint64_t seqNumber = 0; + std::shared_ptr sessionObject = WriteTransaction(BC_REPLY, flags, 0, GetClientFd(), 0, reply, seqNumber, result); + + if (seqNumber == 0) { + DBINDER_BASE_LOGE("seqNumber can not be zero"); + return RPC_BASE_INVOKER_SEND_REPLY_ERR; + } + SendOrWaitForCompletion(0, seqNumber, sessionObject, nullptr); + return 0; +} + +template std::shared_ptr DBinderBaseInvoker::MakeThreadMessageInfo(uint32_t handle) +{ + std::shared_ptr messageInfo = std::make_shared(); + if (messageInfo == nullptr) { + DBINDER_BASE_LOGE("no memory"); + return nullptr; + } + + messageInfo->threadId = std::this_thread::get_id(); + messageInfo->buffer = nullptr; + messageInfo->offsets = 0; + messageInfo->socketId = handle; + return messageInfo; +} + +template +std::shared_ptr DBinderBaseInvoker::MakeThreadProcessInfo(uint32_t handle, const char *inBuffer, + uint32_t size) +{ + if (inBuffer == nullptr || size < sizeof(dbinder_transaction_data) || size > SOCKET_MAX_BUFF_SIZE) { + DBINDER_BASE_LOGE("buffer is null or size invalid"); + return nullptr; + } + + std::shared_ptr processInfo = std::make_shared(); + if (processInfo == nullptr) { + DBINDER_BASE_LOGE("make_shared processInfo fail"); + return nullptr; + } + std::shared_ptr buffer(new (std::nothrow) char[size]); + if (buffer == nullptr) { + DBINDER_BASE_LOGE("new buffer failed of length = %{public}u", size); + return nullptr; + } + + int memcpyResult = memcpy_s(buffer.get(), size, inBuffer, size); + if (memcpyResult != 0) { + DBINDER_BASE_LOGE("memcpy_s failed , size = %{public}u", size); + return nullptr; + } + + processInfo->listenFd = handle; + processInfo->packageSize = size; + processInfo->buffer = buffer; + return processInfo; +} + +template void DBinderBaseInvoker::StartProcessLoop(uint32_t handle, const char *buffer, uint32_t size) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr"); + return; + } + std::shared_ptr processInfo = MakeThreadProcessInfo(handle, buffer, size); + if (processInfo == nullptr) { + DBINDER_BASE_LOGE("processInfo is nullptr"); + return; + } + std::thread::id threadId = current->GetIdleDataThread(); + if (threadId == std::thread::id()) { + bool result = CreateProcessThread(); + if (!result) { + int socketThreadNum = current->GetSocketTotalThreadNum(); + DBINDER_BASE_LOGE("create IO thread failed, current socket thread num=%d", socketThreadNum); + /* thread create too much, wait some thread be idle */ + } + do { + /* no IO thread in idle state, wait a monent */ + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } while ((threadId = current->GetIdleDataThread()) == std::thread::id()); + } + + current->AddDataInfoToThread(threadId, processInfo); + current->WakeUpDataThread(threadId); + return; +} + +template void DBinderBaseInvoker::ProcessTransaction(dbinder_transaction_data *tr, uint32_t listenFd) +{ + int error; + MessageParcel data, reply; + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr"); + return; + } + + auto allocator = new DBinderSendAllocator(); + if (!data.SetAllocator(allocator)) { + DBINDER_BASE_LOGE("SetAllocator failed"); + delete allocator; + return; + } + data.ParseFrom(reinterpret_cast(tr->buffer), tr->buffer_size); + if (!(tr->flags & MessageOption::TF_STATUS_CODE) && tr->offsets_size > 0) { + data.InjectOffsets(reinterpret_cast(reinterpret_cast(tr->buffer) + tr->offsets), + tr->offsets_size / sizeof(binder_size_t)); + } +#ifndef CONFIG_STANDARD_SYSTEM + uint32_t &newflags = const_cast(tr->flags); + int isServerTraced = HitraceInvoker::TraceServerReceieve(tr->cookie, tr->code, data, newflags); +#endif + + const pid_t oldPid = GetCallerPid(); + const auto oldUid = static_cast(GetCallerUid()); + const std::string oldDeviceId = GetCallerDeviceID(); + + if (CheckAndSetCallerInfo(listenFd, tr->cookie) != ERR_NONE) { + DBINDER_BASE_LOGE("set user info error, maybe cookie is NOT belong to current caller"); + return; + } + SetStatus(IRemoteInvoker::ACTIVE_INVOKER); + + const uint32_t flags = tr->flags; + uint64_t senderSeqNumber = tr->seqNumber; + if (tr->cookie == 0) { + // maybe cookie is zero, discard this package + return; + } + + auto *stub = current->QueryStubByIndex(tr->cookie); + if (stub == nullptr) { + DBINDER_BASE_LOGE("stubIndex is invalid"); + return; + } + if (!IRemoteObjectTranslate(reinterpret_cast(tr->buffer), tr->buffer_size, data, listenFd, nullptr)) { + DBINDER_BASE_LOGE("translate object failed"); + return; + } + + auto *stubObject = reinterpret_cast(stub); + MessageOption option; + option.SetFlags(flags); + error = stubObject->SendRequest(tr->code, data, reply, option); + if (error != ERR_NONE) { + DBINDER_BASE_LOGE("stub is invalid, has not OnReceive or Request"); + // can not return; + } + if (data.GetRawData() != nullptr) { + DBINDER_BASE_LOGE("delete raw data in process skeleton"); + current->DetachRawData(listenFd); + } +#ifndef CONFIG_STANDARD_SYSTEM + HitraceInvoker::TraceServerSend(tr->cookie, tr->code, isServerTraced, newflags); +#endif + if (!(flags & MessageOption::TF_ASYNC)) { + SetClientFd(listenFd); + SetSeqNum(senderSeqNumber); + SendReply(reply, 0, error); + SetClientFd(0); + SetSeqNum(0); + } + + SetCallerPid(oldPid); + SetCallerUid(oldUid); + SetCallerDeviceID(oldDeviceId); + SetStatus(IRemoteInvoker::IDLE_INVOKER); +} + +template void DBinderBaseInvoker::ProcessReply(dbinder_transaction_data *tr, uint32_t listenFd) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_BASE_LOGE("current ipc process skeleton is nullptr, can not wakeup thread"); + return; + } + + std::shared_ptr messageInfo = current->QueryThreadBySeqNumber(tr->seqNumber); + if (messageInfo == nullptr) { + DBINDER_BASE_LOGE("no thread waiting reply message of this seqNumber"); + /* messageInfo is null, no thread need to wakeup */ + return; + } + + /* tr->sizeOfSelf > sizeof(dbinder_transaction_data) is checked in CheckTransactionData */ + messageInfo->buffer = new (std::nothrow) unsigned char[tr->sizeOfSelf - sizeof(dbinder_transaction_data)]; + if (messageInfo->buffer == nullptr) { + DBINDER_BASE_LOGE("some thread is waiting for reply message, but no memory"); + /* wake up sender thread */ + current->WakeUpThreadBySeqNumber(tr->seqNumber, listenFd); + return; + } + /* copy receive message to sender thread */ + int memcpyResult = memcpy_s(messageInfo->buffer, tr->sizeOfSelf - sizeof(dbinder_transaction_data), tr->buffer, + tr->sizeOfSelf - sizeof(dbinder_transaction_data)); + if (memcpyResult != 0) { + DBINDER_BASE_LOGE("memcpy_s failed"); + delete[](unsigned char *) messageInfo->buffer; + messageInfo->buffer = nullptr; + /* wake up sender thread even no memssage */ + current->WakeUpThreadBySeqNumber(tr->seqNumber, listenFd); + return; + } + + messageInfo->flags = tr->flags; + messageInfo->bufferSize = tr->buffer_size; + messageInfo->offsetsSize = tr->offsets_size; + messageInfo->offsets = tr->offsets; + messageInfo->socketId = listenFd; + + /* wake up sender thread */ + current->WakeUpThreadBySeqNumber(tr->seqNumber, listenFd); +} + +template void DBinderBaseInvoker::OnTransaction(std::shared_ptr processInfo) +{ + if (processInfo == nullptr) { + DBINDER_BASE_LOGE("processInfo is error!"); + return; + } + uint32_t listenFd = processInfo->listenFd; + char *package = processInfo->buffer.get(); + + if (package == nullptr || listenFd == 0) { + DBINDER_BASE_LOGE("package is null or listenFd invalid!"); + return; + } + + dbinder_transaction_data *tr = reinterpret_cast(package); + if (tr->sizeOfSelf < sizeof(dbinder_transaction_data)) { + DBINDER_BASE_LOGE("package is invalid"); + return; + } + + if (tr->cmd == BC_TRANSACTION) { + ProcessTransaction(tr, listenFd); + } else if (tr->cmd == BC_REPLY) { + ProcessReply(tr, listenFd); + } + return; +} + +template bool DBinderBaseInvoker::PingService(int32_t handle) +{ + return true; +} + +template sptr DBinderBaseInvoker::GetSAMgrObject() +{ + return nullptr; +} + + +template bool DBinderBaseInvoker::SetRegistryObject(sptr &object) +{ + return true; +} + +template void DBinderBaseInvoker::FreeBuffer(void *data) +{ + return; +} + +template bool DBinderBaseInvoker::CheckTransactionData(const dbinder_transaction_data *tr) const +{ + if (tr->sizeOfSelf == 0 || tr->sizeOfSelf > SOCKET_MAX_BUFF_SIZE || tr->buffer_size > SOCKET_MAX_BUFF_SIZE || + tr->buffer_size == 0 || tr->offsets != tr->buffer_size || + tr->sizeOfSelf < sizeof(dbinder_transaction_data) + tr->buffer_size) { + return false; + } + if ((tr->flags & MessageOption::TF_STATUS_CODE) && (tr->offsets != sizeof(binder_size_t))) { + return false; + } + if (!(tr->flags & MessageOption::TF_STATUS_CODE)) { + if (tr->offsets_size > (tr->sizeOfSelf - sizeof(dbinder_transaction_data) - tr->buffer_size)) { + return false; + } + binder_size_t sessionSize = + tr->sizeOfSelf - tr->buffer_size - sizeof(dbinder_transaction_data) - tr->offsets_size; + if (sessionSize * sizeof(binder_size_t) != tr->offsets_size * T::GetFlatSessionLen()) { + return false; + } + } + + return true; +} +} // namespace OHOS +#endif // OHOS_IPC_DBINDER_BASE_INVOKER_H diff --git a/ipc/native/src/mock/include/dbinder_databus_invoker.h b/ipc/native/src/mock/include/dbinder_databus_invoker.h new file mode 100755 index 00000000..e08045a3 --- /dev/null +++ b/ipc/native/src/mock/include/dbinder_databus_invoker.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_DBINDER_DATABUS_INVOKER_H +#define OHOS_IPC_DBINDER_DATABUS_INVOKER_H + +#include +#include +#include "hilog/log.h" +#include "dbinder_base_invoker.h" +#include "invoker_factory.h" +#include "dbinder_session_object.h" +#include "sys_binder.h" + +#include "Session.h" +#include "ISessionService.h" + +using Communication::SoftBus::ISessionService; +using Communication::SoftBus::Session; + +namespace OHOS { +class DBinderDatabusInvoker : public DBinderBaseInvoker { +public: + DBinderDatabusInvoker(); + ~DBinderDatabusInvoker(); + bool AcquireHandle(int32_t handle) override; + bool ReleaseHandle(int32_t handle) override; + void JoinThread(bool initiative) override; + void JoinProcessThread(bool initiative) override; + void StopWorkThread() override; + bool FlattenObject(Parcel &parcel, const IRemoteObject *object) const override; + IRemoteObject *UnflattenObject(Parcel &parcel) override; + int ReadFileDescriptor(Parcel &parcel) override; + bool WriteFileDescriptor(Parcel &parcel, int fd, bool takeOwnership) override; + pid_t GetCallerPid() const override; + uid_t GetCallerUid() const override; + uint32_t GetStatus() const override; + bool IsLocalCalling() override; + std::string GetLocalDeviceID() override; + std::string GetCallerDeviceID() const override; + + bool UpdateClientSession(uint32_t handle, std::shared_ptr sessionObject) override; + std::shared_ptr QueryClientSessionObject(uint32_t databusHandle) override; + std::shared_ptr QueryServerSessionObject(uint32_t handle) override; + std::shared_ptr CreateServerSessionObject(binder_uintptr_t binder, uint64_t &stubIndex, + std::shared_ptr sessionObject) override; + int FlushCommands(IRemoteObject *object) override; + + bool OnDatabusSessionClosed(std::shared_ptr session); + bool OnReceiveNewConnection(std::shared_ptr session); + std::string ResetCallingIdentity() override; + bool SetCallingIdentity(std::string &identity) override; + int TranslateProxy(uint32_t handle, uint32_t flag) override; + int TranslateStub(binder_uintptr_t cookie, binder_uintptr_t ptr, uint32_t flag, int cmd) override; + void OnMessageAvailable(std::shared_ptr session, const char *data, ssize_t len); + +private: + bool CreateProcessThread() override; + int OnSendMessage(std::shared_ptr sessionOfPeer) override; + int OnSendRawData(std::shared_ptr session, const void *data, size_t size) override; + std::shared_ptr NewSessionOfBinderProxy(uint32_t handle, + std::shared_ptr session) override; + std::shared_ptr QuerySessionOfBinderProxy(uint32_t handle, + std::shared_ptr session) override; + uint32_t FlattenSession(char *sessionOffset, const std::shared_ptr connectSession, + uint64_t stubIndex) override; + std::shared_ptr UnFlattenSession(char *sessionOffset, uint64_t &stubIndex) override; + uint32_t QueryHandleBySession(std::shared_ptr session, uint64_t stubIndex) override; + virtual uint64_t GetSeqNum() const override; + virtual void SetSeqNum(uint64_t seq) override; + virtual uint32_t GetClientFd() const override; + virtual void SetClientFd(uint32_t fd) override; + virtual void SetCallerPid(pid_t pid) override; + virtual void SetCallerUid(pid_t uid) override; + virtual void SetStatus(uint32_t status) override; + virtual void SetCallerDeviceID(const std::string &deviceId) override; + virtual int CheckAndSetCallerInfo(uint32_t listenFd, uint64_t stubIndex) override; + uint32_t HasRawDataPackage(const char *data, ssize_t len); + uint32_t HasCompletePackage(const char *data, uint32_t readCursor, ssize_t len); + void OnRawDataAvailable(std::shared_ptr session, const char *data, uint32_t dataSize); + uint64_t MakeStubIndexByRemoteObject(IRemoteObject *stubObject); + std::shared_ptr MakeDefaultServerSessionObject(); + bool ConnectRemoteObject2Session(IRemoteObject *stubObject, uint64_t stubIndex, + const std::shared_ptr sessionObject); + bool AuthSession2Proxy(uint32_t handle, const std::shared_ptr Session); + +private: + DISALLOW_COPY_AND_MOVE(DBinderDatabusInvoker); + bool stopWorkThread_; + pid_t callerPid_; + pid_t callerUid_; + std::string callerDeviceID_; + uint64_t seqNumber_ = 0; + uint32_t clientFd_ = 0; + uint32_t status_; + static inline InvokerDelegator DBinderDatabusDelegator_ = { IRemoteObject::IF_PROT_DATABUS }; +}; +} // namespace OHOS +#endif // OHOS_IPC_DBINDER_DATABUS_INVOKER_H diff --git a/ipc/native/src/mock/include/hitrace_invoker.h b/ipc/native/src/mock/include/hitrace_invoker.h new file mode 100755 index 00000000..7da8029a --- /dev/null +++ b/ipc/native/src/mock/include/hitrace_invoker.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_HITRACE_INVOKER_H +#define OHOS_IPC_HITRACE_INVOKER_H + +#include "hitrace/trace.h" +#include "iremote_object.h" +namespace OHOS { +class HitraceInvoker { +public: + static bool IsClientTraced(int32_t handle, uint32_t flags, const HiviewDFX::HiTraceId &traceId); + + static HiviewDFX::HiTraceId TraceClientSend(int32_t handle, uint32_t code, Parcel &data, uint32_t &flags, + const HiviewDFX::HiTraceId &traceId); + + static void TraceClientReceieve(int32_t handle, uint32_t code, uint32_t flags, const HiviewDFX::HiTraceId &traceId, + const HiviewDFX::HiTraceId &childId); + + static void RecoveryDataAndFlag(Parcel &data, uint32_t &flags, size_t oldReadPosition, uint8_t idLen); + + static bool TraceServerReceieve(int32_t handle, uint32_t code, Parcel &data, uint32_t &flags); + + static void TraceServerSend(int32_t handle, uint32_t code, bool isServerTraced, uint32_t flags); + +private: + static const int PADDED_SIZE_OF_PARCEL = 4; +}; +} // namespace OHOS +#endif // OHOS_IPC_HITRACE_INVOKER_H \ No newline at end of file diff --git a/ipc/native/src/mock/include/invoker_factory.h b/ipc/native/src/mock/include/invoker_factory.h new file mode 100755 index 00000000..64176b4d --- /dev/null +++ b/ipc/native/src/mock/include/invoker_factory.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_INVOKER_FACTORY_H +#define OHOS_IPC_INVOKER_FACTORY_H + +#include +#include +#include "iremote_invoker.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif +class InvokerFactory { +public: + using InvokerCreator = std::function; + static InvokerFactory &Get(); + bool Register(int protocol, InvokerCreator creator); + void Unregister(int protocol); + IRemoteInvoker *newInstance(int protocol); + +private: + InvokerFactory &operator = (const InvokerFactory &) = delete; + InvokerFactory(const InvokerFactory &) = delete; + InvokerFactory(); + ~InvokerFactory(); + static bool isAvailable_; + std::mutex factoryMutex_; + std::unordered_map creators_; +}; + +template class InvokerDelegator { +public: + InvokerDelegator(int prot); + ~InvokerDelegator(); + +private: + int prot_; + InvokerDelegator &operator = (const InvokerDelegator &) = delete; + InvokerDelegator(const InvokerDelegator &) = delete; +}; + +template InvokerDelegator::InvokerDelegator(int prot) +{ + prot_ = prot; + InvokerFactory::Get().Register(prot, []() { return static_cast(new T()); }); +} + +template InvokerDelegator::~InvokerDelegator() +{ + InvokerFactory::Get().Unregister(prot_); +} +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS +#endif // OHOS_IPC_INVOKER_FACTORY_H \ No newline at end of file diff --git a/ipc/native/src/mock/include/invoker_rawdata.h b/ipc/native/src/mock/include/invoker_rawdata.h new file mode 100755 index 00000000..94a1f2a4 --- /dev/null +++ b/ipc/native/src/mock/include/invoker_rawdata.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_INVOKER_RAWDATA_H +#define OHOS_IPC_INVOKER_RAWDATA_H + +#include +#include +#include +#include + +#include "nocopyable.h" + +namespace OHOS { +class InvokerRawData { +public: + DISALLOW_COPY_AND_MOVE(InvokerRawData); + explicit InvokerRawData(size_t size); + ~InvokerRawData(); + std::shared_ptr GetData() const; + size_t GetSize() const; + +private: + std::shared_ptr data_; + size_t size_; +}; +} // namespace OHOS +#endif // OHOS_IPC_INVOKER_RAWDATA_H \ No newline at end of file diff --git a/ipc/native/src/mock/include/iremote_invoker.h b/ipc/native/src/mock/include/iremote_invoker.h new file mode 100755 index 00000000..ba62f420 --- /dev/null +++ b/ipc/native/src/mock/include/iremote_invoker.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_IREMOTE_INVOKER_H +#define OHOS_IPC_IREMOTE_INVOKER_H + +#include +#include +#include "parcel.h" +#include "sys_binder.h" +#include "iremote_object.h" +#include "ipc_file_descriptor.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +class IRemoteInvoker { +public: + enum { + IDLE_INVOKER, + ACTIVE_INVOKER, + }; + virtual ~IRemoteInvoker() = default; + virtual bool AcquireHandle(int32_t handle) = 0; + + virtual bool ReleaseHandle(int32_t handle) = 0; + + virtual bool PingService(int32_t handle) = 0; + + virtual int SendReply(MessageParcel &reply, uint32_t flags, int32_t result) = 0; + + virtual int SendRequest(int handle, uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) = 0; + + virtual bool AddDeathRecipient(int32_t handle, void *cookie) = 0; + + virtual int GetObjectRefCount(const IRemoteObject *object) = 0; + + virtual bool RemoveDeathRecipient(int32_t handle, void *cookie) = 0; + + virtual bool SetMaxWorkThread(int maxThreadNum) = 0; + + virtual void JoinThread(bool initiative) = 0; + + virtual void JoinProcessThread(bool initiative) = 0; + + virtual void StopWorkThread() = 0; + + virtual void FreeBuffer(void *data) = 0; + + virtual bool SetRegistryObject(sptr &object) = 0; + + virtual pid_t GetCallerPid() const = 0; + + virtual uid_t GetCallerUid() const = 0; + + virtual uint32_t GetStatus() const = 0; + + virtual bool IsLocalCalling() = 0; + + virtual std::string GetLocalDeviceID() = 0; + + virtual std::string GetCallerDeviceID() const = 0; + + virtual bool FlattenObject(Parcel &parcel, const IRemoteObject *object) const = 0; + + virtual IRemoteObject *UnflattenObject(Parcel &parcel) = 0; + + virtual int ReadFileDescriptor(Parcel &parcel) = 0; + + virtual bool WriteFileDescriptor(Parcel &parcel, int fd, bool takeOwnership) = 0; + + virtual int FlushCommands(IRemoteObject *object) = 0; + + virtual std::string ResetCallingIdentity() = 0; + + virtual bool SetCallingIdentity(std::string &identity) = 0; + +#ifndef CONFIG_IPC_SINGLE + virtual sptr GetSAMgrObject() = 0; + + virtual int TranslateProxy(uint32_t handle, uint32_t flag) = 0; + + virtual int TranslateStub(binder_uintptr_t cookie, binder_uintptr_t ptr, uint32_t flag, int cmd) = 0; +#endif +}; +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS +#endif // OHOS_IPC_IREMOTE_INVOKER_H diff --git a/ipc/native/src/mock/include/sys_binder.h b/ipc/native/src/mock/include/sys_binder.h new file mode 100755 index 00000000..c3cb5040 --- /dev/null +++ b/ipc/native/src/mock/include/sys_binder.h @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_SYS_BINDER_H +#define OHOS_IPC_SYS_BINDER_H + +#include + +#ifndef _UAPI_LINUX_BINDER_H +#define _UAPI_LINUX_BINDER_H + +#include +#include + +#ifndef B_PACK_CHARS +#define B_PACK_CHARS(c1, c2, c3, c4) ((((c1) << 24)) | (((c2) << 16)) | (((c3) << 8)) | (c4)) +#endif + +#define B_TYPE_LARGE 0x85 +enum { + BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE), + BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE), + BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE), + BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE), + BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE), + BINDER_TYPE_FDA = B_PACK_CHARS('f', 'd', 'a', B_TYPE_LARGE), + BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE), +}; +enum { + FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, + FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, + FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000, +}; +#ifdef BINDER_IPC_32BIT +typedef __u32 binder_size_t; +typedef __u32 binder_uintptr_t; +#else +typedef __u64 binder_size_t; +typedef __u64 binder_uintptr_t; +#endif +struct binder_object_header { + __u32 type; +}; +struct flat_binder_object { + struct binder_object_header hdr; + __u32 flags; + union { + binder_uintptr_t binder; + __u32 handle; + }; + binder_uintptr_t cookie; +}; + +struct binder_fd_object { + struct binder_object_header hdr; + __u32 pad_flags; + union { + binder_uintptr_t pad_binder; + __u32 fd; + }; + binder_uintptr_t cookie; +}; +struct binder_buffer_object { + struct binder_object_header hdr; + __u32 flags; + binder_uintptr_t buffer; + binder_size_t length; + binder_size_t parent; + binder_size_t parent_offset; +}; +enum { + BINDER_BUFFER_FLAG_HAS_PARENT = 0x01, +}; +struct binder_fd_array_object { + struct binder_object_header hdr; + __u32 pad; + binder_size_t num_fds; + binder_size_t parent; + binder_size_t parent_offset; +}; +struct binder_write_read { + binder_size_t write_size; + binder_size_t write_consumed; + binder_uintptr_t write_buffer; + binder_size_t read_size; + binder_size_t read_consumed; + binder_uintptr_t read_buffer; +}; +struct binder_version { + __s32 protocol_version; +}; +#ifdef BINDER_IPC_32BIT +#define BINDER_CURRENT_PROTOCOL_VERSION 7 +#else +#define BINDER_CURRENT_PROTOCOL_VERSION 8 +#endif +struct binder_node_debug_info { + binder_uintptr_t ptr; + binder_uintptr_t cookie; + __u32 has_strong_ref; + __u32 has_weak_ref; +}; + +struct binder_node_info_for_ref { + __u32 handle; + __u32 strong_count; + __u32 weak_count; + __u32 reserved1; + __u32 reserved2; + __u32 reserved3; +}; + +#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) +#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) +#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) +#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32) +#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) +#define BINDER_THREAD_EXIT _IOW('b', 8, __s32) +#define BINDER_VERSION _IOWR('b', 9, struct binder_version) +#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) +#define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) +#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) +#define BINDER_GET_NODE_REFCOUNT _IOWR('b', 17, struct binder_ptr_count) +#define BINDER_TRANSLATE_HANDLE _IOWR('b', 18, __u32) + +enum transaction_flags { + TF_ONE_WAY = 0x01, + TF_ROOT_OBJECT = 0x04, + TF_STATUS_CODE = 0x08, + TF_ACCEPT_FDS = 0x10, + TF_HITRACE = 0x80, // add flag for hitrace +}; +struct binder_transaction_data { + union { + __u32 handle; + binder_uintptr_t ptr; + } target; + binder_uintptr_t cookie; + __u32 code; + __u32 flags; + pid_t sender_pid; + uid_t sender_euid; + binder_size_t data_size; + binder_size_t offsets_size; + union { + struct { + binder_uintptr_t buffer; + binder_uintptr_t offsets; + } ptr; + __u8 buf[8]; + } data; +}; +struct binder_transaction_data_secctx { + struct binder_transaction_data transaction_data; + binder_uintptr_t secctx; +}; + +struct binder_transaction_data_sg { + struct binder_transaction_data transaction_data; + binder_size_t buffers_size; +}; +struct binder_ptr_cookie { + binder_uintptr_t ptr; + binder_uintptr_t cookie; +}; +struct binder_handle_cookie { + __u32 handle; + binder_uintptr_t cookie; +} __attribute__((__packed__)); +struct binder_pri_desc { + __s32 priority; + __u32 desc; +}; +struct binder_pri_ptr_cookie { + __s32 priority; + binder_uintptr_t ptr; + binder_uintptr_t cookie; +}; +enum binder_driver_return_protocol { + BR_ERROR = _IOR('r', 0, __s32), + BR_OK = _IO('r', 1), + BR_TRANSACTION_SEC_CTX = _IOR('r', 2, struct binder_transaction_data_secctx), + BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), + BR_REPLY = _IOR('r', 3, struct binder_transaction_data), + BR_ACQUIRE_RESULT = _IOR('r', 4, __s32), + BR_DEAD_REPLY = _IO('r', 5), + BR_TRANSACTION_COMPLETE = _IO('r', 6), + BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie), + BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie), + BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie), + BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie), + BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie), + BR_NOOP = _IO('r', 12), + BR_SPAWN_LOOPER = _IO('r', 13), + BR_FINISHED = _IO('r', 14), + BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t), + BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t), + BR_FAILED_REPLY = _IO('r', 17), + BR_RELEASE_NODE = _IO('r', 18), +}; +enum binder_driver_command_protocol { + BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data), + BC_REPLY = _IOW('c', 1, struct binder_transaction_data), + BC_ACQUIRE_RESULT = _IOW('c', 2, __s32), + BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t), + BC_INCREFS = _IOW('c', 4, __u32), + BC_ACQUIRE = _IOW('c', 5, __u32), + BC_RELEASE = _IOW('c', 6, __u32), + BC_DECREFS = _IOW('c', 7, __u32), + BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie), + BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie), + BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc), + BC_REGISTER_LOOPER = _IO('c', 11), + BC_ENTER_LOOPER = _IO('c', 12), + BC_EXIT_LOOPER = _IO('c', 13), + BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_handle_cookie), + BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_handle_cookie), + BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t), + BC_TRANSACTION_SG = _IOW('c', 17, struct binder_transaction_data_sg), + BC_REPLY_SG = _IOW('c', 18, struct binder_transaction_data_sg), + BC_SEND_RAWDATA = _IOW('c', 20, __u32), +}; +#endif /* * _UAPI_LINUX_BINDER_H * */ + +static const int DBINDER_MAGICWORD = 0X4442494E; +static const int ENCRYPT_HEAD_LEN = 28; +static const int DEVICEID_LENGTH = 64; +static const int PID_LEN = 32; +static const int VERSION_NUM = 1; + +enum { + BINDER_TYPE_REMOTE_BINDER = B_PACK_CHARS('r', 'b', '*', B_TYPE_LARGE), + BINDER_TYPE_REMOTE_HANDLE = B_PACK_CHARS('r', 'h', '*', B_TYPE_LARGE), + ZBINDER_TYPE_REMOTE_NODE = B_PACK_CHARS('r', 'n', '*', B_TYPE_LARGE), + ZBINDER_TYPE_NODE = B_PACK_CHARS('s', 'n', '*', B_TYPE_LARGE), + BINDER_TYPE_FDR = B_PACK_CHARS('f', 'd', 'r', B_TYPE_LARGE), +}; + +struct binder_ptr_count { + binder_uintptr_t ptr; + uint32_t count; +}; + +struct dbinder_transaction_data { + __u32 sizeOfSelf; + __u32 magic; + __u32 version; + int cmd; + __u32 code; + __u32 flags; + __u64 cookie; + __u64 seqNumber; + binder_size_t buffer_size; + binder_size_t offsets_size; + binder_uintptr_t offsets; + unsigned char buffer[0]; +}; +#endif // OHOS_IPC_SYS_BINDER_H diff --git a/ipc/native/src/mock/source/binder_connector.cpp b/ipc/native/src/mock/source/binder_connector.cpp new file mode 100755 index 00000000..ff14cdbc --- /dev/null +++ b/ipc/native/src/mock/source/binder_connector.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_connector.h" +#include +#include +#include +#include +#include +#include +#include +#include "hilog/log.h" +#include "ipc_types.h" +#include "ipc_debug.h" +#include "dbinder_error_code.h" +#include "log_tags.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "BinderConnector" }; +std::mutex BinderConnector::skeletonMutex; +constexpr int SZ_1_M = 1048576; +constexpr int DOUBLE = 2; +static const int IPC_MMAP_SIZE = (SZ_1_M - sysconf(_SC_PAGE_SIZE) * DOUBLE); +#if (defined CONFIG_DUAL_FRAMEWORK) +static const std::string DRIVER_NAME = std::string("/dev/binder"); +#else +static const std::string DRIVER_NAME = std::string("/dev/zbinder"); +#endif /* CONFIG_DUAL_FRAMEWORK */ +BinderConnector *BinderConnector::instance_ = nullptr; + +BinderConnector::BinderConnector(const std::string &deviceName) + : driverFD_(-1), vmAddr_(MAP_FAILED), deviceName_(deviceName) +{} + +BinderConnector::~BinderConnector() +{ + if (vmAddr_ != MAP_FAILED) { + munmap(vmAddr_, IPC_MMAP_SIZE); + vmAddr_ = MAP_FAILED; + } + + if (driverFD_ >= 0) { + close(driverFD_); + driverFD_ = -1; + } +}; + +bool BinderConnector::IsDriverAlive() +{ + return driverFD_ >= 0; +} + +bool BinderConnector::OpenDriver() +{ + int fd = open(deviceName_.c_str(), O_RDWR); + if (fd < 0) { + ZLOGE(LABEL, "%s:fail to open", __func__); +#ifndef BUILD_PUBLIC_VERSION + ReportEvent(DbinderErrorCode::KERNEL_DRIVER_ERROR, DbinderErrorCode::ERROR_CODE, + DbinderErrorCode::OPEN_IPC_DRIVER_FAILURE); +#endif + return false; + } + + ZLOGI(LABEL, "%s:succ to open, fd=%d", __func__, fd); + driverFD_ = fd; + vmAddr_ = mmap(0, IPC_MMAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, driverFD_, 0); + if (vmAddr_ == MAP_FAILED) { + ZLOGE(LABEL, "%s:fail to mmap\n", __func__); + close(driverFD_); + driverFD_ = -1; +#ifndef BUILD_PUBLIC_VERSION + ReportEvent(DbinderErrorCode::KERNEL_DRIVER_ERROR, DbinderErrorCode::ERROR_CODE, + DbinderErrorCode::OPEN_IPC_DRIVER_FAILURE); +#endif + return false; + } + + return true; +} + +int BinderConnector::WriteBinder(unsigned long request, void *value) +{ + int err = -EINTR; + + while (err == -EINTR) { + if (ioctl(driverFD_, request, value) >= 0) { + err = ERR_NONE; + } else { + err = -errno; + } + + if (err == -EINTR) { + ZLOGE(LABEL, "%s:ioctl_binder returned EINTR", __func__); +#ifndef BUILD_PUBLIC_VERSION + ReportEvent(DbinderErrorCode::KERNEL_DRIVER_ERROR, DbinderErrorCode::ERROR_CODE, + DbinderErrorCode::WRITE_IPC_DRIVER_FAILURE); +#endif + } + } + + return err; +} + +void BinderConnector::ExitCurrentThread(unsigned long request) +{ + if (driverFD_ > 0) { + ioctl(driverFD_, request, 0); + } +} + +BinderConnector *BinderConnector::GetInstance() +{ + if (instance_ == nullptr) { + std::lock_guard lockGuard(skeletonMutex); + if (instance_ == nullptr) { + BinderConnector *temp = new BinderConnector(DRIVER_NAME); + if (!temp->OpenDriver()) { + delete temp; + temp = nullptr; + } + instance_ = temp; + } + } + + return instance_; +} +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS diff --git a/ipc/native/src/mock/source/binder_debug.cpp b/ipc/native/src/mock/source/binder_debug.cpp new file mode 100755 index 00000000..b15cb3dd --- /dev/null +++ b/ipc/native/src/mock/source/binder_debug.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_debug.h" +#include "sys_binder.h" + +namespace OHOS { +const std::string &BinderDebug::ToString(int value) +{ + static BinderDebug instance; + return instance.GetErrorDesc(value); +} + +ErrorMap &BinderDebug::GetErrorMap() +{ + static ErrorMap errorMap = { { BR_ERROR, "BR_ERROR" }, + { BR_OK, "BR_OK" }, + { BR_TRANSACTION, "BR_TRANSACTION" }, + { BR_REPLY, "BR_REPLY" }, + { BR_ACQUIRE_RESULT, "BR_ACQUIRE_RESULT" }, + { BR_DEAD_REPLY, "BR_DEAD_REPLY" }, + { BR_TRANSACTION_COMPLETE, "BR_TRANSACTION_COMPLETE" }, + { BR_INCREFS, "BR_INCREFS" }, + { BR_ACQUIRE, "BR_ACQUIRE" }, + { BR_RELEASE, "BR_RELEASE" }, + { BR_DECREFS, "BR_DECREFS" }, + { BR_ATTEMPT_ACQUIRE, "BR_ATTEMPT_ACQUIRE" }, + { BR_NOOP, "BR_NOOP" }, + { BR_SPAWN_LOOPER, "BR_SPAWN_LOOPER" }, + { BR_FINISHED, "BR_FINISHED" }, + { BR_DEAD_BINDER, "BR_DEAD_BINDER" }, + { BR_CLEAR_DEATH_NOTIFICATION_DONE, "BR_CLEAR_DEATH_NOTIFICATION_DONE" }, + { BR_FAILED_REPLY, "BR_FAILED_REPLY" }, + { BC_TRANSACTION, "BC_TRANSACTION" }, + { BC_REPLY, "BC_REPLY" }, + { BC_ACQUIRE_RESULT, "BC_ACQUIRE_RESULT" }, + { BC_FREE_BUFFER, "BC_FREE_BUFFER" }, + { BC_INCREFS, "BC_INCREFS" }, + { BC_ACQUIRE, "BC_ACQUIRE" }, + { BC_RELEASE, "BC_RELEASE" }, + { BC_DECREFS, "BC_DECREFS" }, + { BC_INCREFS_DONE, "BC_INCREFS_DONE" }, + { BC_ACQUIRE_DONE, "BC_ACQUIRE_DONE" }, + { BC_ATTEMPT_ACQUIRE, "BC_ATTEMPT_ACQUIRE" }, + { BC_REGISTER_LOOPER, "BC_REGISTER_LOOPER" }, + { BC_ENTER_LOOPER, "BC_ENTER_LOOPER" }, + { BC_EXIT_LOOPER, "BC_EXIT_LOOPER" }, + { BC_REQUEST_DEATH_NOTIFICATION, "BC_REQUEST_DEATH_NOTIFICATION" }, + { BC_CLEAR_DEATH_NOTIFICATION, "BC_CLEAR_DEATH_NOTIFICATION" }, + { BC_DEAD_BINDER_DONE, "BC_DEAD_BINDER_DONE" } }; + return errorMap; +} +} // namespace OHOS \ No newline at end of file diff --git a/ipc/native/src/mock/source/binder_invoker.cpp b/ipc/native/src/mock/source/binder_invoker.cpp new file mode 100755 index 00000000..23c52969 --- /dev/null +++ b/ipc/native/src/mock/source/binder_invoker.cpp @@ -0,0 +1,951 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_invoker.h" +#include "string_ex.h" +#include "sys_binder.h" +#include "hilog/log.h" +#include "binder_debug.h" +#include "ipc_object_stub.h" +#include "ipc_object_proxy.h" +#include "ipc_process_skeleton.h" +#include "ipc_thread_skeleton.h" +#ifndef CONFIG_STANDARD_SYSTEM +#include "hitrace_invoker.h" +#endif +#include "dbinder_error_code.h" +#include "log_tags.h" + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif + +using namespace OHOS::HiviewDFX; +static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "BinderInvoker" }; +enum { + GET_SERVICE_TRANSACTION = 0x1, + CHECK_SERVICE_TRANSACTION, + ADD_SERVICE_TRANSACTION, +}; + +BinderInvoker::BinderInvoker() + : isMainWorkThread(false), stopWorkThread(false), callerPid_(getpid()), callerUid_(getuid()), status_(0) +{ + input_.SetDataCapacity(IPC_DEFAULT_PARCEL_SIZE); + binderConnector_ = BinderConnector::GetInstance(); +} + +bool BinderInvoker::AcquireHandle(int32_t handle) +{ + size_t rewindPos = output_.GetWritePosition(); + if (!output_.WriteUint32(BC_ACQUIRE)) { + return false; + } + + if (!output_.WriteInt32(handle)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + return false; + } + /* invoke remote to receive acquire handle event, don't care ping result */ + if (handle != 0) { + (void)PingService(handle); + } + + ZLOGI(LABEL, "Acquire Handle %{public}d", handle); + return true; +} + +bool BinderInvoker::ReleaseHandle(int32_t handle) +{ + size_t rewindPos = output_.GetWritePosition(); + if (!output_.WriteUint32(BC_RELEASE)) { + return false; + } + + if (!output_.WriteInt32(handle)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + return false; + } + + ZLOGI(LABEL, "Release Handle %{public}d", handle); + FlushCommands(nullptr); + return true; +} + +int BinderInvoker::SendRequest(int handle, uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + int error = ERR_NONE; + uint32_t flags = option.GetFlags(); + ZLOGI(LABEL, "%{public}s: handle=%d ,flags:%d", __func__, handle, flags); + MessageParcel &newData = const_cast(data); + size_t oldWritePosition = newData.GetWritePosition(); +#ifndef CONFIG_STANDARD_SYSTEM + HiTraceId traceId = HiTrace::GetId(); + // set client send trace point if trace is enabled + HiTraceId childId = HitraceInvoker::TraceClientSend(handle, code, newData, flags, traceId); +#endif + if (!WriteTransaction(BC_TRANSACTION, flags, handle, code, data, nullptr)) { + newData.RewindWrite(oldWritePosition); + ZLOGE(LABEL, "WriteTransaction ERROR"); +#ifndef BUILD_PUBLIC_VERSION + ReportDriverEvent(DbinderErrorCode::COMMON_DRIVER_ERROR, DbinderErrorCode::ERROR_TYPE, + DbinderErrorCode::IPC_DRIVER, DbinderErrorCode::ERROR_CODE, DbinderErrorCode::TRANSACT_DATA_FAILURE); +#endif + return IPC_INVOKER_WRITE_TRANS_ERR; + } + + if ((flags & TF_ONE_WAY) != 0) { + error = WaitForCompletion(nullptr); + } else { + error = WaitForCompletion(&reply); + } +#ifndef CONFIG_STANDARD_SYSTEM + HitraceInvoker::TraceClientReceieve(handle, code, flags, traceId, childId); +#endif + // restore Parcel data + newData.RewindWrite(oldWritePosition); + ZLOGI(LABEL, "%{public}s: handle=%d result = %{public}d", __func__, handle, error); + return error; +} + +bool BinderInvoker::AddDeathRecipient(int32_t handle, void *cookie) +{ + ZLOGI(LABEL, "BinderInvoker::AddDeathRecipient for handle:%d", handle); + size_t rewindPos = output_.GetWritePosition(); + if (!output_.WriteInt32(BC_REQUEST_DEATH_NOTIFICATION)) { + ZLOGE(LABEL, "fail to write command field:%d", handle); + return false; + } + + if (!output_.WriteInt32(handle)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + return false; + } + + if (!output_.WritePointer((uintptr_t)cookie)) { + /* rewind written size notification and handle. */ + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + return false; + } + + // pass in nullptr directly + int error = FlushCommands(nullptr); + if (error == ERR_NONE) { + auto *proxy = reinterpret_cast(cookie); + if (proxy != nullptr) { + proxy->IncStrongRef(this); + } + } + return error == ERR_NONE; +} + +bool BinderInvoker::RemoveDeathRecipient(int32_t handle, void *cookie) +{ + size_t rewindPos = output_.GetWritePosition(); + if (!output_.WriteInt32(BC_CLEAR_DEATH_NOTIFICATION)) { + return false; + } + + if (!output_.WriteInt32(handle)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + return false; + } + + if (!output_.WritePointer((uintptr_t)cookie)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + return false; + } + + // pass in nullptr directly + int error = FlushCommands(nullptr); + if (error != ERR_NONE) { + ZLOGE(LABEL, "Remove Death Recipient handle =%{public}d result = %{public}d", handle, error); + return false; + } + + return true; +} + +int BinderInvoker::GetObjectRefCount(const IRemoteObject *object) +{ + if ((binderConnector_ == nullptr) || (!binderConnector_->IsDriverAlive())) { + return 0; + } + + struct binder_ptr_count refs; + refs.ptr = reinterpret_cast(object); + + int error = binderConnector_->WriteBinder(BINDER_GET_NODE_REFCOUNT, &refs); + if (error != ERR_NONE) { + ZLOGE(LABEL, "GetSRefCount error = %{public}d", error); + return 0; + } + return refs.count; +} + +#ifndef CONFIG_IPC_SINGLE +int BinderInvoker::TranslateProxy(uint32_t handle, uint32_t flag) +{ + binder_node_debug_info info {}; + if ((binderConnector_ == nullptr) || (!binderConnector_->IsDriverAlive())) { + return -IPC_INVOKER_CONNECT_ERR; + } + info.has_strong_ref = handle; + info.has_weak_ref = flag; + ZLOGI(LABEL, "TranslateProxy input handle = %{public}u", info.has_strong_ref); + int error = binderConnector_->WriteBinder(BINDER_TRANSLATE_HANDLE, &info); + if (error == ERR_NONE && info.has_strong_ref > 0) { + ZLOGI(LABEL, "TranslateProxy get new handle = %{public}u", info.has_strong_ref); + return info.has_strong_ref; + } + ZLOGE(LABEL, "failed to translateProxy input handle = %{public}u", info.has_strong_ref); + return -IPC_INVOKER_TRANSLATE_ERR; +} + +int BinderInvoker::TranslateStub(binder_uintptr_t cookie, binder_uintptr_t ptr, uint32_t flag, int cmd) +{ + binder_node_debug_info info {}; + if ((binderConnector_ == nullptr) || (!binderConnector_->IsDriverAlive())) { + return -IPC_INVOKER_CONNECT_ERR; + } + info.cookie = cookie; + info.ptr = ptr; + info.has_weak_ref = cmd; + info.has_strong_ref = flag; + int error = binderConnector_->WriteBinder(BINDER_TRANSLATE_HANDLE, &info); + if (error == ERR_NONE && info.has_strong_ref > 0) { + ZLOGI(LABEL, "TranslateStub get new handle = %{public}u", info.has_strong_ref); + return info.has_strong_ref; + } + ZLOGE(LABEL, "failed to TranslateStub"); + return -IPC_INVOKER_TRANSLATE_ERR; +} + +sptr BinderInvoker::GetSAMgrObject() +{ + return nullptr; +} + +#endif +bool BinderInvoker::SetMaxWorkThread(int maxThreadNum) +{ + if ((binderConnector_ == nullptr) || (!binderConnector_->IsDriverAlive())) { + ZLOGE(LABEL, "%{public}s driver died", __func__); + return false; + } + + int error = binderConnector_->WriteBinder(BINDER_SET_MAX_THREADS, &maxThreadNum); + if (error != ERR_NONE) { + ZLOGE(LABEL, "SetMaxWorkThread error = %{public}d", error); + return false; + } + + return true; +} + +int BinderInvoker::FlushCommands(IRemoteObject *object) +{ + if ((binderConnector_ == nullptr) || (!binderConnector_->IsDriverAlive())) { + ZLOGE(LABEL, "driver is died"); + return IPC_INVOKER_CONNECT_ERR; + } + int error = TransactWithDriver(false); + if (error != ERR_NONE) { + ZLOGE(LABEL, "fail to flush commands with error = %{public}d", error); + } + + if (output_.GetDataSize() > 0) { + error = TransactWithDriver(false); + ZLOGE(LABEL, "flush commands again with return value = %{public}d", error); + } + if (error != ERR_NONE || output_.GetDataSize() > 0) { + ZLOGE(LABEL, "flush commands with error = %{public}d, left data size = %{public}zu", error, + output_.GetDataSize()); + } + + return error; +} + +void BinderInvoker::ExitCurrentThread() +{ + if ((binderConnector_ == nullptr) || (!binderConnector_->IsDriverAlive())) { + ZLOGE(LABEL, "%{public}s driver died when exit current thread", __func__); + return; + } + binderConnector_->ExitCurrentThread(BINDER_THREAD_EXIT); +} + +void BinderInvoker::StartWorkLoop() +{ + int error; + do { + error = TransactWithDriver(); + if (error < ERR_NONE && error != -ECONNREFUSED && error != -EBADF) { + ZLOGE(LABEL, "returned unexpected error %d, aborting", error); + abort(); + } + uint32_t cmd = input_.ReadUint32(); + int userError = HandleCommands(cmd); + if ((userError == -ERR_TIMED_OUT || userError == IPC_INVOKER_INVALID_DATA_ERR) && !isMainWorkThread) { + break; + } + } while (error != -ECONNREFUSED && error != -EBADF && !stopWorkThread); +} + +int BinderInvoker::SendReply(MessageParcel &reply, uint32_t flags, int32_t result) +{ + int error = WriteTransaction(BC_REPLY, flags, -1, 0, reply, &result); + if (error < ERR_NONE) { + return error; + } + + return WaitForCompletion(); +} + +void BinderInvoker::OnBinderDied() +{ + uintptr_t cookie = input_.ReadPointer(); + auto *proxy = reinterpret_cast(cookie); + ZLOGI(LABEL, "%s", __func__); + if (proxy != nullptr) { + proxy->SendObituary(); + } + + size_t rewindPos = output_.GetWritePosition(); + if (!output_.WriteInt32(BC_DEAD_BINDER_DONE)) { + return; + } + + if (!output_.WritePointer((uintptr_t)cookie)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + } +} + +void BinderInvoker::OnAcquireObject(uint32_t cmd) +{ + bool ParcelResult = false; + uintptr_t refsPointer = input_.ReadPointer(); + uintptr_t objectPointer = input_.ReadPointer(); + RefBase *refs = reinterpret_cast(refsPointer); + if ((refs == nullptr) || (!objectPointer)) { + ZLOGE(LABEL, "OnAcquireObject FAIL!"); + return; + } + + ZLOGI(LABEL, "OnAcquireObject refcount=%{public}d", refs->GetSptrRefCount()); + + size_t rewindPos = output_.GetWritePosition(); + if (cmd == BR_ACQUIRE) { + refs->IncStrongRef(this); + ParcelResult = output_.WriteInt32(BC_ACQUIRE_DONE); + } else { + refs->IncWeakRef(this); + ParcelResult = output_.WriteInt32(BC_INCREFS_DONE); + } + + if (!ParcelResult || !output_.WritePointer(refsPointer)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + return; + } + + if (!output_.WritePointer(objectPointer)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + } +} + +void BinderInvoker::OnReleaseObject(uint32_t cmd) +{ + uintptr_t refsPointer = input_.ReadPointer(); + uintptr_t objectPointer = input_.ReadPointer(); + auto *refs = reinterpret_cast(refsPointer); + auto *object = reinterpret_cast(objectPointer); + if ((refs == nullptr) || (object == nullptr)) { + ZLOGE(LABEL, "OnReleaseObject FAIL!"); + return; + } + + ZLOGI(LABEL, "OnReleaseObject refcount=%{public}d", refs->GetSptrRefCount()); + + if (cmd == BR_RELEASE) { + refs->DecStrongRef(this); + } else { + refs->DecWeakRef(this); + } +} + +void BinderInvoker::OnTransaction(const uint8_t *buffer) +{ + const binder_transaction_data *tr = reinterpret_cast(buffer); + auto data = std::make_unique(new BinderAllocator()); + data->ParseFrom(tr->data.ptr.buffer, tr->data_size); + if (tr->offsets_size > 0) { + data->InjectOffsets(tr->data.ptr.offsets, tr->offsets_size / sizeof(binder_size_t)); + } +#ifndef CONFIG_STANDARD_SYSTEM + uint32_t &newflags = const_cast(tr->flags); + int isServerTraced = HitraceInvoker::TraceServerReceieve(tr->target.handle, tr->code, *data, newflags); +#endif + const pid_t oldPid = callerPid_; + const auto oldUid = static_cast(callerUid_); + callerPid_ = tr->sender_pid; + callerUid_ = tr->sender_euid; + SetStatus(IRemoteInvoker::ACTIVE_INVOKER); + int error = ERR_DEAD_OBJECT; + sptr targetObject; + if (tr->target.ptr != 0) { + auto *refs = reinterpret_cast(tr->target.ptr); + if ((refs != nullptr) && (tr->cookie) && (refs->AttemptIncStrongRef(this))) { + targetObject = reinterpret_cast(tr->cookie); + targetObject->DecStrongRef(this); + } + } else { + targetObject = IPCProcessSkeleton::GetCurrent()->GetRegistryObject(); + } + MessageParcel reply; + MessageOption option; + uint32_t flagValue = static_cast(tr->flags) & ~static_cast(MessageOption::TF_ACCEPT_FDS); + if (targetObject != nullptr) { + option.SetFlags(static_cast(flagValue)); + error = targetObject->SendRequest(tr->code, *data, reply, option); + } +#ifndef CONFIG_STANDARD_SYSTEM + HitraceInvoker::TraceServerSend(tr->target.handle, tr->code, isServerTraced, newflags); +#endif + if (!(flagValue & TF_ONE_WAY)) { + SendReply(reply, 0, error); + } + callerPid_ = oldPid; + callerUid_ = oldUid; + SetStatus(IRemoteInvoker::IDLE_INVOKER); +} + +void BinderInvoker::OnAttemptAcquire() +{ + bool success = false; + uintptr_t refsPtr = input_.ReadPointer(); + uintptr_t objectPtr = input_.ReadPointer(); + auto *refs = reinterpret_cast(refsPtr); + + size_t rewindPos = output_.GetWritePosition(); + if ((refs != nullptr) && (!objectPtr)) { + ZLOGI(LABEL, "OnAttemptAcquire refcount=%{public}d", refs->GetSptrRefCount()); + success = refs->AttemptIncStrongRef(this); + } + + if (!output_.WriteUint32(BC_ACQUIRE_RESULT)) { + return; + } + + if (!output_.WriteUint32((uint32_t)success)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + } +} + +void BinderInvoker::OnRemoveRecipientDone() +{ + uintptr_t cookie = input_.ReadPointer(); + auto *proxy = reinterpret_cast(cookie); + if (proxy != nullptr) { + proxy->DecStrongRef(this); + } +} + +int BinderInvoker::HandleReply(MessageParcel *reply) +{ + const size_t readSize = sizeof(binder_transaction_data); + const uint8_t *buffer = input_.ReadBuffer(readSize); + if (buffer == nullptr) { + ZLOGE(LABEL, "HandleReply read tr failed"); + return IPC_INVOKER_INVALID_DATA_ERR; + } + const binder_transaction_data *tr = reinterpret_cast(buffer); + + if (reply == nullptr) { + ZLOGI(LABEL, "no need reply, free the buffer"); + FreeBuffer(reinterpret_cast(tr->data.ptr.buffer)); + return IPC_INVOKER_INVALID_REPLY_ERR; + } + + if (tr->flags & TF_STATUS_CODE) { + int32_t status = *reinterpret_cast(tr->data.ptr.buffer); + ZLOGI(LABEL, "received status code:%{public}d, free the buffer", status); + FreeBuffer(reinterpret_cast(tr->data.ptr.buffer)); + return status; + } + + if (tr->data_size > 0) { + auto allocator = new BinderAllocator(); + if (!reply->SetAllocator(allocator)) { + ZLOGI(LABEL, "SetAllocator failed"); + delete allocator; + FreeBuffer(reinterpret_cast(tr->data.ptr.buffer)); + return IPC_INVOKER_INVALID_DATA_ERR; + } + reply->ParseFrom(tr->data.ptr.buffer, tr->data_size); + } + + if (tr->offsets_size > 0) { + reply->InjectOffsets(tr->data.ptr.offsets, tr->offsets_size / sizeof(binder_size_t)); + reply->SetClearFdFlag(); + } + return ERR_NONE; +} + +int BinderInvoker::HandleCommands(uint32_t cmd) +{ + int error = ERR_NONE; + ZLOGI(LABEL, "HandleCommands:cmd=[%u]:%{public}s\n", cmd, BinderDebug::ToString(cmd).c_str()); + switch (cmd) { + case BR_ERROR: + error = input_.ReadInt32(); + break; + case BR_ACQUIRE: + case BR_INCREFS: + OnAcquireObject(cmd); + break; + case BR_RELEASE: + case BR_DECREFS: + OnReleaseObject(cmd); + break; + case BR_ATTEMPT_ACQUIRE: + OnAttemptAcquire(); + break; + case BR_TRANSACTION: { + const uint8_t *buffer = input_.ReadBuffer(sizeof(binder_transaction_data)); + if (buffer == nullptr) { + error = IPC_INVOKER_INVALID_DATA_ERR; + break; + } + OnTransaction(buffer); + break; + } + case BR_SPAWN_LOOPER: { + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current != nullptr) { + current->SpawnThread(); + } + break; + } + case BR_FINISHED: + error = -ERR_TIMED_OUT; + break; + case BR_DEAD_BINDER: + OnBinderDied(); + break; + case BR_CLEAR_DEATH_NOTIFICATION_DONE: + OnRemoveRecipientDone(); + break; + case BR_OK: + case BR_NOOP: + break; + default: + error = IPC_INVOKER_ON_TRANSACT_ERR; + break; + } + if (error != ERR_NONE) { + ZLOGE(LABEL, "HandleCommands cmd = %{public}u(%{public}s), error = %{public}d", cmd, + BinderDebug::ToString(cmd).c_str(), error); + } + + return error; +} + +void BinderInvoker::JoinThread(bool initiative) +{ + isMainWorkThread = initiative; + output_.WriteUint32(initiative ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); + StartWorkLoop(); + output_.WriteUint32(BC_EXIT_LOOPER); + // pass in nullptr directly + FlushCommands(nullptr); + ZLOGE(LABEL, "Current Thread %d is leaving", getpid()); +} + +void BinderInvoker::JoinProcessThread(bool initiative) {} + +int BinderInvoker::TransactWithDriver(bool doRead) +{ + if ((binderConnector_ == nullptr) || (!binderConnector_->IsDriverAlive())) { + ZLOGE(LABEL, "%{public}s: Binder Driver died", __func__); + return IPC_INVOKER_CONNECT_ERR; + } + + binder_write_read bwr; + const bool readAvail = input_.GetReadableBytes() == 0; + const size_t outAvail = (!doRead || readAvail) ? output_.GetDataSize() : 0; + + bwr.write_size = (binder_size_t)outAvail; + bwr.write_buffer = output_.GetData(); + + if (doRead && readAvail) { + bwr.read_size = input_.GetDataCapacity(); + bwr.read_buffer = input_.GetData(); + } else { + bwr.read_size = 0; + bwr.read_buffer = 0; + } + if ((bwr.write_size == 0) && (bwr.read_size == 0)) { + return ERR_NONE; + } + + bwr.write_consumed = 0; + bwr.read_consumed = 0; + ZLOGI(LABEL, "TransactWithDriver write_size:%lld, read_size:%lld\n", bwr.write_size, bwr.read_size); + int error = binderConnector_->WriteBinder(BINDER_WRITE_READ, &bwr); + if (bwr.write_consumed > 0) { + if (bwr.write_consumed < output_.GetDataSize()) { + // we still have some bytes not been handled. + } else { + output_.FlushBuffer(); + } + } + if (bwr.read_consumed > 0) { + input_.SetDataSize(bwr.read_consumed); + input_.RewindRead(0); + } + if (error != ERR_NONE) { + ZLOGE(LABEL, "TransactWithDriver result = %{public}d\n", error); + } + + return error; +} + +bool BinderInvoker::WriteTransaction(int cmd, uint32_t flags, int32_t handle, uint32_t code, const MessageParcel &data, + const int32_t *status) +{ + binder_transaction_data tr {}; + tr.target.handle = (uint32_t)handle; + tr.code = code; + tr.flags = flags; + tr.flags |= TF_ACCEPT_FDS; + if (data.GetDataSize() > 0) { + // Send this parcel's data through the binder. + tr.data_size = data.GetDataSize(); + tr.data.ptr.buffer = (binder_uintptr_t)data.GetData(); + tr.offsets_size = data.GetOffsetsSize() * sizeof(binder_size_t); + tr.data.ptr.offsets = data.GetObjectOffsets(); + } else if (status != nullptr) { + // Send this parcel's status through the binder. + tr.flags |= TF_STATUS_CODE; + tr.data_size = sizeof(int32_t); + tr.data.ptr.buffer = reinterpret_cast(status); + tr.offsets_size = 0; + tr.data.ptr.offsets = 0; + } + + if (!output_.WriteInt32(cmd)) { + ZLOGE(LABEL, "WriteTransaction Command failure"); + return false; + } + + return output_.WriteBuffer(&tr, sizeof(binder_transaction_data)); +} + +int BinderInvoker::WaitForCompletion(MessageParcel *reply, int32_t *acquireResult) +{ + uint32_t cmd; + bool continueLoop = true; + int error = ERR_NONE; + while (continueLoop) { + if ((error = TransactWithDriver()) < ERR_NONE) { + break; + } + if (input_.GetReadableBytes() == 0) { + continue; + } + cmd = input_.ReadUint32(); + switch (cmd) { + case BR_TRANSACTION_COMPLETE: { + if (reply == nullptr && acquireResult == nullptr) { + continueLoop = false; + } + break; + } + case BR_DEAD_REPLY: // fall-through + case BR_FAILED_REPLY: { + error = cmd; + if (acquireResult != nullptr) { + *acquireResult = cmd; + } + continueLoop = false; + break; + } + case BR_ACQUIRE_RESULT: { + int32_t result = input_.ReadInt32(); + if (acquireResult != nullptr) { + *acquireResult = result ? ERR_NONE : ERR_INVALID_OPERATION; + continueLoop = false; + } + break; + } + case BR_REPLY: { + error = HandleReply(reply); + if (error != IPC_INVOKER_INVALID_REPLY_ERR) { + continueLoop = false; + break; + } + error = ERR_NONE; + break; + } + default: { + error = HandleCommands(cmd); + if (error != ERR_NONE) { + continueLoop = false; + } + break; + } + } + } + return error; +} + +void BinderInvoker::StopWorkThread() +{ + stopWorkThread = true; +} + +bool BinderInvoker::PingService(int32_t handle) +{ + MessageParcel data, reply; + MessageOption option; + int result = SendRequest(handle, PING_TRANSACTION, data, reply, option); + return (result == ERR_NONE); +} + +bool BinderInvoker::SetRegistryObject(sptr &object) +{ + if ((binderConnector_ == nullptr) || (!binderConnector_->IsDriverAlive())) { + return false; + } + + if (object->IsProxyObject()) { + ZLOGE(LABEL, "%{public}s: set wrong object!", __func__); + return false; + } + + Parcel dummy; + int result = binderConnector_->WriteBinder(BINDER_SET_CONTEXT_MGR, &dummy); + if (result != ERR_NONE) { + ZLOGE(LABEL, "%{public}s:set registry fail, driver error %{public}d", __func__, result); + return false; + } + + return true; +} + +void BinderInvoker::FreeBuffer(void *data) +{ + size_t rewindPos = output_.GetWritePosition(); + if (!output_.WriteUint32(BC_FREE_BUFFER)) { + return; + } + + if (!output_.WritePointer((uintptr_t)data)) { + if (!output_.RewindWrite(rewindPos)) { + output_.FlushBuffer(); + } + } +} + +void BinderInvoker::BinderAllocator::Dealloc(void *data) +{ + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + if (invoker != nullptr) { + invoker->FreeBuffer(data); + } +} + +pid_t BinderInvoker::GetCallerPid() const +{ + return callerPid_; +} + +uid_t BinderInvoker::GetCallerUid() const +{ + return callerUid_; +} + +uint32_t BinderInvoker::GetStatus() const +{ + return status_; +} + +void BinderInvoker::SetStatus(uint32_t status) +{ + status_ = status; +} + +std::string BinderInvoker::GetLocalDeviceID() +{ + return ""; +} + +std::string BinderInvoker::GetCallerDeviceID() const +{ + return ""; +} + +bool BinderInvoker::IsLocalCalling() +{ + return true; +} + +bool BinderInvoker::FlattenObject(Parcel &parcel, const IRemoteObject *object) const +{ + if (object == nullptr) { + return false; + } + flat_binder_object flat; + if (object->IsProxyObject()) { + const IPCObjectProxy *proxy = reinterpret_cast(object); + const int32_t handle = proxy ? proxy->GetHandle() : -1; + flat.hdr.type = BINDER_TYPE_HANDLE; + flat.binder = 0; + flat.handle = (uint32_t)handle; + flat.cookie = proxy ? static_cast(proxy->GetProto()) : 0; + } else { + flat.hdr.type = BINDER_TYPE_BINDER; + flat.binder = reinterpret_cast(object); + flat.cookie = flat.binder; + } + + flat.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; + bool status = parcel.WriteBuffer(&flat, sizeof(flat_binder_object)); + if (!status) { + ZLOGE(LABEL, "Fail to flatten object"); +#ifndef BUILD_PUBLIC_VERSION + ReportDriverEvent(DbinderErrorCode::COMMON_DRIVER_ERROR, DbinderErrorCode::ERROR_TYPE, + DbinderErrorCode::IPC_DRIVER, DbinderErrorCode::ERROR_CODE, DbinderErrorCode::FLATTEN_OBJECT_FAILURE); +#endif + } + return status; +} + +IRemoteObject *BinderInvoker::UnflattenObject(Parcel &parcel) +{ + const uint8_t *buffer = parcel.ReadBuffer(sizeof(flat_binder_object)); + if (buffer == nullptr) { + ZLOGE(LABEL, "UnflattenObject null object buffer"); + return nullptr; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + return nullptr; + } + + IRemoteObject *remoteObject = nullptr; + auto *flat = reinterpret_cast(buffer); + switch (flat->hdr.type) { + case BINDER_TYPE_BINDER: { + remoteObject = reinterpret_cast(flat->cookie); + if (!current->IsContainsObject(remoteObject)) { + remoteObject = nullptr; + } + break; + } + case BINDER_TYPE_REMOTE_HANDLE: + case BINDER_TYPE_HANDLE: { + remoteObject = current->FindOrNewObject(flat->handle); + break; + } + default: + ZLOGE(LABEL, "%s: unknown binder type %u", __func__, flat->hdr.type); + remoteObject = nullptr; + break; + } + + return remoteObject; +} + +int BinderInvoker::ReadFileDescriptor(Parcel &parcel) +{ + int fd = -1; + const uint8_t *buffer = parcel.ReadBuffer(sizeof(flat_binder_object)); + if (buffer == nullptr) { + ZLOGE(LABEL, "UnflattenObject null object buffer"); + return fd; + } + + auto *flat = reinterpret_cast(buffer); + if (flat->hdr.type == BINDER_TYPE_FD || flat->hdr.type == BINDER_TYPE_FDR) { + fd = flat->handle; + ZLOGW(LABEL, "%s:%d : fd = %d", __func__, __LINE__, fd); + } else { + ZLOGE(LABEL, "%s: unknown binder type %u", __func__, flat->hdr.type); + } + + return fd; +} + +bool BinderInvoker::WriteFileDescriptor(Parcel &parcel, int fd, bool takeOwnership) +{ + flat_binder_object flat; + flat.hdr.type = BINDER_TYPE_FD; + flat.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; + flat.binder = 0; // Don't pass uninitialized stack data to a remote process + flat.handle = fd; + flat.cookie = takeOwnership ? 1 : 0; + + ZLOGW(LABEL, "%s(%d) write fd : %d", __func__, __LINE__, fd); + return parcel.WriteBuffer(&flat, sizeof(flat_binder_object)); +} + +std::string BinderInvoker::ResetCallingIdentity() +{ + int64_t identity = (static_cast(callerUid_) << PID_LEN) | callerPid_; + callerUid_ = getuid(); + callerPid_ = getpid(); + return std::to_string(identity); +} + +bool BinderInvoker::SetCallingIdentity(std::string &identity) +{ + if (identity.empty()) { + return false; + } + + int64_t token = std::atoll(identity.c_str()); + callerUid_ = static_cast(token >> PID_LEN); + callerPid_ = static_cast(token); + + return true; +} +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS diff --git a/ipc/native/src/mock/source/dbinder_databus_invoker.cpp b/ipc/native/src/mock/source/dbinder_databus_invoker.cpp new file mode 100755 index 00000000..7d0681cc --- /dev/null +++ b/ipc/native/src/mock/source/dbinder_databus_invoker.cpp @@ -0,0 +1,892 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_databus_invoker.h" +#include +#include "string_ex.h" +#include "securec.h" +#include "sys_binder.h" + +#include "ipc_object_stub.h" +#include "ipc_object_proxy.h" +#include "ipc_process_skeleton.h" +#include "ipc_thread_skeleton.h" +#include "ipc_debug.h" +#include "log_tags.h" +#include "databus_session_callback.h" + +namespace OHOS { +using namespace OHOS::HiviewDFX; + +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "DBinderDatabusInvoker" }; +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +DBinderDatabusInvoker::DBinderDatabusInvoker() + : stopWorkThread_(false), callerPid_(getpid()), callerUid_(getuid()), callerDeviceID_(""), status_(0) +{ + DBINDER_LOGI("Create DBinderDatabusInvoker"); +} + +DBinderDatabusInvoker::~DBinderDatabusInvoker() +{ + DBINDER_LOGI("Clean DBinderDatabusInvoker"); +} + +bool DBinderDatabusInvoker::AcquireHandle(int32_t handle) +{ + DBINDER_LOGI("Acquire Handle %{public}d", handle); + return true; +} + +bool DBinderDatabusInvoker::ReleaseHandle(int32_t handle) +{ + DBINDER_LOGI("Release Handle %{public}d", handle); + return true; +} + +std::shared_ptr DBinderDatabusInvoker::NewSessionOfBinderProxy(uint32_t handle, + std::shared_ptr remoteSession) +{ + if (remoteSession == nullptr) { + DBINDER_LOGE("remote session is nullptr"); + return nullptr; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current ipc process skeleton is nullptr"); + return nullptr; + } + + IPCObjectProxy *ipcProxy = reinterpret_cast(current->FindOrNewObject(handle)); + if (ipcProxy == nullptr) { + DBINDER_LOGE("attempt to send a invalid handle = %u", handle); + return nullptr; + } + + if (ipcProxy->GetProto() != IRemoteObject::IF_PROT_BINDER) { + DBINDER_LOGE("attempt to send a distributed proxy, handle = %u", handle); + return nullptr; + } + + std::string sessionName = ipcProxy->GetPidAndUidInfo(); + if (sessionName.empty()) { + DBINDER_LOGE("get bus name error"); + return nullptr; + } + + std::shared_ptr session = remoteSession->GetBusSession(); + if (session == nullptr) { + DBINDER_LOGE("get databus session fail"); + return nullptr; + } + + MessageParcel data, reply; + if (!data.WriteUint32(IRemoteObject::DATABUS_TYPE) || !data.WriteString(current->GetLocalDeviceID()) || + !data.WriteUint32(session->GetPeerPid()) || !data.WriteUint32(session->GetPeerUid()) || + !data.WriteString(session->GetPeerDeviceId()) || !data.WriteString(sessionName)) { + DBINDER_LOGE("write to parcel fail"); + return nullptr; + } + int err = ipcProxy->InvokeListenThread(data, reply); + if (err != ERR_NONE) { + DBINDER_LOGE("start service listen error = %d", err); + return nullptr; + } + + uint64_t stubIndex = reply.ReadUint64(); + if (stubIndex == 0) { + DBINDER_LOGE("stubindex error = %" PRIu64 "", stubIndex); + return nullptr; + } + + if (!current->AttachHandleToIndex(handle, stubIndex)) { + DBINDER_LOGE("add stub index err stubIndex = %" PRIu64 ", handle = %u", stubIndex, handle); + // do nothing, Sending an object repeatedly + } + + std::string serverName = reply.ReadString(); + std::string deviceId = reply.ReadString(); + DBINDER_LOGI("NewSessionOfBinderProxy serverName= %s", serverName.c_str()); + + std::shared_ptr connectSession = + std::make_shared(nullptr, serverName, deviceId); + if (connectSession == nullptr) { + DBINDER_LOGE("new server session fail!"); + return nullptr; + } + + return connectSession; +} + +bool DBinderDatabusInvoker::AuthSession2Proxy(uint32_t handle, + const std::shared_ptr databusSession) +{ + if (databusSession == nullptr) { + DBINDER_LOGE("remote session is nullptr"); + return false; + } + + std::shared_ptr session = databusSession->GetBusSession(); + if (session == nullptr) { + DBINDER_LOGE("get databus session fail"); + return false; + } + + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteUint32(session->GetPeerPid()) || !data.WriteUint32(session->GetPeerUid()) || + !data.WriteString(session->GetPeerDeviceId())) { + DBINDER_LOGE("write to MessageParcel fail"); + return false; + } + + uint32_t err = SendRequest(handle, DBINDER_ADD_COMMAUTH, data, reply, option); + if (err != ERR_NONE) { + DBINDER_LOGE("send auth info to remote fail"); + return false; + } + return true; +} + +std::shared_ptr DBinderDatabusInvoker::QuerySessionOfBinderProxy(uint32_t handle, + std::shared_ptr session) +{ + if (AuthSession2Proxy(handle, session) != true) { + DBINDER_LOGE("auth handle =%{public}u to session failed", handle); + return nullptr; + } + return QueryServerSessionObject(handle); +} + +std::shared_ptr DBinderDatabusInvoker::QueryClientSessionObject(uint32_t databusHandle) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current ipc process skeleton is nullptr"); + return nullptr; + } + std::shared_ptr sessionOfPeer = current->StubQueryDBinderSession(databusHandle); + if (sessionOfPeer == nullptr) { + DBINDER_LOGE("no session attach to this proxy = %{public}u", databusHandle); + return nullptr; + } + return sessionOfPeer; +} + +std::shared_ptr DBinderDatabusInvoker::QueryServerSessionObject(uint32_t handle) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current ipc process skeleton is nullptr"); + return nullptr; + } + + std::shared_ptr sessionOfPeer = current->ProxyQueryDBinderSession(handle); + if (sessionOfPeer == nullptr) { + DBINDER_LOGI("no session attach to this handle = %{public}u", handle); + return nullptr; + } + + return sessionOfPeer; +} + +bool DBinderDatabusInvoker::OnReceiveNewConnection(std::shared_ptr session) +{ + uint32_t handle = IPCProcessSkeleton::ConvertChannelID2Int(session->GetChannelId()); + if (handle == 0) { + return false; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current ipc process skeleton is nullptr"); + return false; + } + + if (!current->QueryIsAuth(session->GetPeerPid(), session->GetPeerUid(), session->GetPeerDeviceId())) { + DBINDER_LOGE("remote device is not auth"); + return false; + } + + std::shared_ptr sessionObject = + std::make_shared(session, session->GetPeerSessionName(), session->GetPeerDeviceId()); + + if (!current->StubAttachDBinderSession(handle, sessionObject)) { + DBINDER_LOGE("attach session to process skeleton failed, handle =%u", handle); + } + return true; +} + +bool DBinderDatabusInvoker::CreateProcessThread() +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current ipc process skeleton is nullptr"); + return false; + } + /* epoll thread obtained one thread, so idle thread must more than 1 */ + if (current->GetSocketIdleThreadNum() > 0) { + current->SpawnThread(IPCWorkThread::PROCESS_PASSIVE, IRemoteObject::IF_PROT_DATABUS); + DBINDER_LOGI("create Process thread success"); + return true; + } + + DBINDER_LOGE("no idle socket thread left, fail to CreateProcessThread"); + return false; +} + +void DBinderDatabusInvoker::OnRawDataAvailable(std::shared_ptr session, const char *data, uint32_t dataSize) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current ipc process skeleton is nullptr"); + return; + } + + uint32_t rawDataSize = dataSize - sizeof(dbinder_transaction_data); + if (rawDataSize > 0 && rawDataSize <= MAX_RAWDATA_SIZE - sizeof(dbinder_transaction_data)) { + std::shared_ptr invokerRawData = std::make_shared(rawDataSize); + if (memcpy_s(invokerRawData->GetData().get(), rawDataSize, data + sizeof(dbinder_transaction_data), + rawDataSize) != EOK) { + DBINDER_LOGE("memcpy_s failed , size = %u", rawDataSize); + return; + } + if (!current->AttachRawData(IPCProcessSkeleton::ConvertChannelID2Int(session->GetChannelId()), + invokerRawData)) { + return; + } + } + return; +} + +/* + * Write 64K=SOCKET_BUFF_SIZE + * +------------------+-------------------------+----------------| + * |0<---processed--->|Read <----need process-->|<--idle buffer--> + * -cursor + * + * when idle buffer less 1k, move need process to buffer head, then update R/W cursor + * when idle buffer can not put a full package, also move need process package to buffer head + */ +void DBinderDatabusInvoker::OnMessageAvailable(std::shared_ptr session, const char *data, ssize_t len) +{ + if (session == nullptr || data == nullptr || len > static_cast(MAX_RAWDATA_SIZE) || + len < static_cast(sizeof(dbinder_transaction_data))) { + DBINDER_LOGE("session has wrong inputs"); + return; + } + + uint32_t packageSize = HasRawDataPackage(data, len); + if (packageSize > 0) { + // Only one set of big data can be transferred at a time. + return OnRawDataAvailable(session, data, packageSize); + } + + uint32_t handle = IPCProcessSkeleton::ConvertChannelID2Int(session->GetChannelId()); + uint32_t readSize = 0; + do { + packageSize = HasCompletePackage(data, readSize, len); + if (packageSize > 0) { + StartProcessLoop(handle, data + readSize, packageSize); + readSize += packageSize; + } else { + // If the current is abnormal, the subsequent is no longer processed. + break; + } + } while (readSize + sizeof(dbinder_transaction_data) < static_cast(len)); +} + +int DBinderDatabusInvoker::OnSendMessage(std::shared_ptr sessionOfPeer) +{ + if (sessionOfPeer == nullptr) { + DBINDER_LOGE("sessionOfPeer is null"); + return -RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + std::shared_ptr session = sessionOfPeer->GetBusSession(); + if (session == nullptr) { + DBINDER_LOGE("databus session is null"); + return -RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + std::shared_ptr sessionBuff = sessionOfPeer->GetSessionBuff(); + if (sessionBuff == nullptr) { + DBINDER_LOGE("databus session buff is null"); + return -RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + char *sendBuffer = sessionBuff->GetSendBufferAndLock(SOCKET_DEFAULT_BUFF_SIZE); + /* session buffer contain mutex, need release mutex */ + if (sendBuffer == nullptr) { + DBINDER_LOGE("buffer alloc failed in session"); + return -RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + sessionBuff->UpdateSendBuffer(); + size_t writeCursor = sessionBuff->GetSendBufferWriteCursor(); + size_t readCursor = sessionBuff->GetSendBufferReadCursor(); + if (writeCursor <= readCursor) { + sessionBuff->ReleaseSendBufferLock(); + return -RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + size_t size = writeCursor - readCursor; + int ret = session->SendBytes(static_cast(sendBuffer + readCursor), static_cast(size)); + if (ret == 0) { + readCursor += size; + sessionBuff->SetSendBufferReadCursor(readCursor); + sessionBuff->SetSendBufferWriteCursor(writeCursor); + } else { + DBINDER_LOGE("ret = %{public}d, send buffer failed with length = %{public}zu, send in next time", ret, size); + } + sessionBuff->ReleaseSendBufferLock(); + return ret; +} + +int DBinderDatabusInvoker::OnSendRawData(std::shared_ptr session, const void *data, size_t size) +{ + if (session == nullptr) { + DBINDER_LOGE("sessionOfPeer is null"); + return -RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + std::shared_ptr dataBusSession = session->GetBusSession(); + if (dataBusSession == nullptr) { + DBINDER_LOGE("databus session is null"); + return -RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + int ret = dataBusSession->SendBytes(data, size); + if (ret != 0) { + DBINDER_LOGE("ret = %{public}d, send buffer overflow with length = %{public}zu", ret, size); + } + + return ret; +} + +void DBinderDatabusInvoker::JoinThread(bool initiative) {} + +void DBinderDatabusInvoker::JoinProcessThread(bool initiative) +{ + std::thread::id threadId = std::this_thread::get_id(); + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current ipc process skeleton is nullptr"); + return; + } + + std::shared_ptr processInfo = nullptr; + do { + current->AddDataThreadInWait(threadId); + while ((processInfo = current->PopDataInfoFromThread(threadId)) != nullptr) { + OnTransaction(processInfo); + } + } while (!stopWorkThread_); +} + +void DBinderDatabusInvoker::StopWorkThread() +{ + stopWorkThread_ = true; +} + +uint32_t DBinderDatabusInvoker::FlattenSession(char *sessionOffset, + const std::shared_ptr connectSession, uint64_t stubIndex) +{ + FlatDBinderSession *flatSession = reinterpret_cast(sessionOffset); + flatSession->stubIndex = stubIndex; + + flatSession->deviceIdLength = connectSession->GetDeviceId().length(); + if (flatSession->deviceIdLength == 0 || flatSession->deviceIdLength > DEVICEID_LENGTH) { + DBINDER_LOGE("wrong devices id"); + return 0; + } + int memcpyResult = memcpy_s(flatSession->deviceId, DEVICEID_LENGTH, connectSession->GetDeviceId().data(), + flatSession->deviceIdLength); + if (memcpyResult != 0) { + DBINDER_LOGE("memcpy_s failed , ID Size = %hu", flatSession->deviceIdLength); + return 0; + } + flatSession->deviceId[flatSession->deviceIdLength] = '\0'; + + flatSession->serviceNameLength = connectSession->GetServiceName().length(); + if (flatSession->serviceNameLength == 0 || flatSession->serviceNameLength > SERVICENAME_LENGTH) { + DBINDER_LOGE("wrong service name"); + return 0; + } + memcpyResult = memcpy_s(flatSession->serviceName, SERVICENAME_LENGTH, connectSession->GetServiceName().data(), + flatSession->serviceNameLength); + if (memcpyResult != 0) { + DBINDER_LOGE("memcpy_s failed , name Size = %hu", flatSession->serviceNameLength); + return 0; + } + flatSession->serviceName[flatSession->serviceNameLength] = '\0'; + + DBINDER_LOGI("serviceName = %s, stubIndex = %" PRIu64 "", flatSession->serviceName, flatSession->stubIndex); + + return sizeof(struct FlatDBinderSession); +} + +std::shared_ptr DBinderDatabusInvoker::UnFlattenSession(char *sessionOffset, uint64_t &stubIndex) +{ + FlatDBinderSession *flatSession = reinterpret_cast(sessionOffset); + /* force end true string length */ + flatSession->deviceId[DEVICEID_LENGTH] = '\0'; + flatSession->serviceName[SERVICENAME_LENGTH] = '\0'; + + DBINDER_LOGI("serviceName = %s, stubIndex = %" PRIu64 "", flatSession->serviceName, flatSession->stubIndex); + stubIndex = flatSession->stubIndex; + if (stubIndex == 0) { + DBINDER_LOGE("stubIndex err"); + return nullptr; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current process skeleton is nullptr"); + return nullptr; + } + + std::shared_ptr sessionObject = + current->QuerySessionByInfo(flatSession->serviceName, flatSession->deviceId); + if (sessionObject != nullptr) { + return sessionObject; + } + return std::make_shared(nullptr, flatSession->serviceName, flatSession->deviceId); +} + +bool DBinderDatabusInvoker::FlattenObject(Parcel &parcel, const IRemoteObject *object) const +{ + return true; +} + +IRemoteObject *DBinderDatabusInvoker::UnflattenObject(Parcel &parcel) +{ + return nullptr; +} + +int DBinderDatabusInvoker::ReadFileDescriptor(Parcel &parcel) +{ + return -1; +} + +bool DBinderDatabusInvoker::WriteFileDescriptor(Parcel &parcel, int fd, bool takeOwnership) +{ + return true; +} + +bool DBinderDatabusInvoker::UpdateClientSession(uint32_t handle, std::shared_ptr sessionObject) +{ + DBINDER_LOGI("update client session enter"); + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current process skeleton is nullptr"); + return false; + } + + std::shared_ptr manager = ISessionService::GetInstance(); + if (manager == nullptr) { + DBINDER_LOGE("fail to get softbus manager"); + return false; + } + + std::string sessionName = current->GetDatabusName(); + if (sessionName.empty()) { + DBINDER_LOGE("fail to get session name"); + return false; + } + + std::shared_ptr session = manager->OpenSession(sessionName, sessionObject->GetServiceName(), + sessionObject->GetDeviceId(), std::string(""), Session::TYPE_BYTES); + if (session == nullptr) { + DBINDER_LOGE("get databus session fail"); + return false; + } + + sessionObject->SetBusSession(session); + + if (!current->ProxyAttachDBinderSession(handle, sessionObject)) { + DBINDER_LOGE("fail to attach session"); + return false; + } + + return true; +} + +bool DBinderDatabusInvoker::OnDatabusSessionClosed(std::shared_ptr session) +{ + if (session == nullptr) { + DBINDER_LOGE("databus session to be closed is nullptr"); + return false; + } + /* means close socket */ + DBINDER_LOGI("close databus session, own session name = %{public}s, peer session name = %{public}s", + session->GetMySessionName().c_str(), session->GetPeerSessionName().c_str()); + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current ipc process skeleton is nullptr"); + return false; + } + + if (current->StubDetachDBinderSession(IPCProcessSkeleton::ConvertChannelID2Int(session->GetChannelId()))) { + current->DetachStubRefInfo(session->GetPeerPid(), session->GetPeerDeviceId()); + // No need to clear proxy objects + return true; + } + + std::vector proxy; + if (!current->QueryProxyBySessionHandle(IPCProcessSkeleton::ConvertChannelID2Int(session->GetChannelId()), proxy)) { + return false; + } + + if (proxy.empty()) { + DBINDER_LOGE("proxy handle is empty"); + return false; + } + + for (auto it = proxy.begin(); it != proxy.end(); ++it) { + std::u16string descriptor = current->MakeHandleDescriptor(*it); + IRemoteObject *remoteObject = current->QueryObject(descriptor); + if (remoteObject != nullptr) { + IPCObjectProxy *remoteProxy = reinterpret_cast(remoteObject); + if (remoteProxy->IsSubscribeDeathNotice()) { + remoteProxy->SendObituary(); + } + (void)current->ProxyDetachDBinderSession(*it); + (void)current->DetachHandleToIndex(*it); + } + } + + DBINDER_LOGI("closet socket sussess"); + return true; +} + +uint32_t DBinderDatabusInvoker::QueryHandleBySession(std::shared_ptr session, uint64_t stubIndex) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current ipc process skeleton is nullptr"); + return 0; + } + + return current->QueryHandleByDatabusSession(session->GetServiceName(), session->GetDeviceId(), stubIndex); +} + +uint64_t DBinderDatabusInvoker::GetSeqNum() const +{ + return seqNumber_; +} + +void DBinderDatabusInvoker::SetSeqNum(uint64_t seq) +{ + seqNumber_ = seq; +} + +uint32_t DBinderDatabusInvoker::GetClientFd() const +{ + return clientFd_; +} + +void DBinderDatabusInvoker::SetClientFd(uint32_t fd) +{ + clientFd_ = fd; +} + +pid_t DBinderDatabusInvoker::GetCallerPid() const +{ + return callerPid_; +} + +void DBinderDatabusInvoker::SetStatus(uint32_t status) +{ + status_ = status; +} + +uint32_t DBinderDatabusInvoker::GetStatus() const +{ + return status_; +} + +void DBinderDatabusInvoker::SetCallerPid(pid_t pid) +{ + callerPid_ = pid; +} + +uid_t DBinderDatabusInvoker::GetCallerUid() const +{ + return callerUid_; +} + +void DBinderDatabusInvoker::SetCallerUid(pid_t uid) +{ + callerUid_ = uid; +} + +void DBinderDatabusInvoker::SetCallerDeviceID(const std::string &deviceId) +{ + callerDeviceID_ = deviceId; +} + +bool DBinderDatabusInvoker::IsLocalCalling() +{ + return false; +} + +int DBinderDatabusInvoker::CheckAndSetCallerInfo(uint32_t listenFd, uint64_t stubIndex) +{ + std::shared_ptr sessionObject = QueryClientSessionObject(listenFd); + if (sessionObject == nullptr) { + DBINDER_LOGE("session is not exist for listenFd = %u", listenFd); + return RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + std::shared_ptr session = sessionObject->GetBusSession(); + if (session == nullptr) { + DBINDER_LOGE("get databus session fail"); + return RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + int pid = session->GetPeerPid(); + int uid = session->GetPeerUid(); + std::string deviceId = session->GetPeerDeviceId(); + if (uid < 0 || deviceId.length() > DEVICEID_LENGTH) { + DBINDER_LOGE("user id and device id error"); + return RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current process skeleton is nullptr"); + return IPC_SKELETON_ERR; + } + if (current->QueryAppInfoToStubIndex(pid, uid, deviceId, stubIndex) == false) { + DBINDER_LOGE("stub index is NOT belong to caller,serviceName = %{public}s, listenFd = %{public}u", + deviceId.c_str(), listenFd); + return RPC_DATABUS_INVOKER_INVALID_STUB_INDEX; + } + callerPid_ = pid; + callerUid_ = uid; + callerDeviceID_ = deviceId; + return ERR_NONE; +} + +std::string DBinderDatabusInvoker::GetLocalDeviceID() +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("current process skeleton is nullptr"); + return ""; + } + + return current->GetLocalDeviceID(); +} + +std::string DBinderDatabusInvoker::GetCallerDeviceID() const +{ + return callerDeviceID_; +} + +uint64_t DBinderDatabusInvoker::MakeStubIndexByRemoteObject(IRemoteObject *stubObject) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("IPCProcessSkeleton is nullptr"); + return 0; + } + + if (!current->IsContainsObject(stubObject)) { + DBINDER_LOGE("fail to find stub"); + return 0; + } + + uint64_t stubIndex = current->AddStubByIndex(stubObject); + if (!stubIndex) { + DBINDER_LOGE("fail to add stub"); + return 0; + } + return stubIndex; +} + +std::shared_ptr DBinderDatabusInvoker::MakeDefaultServerSessionObject() +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("IPCProcessSkeleton is nullptr"); + return nullptr; + } + std::string serviceName = current->GetDatabusName(); + if (serviceName.empty()) { + DBINDER_LOGE("fail to get databus name"); + return nullptr; + } + std::shared_ptr connectSession = + std::make_shared(nullptr, serviceName, current->GetLocalDeviceID()); + if (connectSession == nullptr) { + DBINDER_LOGE("new server session fail!"); + return nullptr; + } + return connectSession; +} + +bool DBinderDatabusInvoker::ConnectRemoteObject2Session(IRemoteObject *stubObject, uint64_t stubIndex, + const std::shared_ptr sessionObject) +{ + if (sessionObject == nullptr) { + DBINDER_LOGE("session object is nullptr"); + return false; + } + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + DBINDER_LOGE("IPCProcessSkeleton is nullptr"); + return false; + } + std::shared_ptr session = sessionObject->GetBusSession(); + if (session == nullptr) { + DBINDER_LOGE("get databus session fail"); + return false; + } + + int peerPid = session->GetPeerPid(); + int peerUid = session->GetPeerUid(); + std::string deviceId = session->GetPeerDeviceId(); + if (!current->AttachAppInfoToStubIndex(peerPid, peerUid, deviceId, stubIndex)) { + DBINDER_LOGI("fail to attach appinfo to stub index, when proxy call we check appinfo"); + // attempt attach again, if failed, do nothing + } + if (!current->AttachCommAuthInfo(stubObject, peerPid, peerUid, deviceId)) { + DBINDER_LOGI("fail to attach comm auth info, maybe attached already"); + // attempt attach again, if failed, do nothing + } + + if (current->AttachStubSendRefInfo(stubObject, peerPid, deviceId)) { + if (!current->IncStubRefTimes(stubObject)) { + DBINDER_LOGE("Inc Stub RefTimes fail"); + current->DetachCommAuthInfo(stubObject, peerPid, peerUid, deviceId); + current->DetachAppInfoToStubIndex(peerPid, peerUid, deviceId, stubIndex); + return false; + } + stubObject->IncStrongRef(this); + } + return true; +} + +std::shared_ptr DBinderDatabusInvoker::CreateServerSessionObject(binder_uintptr_t binder, + uint64_t &stubIndex, std::shared_ptr sessionObject) +{ + IRemoteObject *stubObject = reinterpret_cast(binder); + if (stubObject == nullptr) { + DBINDER_LOGE("binder is nullptr"); + return nullptr; + } + + stubIndex = MakeStubIndexByRemoteObject(stubObject); + if (stubIndex == 0) { + DBINDER_LOGE("fail to add stub"); + return nullptr; + } + if (ConnectRemoteObject2Session(stubObject, stubIndex, sessionObject) != true) { + DBINDER_LOGE("fail to connect stub to session"); + return nullptr; + } + return MakeDefaultServerSessionObject(); +} + +int DBinderDatabusInvoker::FlushCommands(IRemoteObject *object) +{ + if (object == nullptr || !object->IsProxyObject()) { + DBINDER_LOGE("proxy is invalid"); + return RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + IPCObjectProxy *proxy = reinterpret_cast(object); + + std::shared_ptr session = QueryServerSessionObject(proxy->GetHandle()); + if (session == nullptr) { + DBINDER_LOGE("session is nullptr"); + return RPC_DATABUS_INVOKER_INVALID_DATA_ERR; + } + + (void)OnSendMessage(session); + return ERR_NONE; +} + +std::string DBinderDatabusInvoker::ResetCallingIdentity() +{ + std::string token = std::to_string(((static_cast(callerUid_) << PID_LEN) | callerPid_)); + std::string identity = callerDeviceID_ + token; + callerUid_ = getuid(); + callerPid_ = getpid(); + callerDeviceID_ = GetLocalDeviceID(); + return identity; +} + +bool DBinderDatabusInvoker::SetCallingIdentity(std::string &identity) +{ + if (identity.empty() || identity.length() <= DEVICEID_LENGTH) { + return false; + } + + std::string deviceId = identity.substr(0, DEVICEID_LENGTH); + int64_t token = std::atoll(identity.substr(DEVICEID_LENGTH, identity.length() - DEVICEID_LENGTH).c_str()); + + callerUid_ = static_cast(token >> PID_LEN); + callerPid_ = static_cast(token); + callerDeviceID_ = deviceId; + + return true; +} + +int DBinderDatabusInvoker::TranslateProxy(uint32_t handle, uint32_t flag) +{ + return -IPC_INVOKER_TRANSLATE_ERR; +} + +int DBinderDatabusInvoker::TranslateStub(binder_uintptr_t cookie, binder_uintptr_t ptr, uint32_t flag, int cmd) +{ + return -IPC_INVOKER_TRANSLATE_ERR; +} + +uint32_t DBinderDatabusInvoker::HasRawDataPackage(const char *data, ssize_t len) +{ + const dbinder_transaction_data *tr = reinterpret_cast(data); + if ((tr->magic == DBINDER_MAGICWORD) && (tr->cmd == BC_SEND_RAWDATA) && + (tr->sizeOfSelf == static_cast(len))) { + if (tr->sizeOfSelf > MAX_RAWDATA_SIZE) { + return MAX_RAWDATA_SIZE; + } + return tr->sizeOfSelf; + } + return 0; +} + +uint32_t DBinderDatabusInvoker::HasCompletePackage(const char *data, uint32_t readCursor, ssize_t len) +{ + const dbinder_transaction_data *tr = reinterpret_cast(data + readCursor); + if ((tr->magic == DBINDER_MAGICWORD) && + (tr->sizeOfSelf <= SOCKET_MAX_BUFF_SIZE + sizeof(dbinder_transaction_data)) && + (readCursor + tr->sizeOfSelf <= static_cast(len)) && CheckTransactionData(tr)) { + return tr->sizeOfSelf; + } + return 0; +} +} // namespace OHOS diff --git a/ipc/native/src/mock/source/hitrace_invoker.cpp b/ipc/native/src/mock/source/hitrace_invoker.cpp new file mode 100755 index 00000000..313e07b0 --- /dev/null +++ b/ipc/native/src/mock/source/hitrace_invoker.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "hitrace_invoker.h" + +#include +#include "hilog/log.h" +#include "hitrace/trace.h" +#include "sys_binder.h" +#include "ipc_debug.h" +#include "log_tags.h" + +namespace OHOS { +// the value should be equal to the set of parcel +using namespace OHOS::HiviewDFX; +static const HiLogLabel TRACE_LABEL = { LOG_CORE, LOG_ID_IPC, "BinderHiTrace" }; + +bool HitraceInvoker::IsClientTraced(int32_t handle, uint32_t flags, const HiTraceId &traceId) +{ + return (traceId.IsValid() && (handle != 0) && + ((flags & TF_ONE_WAY) ? traceId.IsFlagEnabled(HITRACE_FLAG_INCLUDE_ASYNC) : true)); +} + +HiTraceId HitraceInvoker::TraceClientSend(int32_t handle, uint32_t code, Parcel &data, uint32_t &flags, + const HiTraceId &traceId) +{ + HiTraceId childId = traceId; + bool isClientTraced = IsClientTraced(handle, flags, traceId); + if (isClientTraced) { + childId = HiTrace::CreateSpan(); + // add childid to parcel data + uint8_t idBytes[HITRACE_ID_LEN]; + int idLen = childId.ToBytes(idBytes, HITRACE_ID_LEN); + if (idLen != HITRACE_ID_LEN) { + ZLOGE(TRACE_LABEL, "%{public}s:idLen not correct", __func__); + return childId; + } + + size_t oldWritePosition = data.GetWritePosition(); + if (!data.WriteBuffer(idBytes, idLen)) { + ZLOGE(TRACE_LABEL, "%{public}s:Write idBytes fail", __func__); + // restore Parcel data + data.RewindWrite(oldWritePosition); + return childId; + } + + // padded size of traceid + if (!data.WriteUint8(data.GetWritePosition() - oldWritePosition)) { + ZLOGE(TRACE_LABEL, "%{public}s:Write idLen fail", __func__); + // restore Parcel data + data.RewindWrite(oldWritePosition); + return childId; + } + // tracepoint: CS(Client Send) + HiTrace::Tracepoint(HITRACE_TP_CS, childId, "%s handle=%d,code=%u", (flags & TF_ONE_WAY) ? "ASYNC" : "SYNC", + handle, code); + flags |= TF_HITRACE; + } + return childId; +} + +void HitraceInvoker::TraceClientReceieve(int32_t handle, uint32_t code, uint32_t flags, const HiTraceId &traceId, + const HiTraceId &childId) +{ + if (!(flags & TF_HITRACE)) { + return; + } + bool isClientTraced = IsClientTraced(handle, flags, traceId); + if (isClientTraced) { + if (!(flags & TF_ONE_WAY)) { + // restore thread trace id + HiTrace::SetId(traceId); + // tracepoint: CR(Client Receive) + HiTrace::Tracepoint(HITRACE_TP_CR, childId, "%s handle=%d,code=%u", "SYNC", handle, code); + } + } +} + +void HitraceInvoker::RecoveryDataAndFlag(Parcel &data, uint32_t &flags, size_t oldReadPosition, uint8_t idLen) +{ + // restore data + data.RewindRead(oldReadPosition); + // padded size(4 bytes) of uint8_t + data.SetDataSize(data.GetDataSize() - PADDED_SIZE_OF_PARCEL - idLen); + flags &= ~(uint32_t)TF_HITRACE; +} + +bool HitraceInvoker::TraceServerReceieve(int32_t handle, uint32_t code, Parcel &data, uint32_t &flags) +{ + bool isServerTraced = (flags & TF_HITRACE) != 0; + if (isServerTraced) { + size_t oldReadPosition = data.GetReadPosition(); + // padded size(4 bytes) of uint8_t + data.RewindRead(data.GetDataSize() - PADDED_SIZE_OF_PARCEL); + // the padded size of traceid + uint8_t idLen = data.ReadUint8(); + if (idLen >= sizeof(HiTraceIdStruct)) { + // padded size(4 bytes) of uint8_t + data.RewindRead(data.GetDataSize() - PADDED_SIZE_OF_PARCEL - idLen); + const uint8_t *idBytes = data.ReadUnpadBuffer(sizeof(HiTraceIdStruct)); + if (idBytes == nullptr) { + ZLOGE(TRACE_LABEL, "%{public}s:idBytes is null", __func__); + isServerTraced = 0; + RecoveryDataAndFlag(data, flags, oldReadPosition, idLen); + return isServerTraced; + } + HiTraceId traceId(idBytes, sizeof(HiTraceIdStruct)); + HiTrace::SetId(traceId); + // tracepoint: SR(Server Receive) + HiTrace::Tracepoint(HITRACE_TP_SR, traceId, "%s handle=%d,code=%u", (flags & TF_ONE_WAY) ? "ASYNC" : "SYNC", + handle, code); + } + + RecoveryDataAndFlag(data, flags, oldReadPosition, idLen); + } + return isServerTraced; +} + +void HitraceInvoker::TraceServerSend(int32_t handle, uint32_t code, bool isServerTraced, uint32_t flags) +{ + if (isServerTraced) { + // tracepoint: SS(Server Send) + HiTrace::Tracepoint(HITRACE_TP_SS, HiTrace::GetId(), "%s handle=%d,code=%u", + (flags & TF_ONE_WAY) ? "ASYNC" : "SYNC", handle, code); + } + HiTrace::ClearId(); +} +} // namespace OHOS diff --git a/ipc/native/src/mock/source/invoker_factory.cpp b/ipc/native/src/mock/source/invoker_factory.cpp new file mode 100755 index 00000000..7b3e0a99 --- /dev/null +++ b/ipc/native/src/mock/source/invoker_factory.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "invoker_factory.h" +#include + +namespace OHOS { +#ifdef CONFIG_IPC_SINGLE +namespace IPC_SINGLE { +#endif +bool InvokerFactory::isAvailable_ = true; + +InvokerFactory::InvokerFactory() {} + +InvokerFactory::~InvokerFactory() +{ + isAvailable_ = false; + creators_.clear(); +} + +InvokerFactory &InvokerFactory::Get() +{ + static InvokerFactory instance; + return instance; +} + +bool InvokerFactory::Register(int protocol, InvokerCreator creator) +{ + if (isAvailable_ != true) { + return false; + } + std::lock_guard lockGuard(factoryMutex_); + + /* check isAvailable_ == true again when a thread take mutex */ + if (isAvailable_ != true) { + return false; + } + return creators_.insert(std::make_pair(protocol, creator)).second; +} + +void InvokerFactory::Unregister(int protocol) +{ + if (isAvailable_ != true) { + return; + } + std::lock_guard lockGuard(factoryMutex_); + + /* check isAvailable_ == true again when a thread take mutex */ + if (isAvailable_ != true) { + return; + } + (void)creators_.erase(protocol); +} + +IRemoteInvoker *InvokerFactory::newInstance(int protocol) +{ + if (isAvailable_ != true) { + return nullptr; + } + std::lock_guard lockGuard(factoryMutex_); + + /* check isAvailable_ == true again when a thread take mutex */ + if (isAvailable_ != true) { + return nullptr; + } + auto it = creators_.find(protocol); + if (it != creators_.end() && (it->second != nullptr)) { + return it->second(); + } + return nullptr; +} +#ifdef CONFIG_IPC_SINGLE +} // namespace IPC_SINGLE +#endif +} // namespace OHOS \ No newline at end of file diff --git a/ipc/native/src/mock/source/invoker_rawdata.cpp b/ipc/native/src/mock/source/invoker_rawdata.cpp new file mode 100755 index 00000000..fe92c8dd --- /dev/null +++ b/ipc/native/src/mock/source/invoker_rawdata.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "invoker_rawdata.h" + +namespace OHOS { +InvokerRawData::InvokerRawData(size_t size) +{ + /* size is guaranteed by caller, in MessageParcel max size is 1G */ + data_.reset(reinterpret_cast(::operator new(size))); + size_ = size; +} + +InvokerRawData::~InvokerRawData() +{ + data_ = nullptr; +} + +std::shared_ptr InvokerRawData::GetData() const +{ + return data_; +} + +size_t InvokerRawData::GetSize() const +{ + return size_; +} +} // namespace OHOS \ No newline at end of file diff --git a/ipc/native/test/BUILD.gn b/ipc/native/test/BUILD.gn new file mode 100755 index 00000000..7b510763 --- /dev/null +++ b/ipc/native/test/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +#################################group######################################### + +group("unittest") { + testonly = true + deps = [ "unittest/common:unittest" ] +} +############################################################################### diff --git a/ipc/native/test/unittest/common/BUILD.gn b/ipc/native/test/unittest/common/BUILD.gn new file mode 100755 index 00000000..cfd78975 --- /dev/null +++ b/ipc/native/test/unittest/common/BUILD.gn @@ -0,0 +1,82 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +IPC_TEST_ROOT = "//foundation/communication/ipc/ipc/test" +MODULE_OUTPUT_PATH = "ipc" + +ohos_unittest("IPCNativeUnitTest") { + module_out_path = MODULE_OUTPUT_PATH + + include_dirs = [ "//utils/system/safwk/native/include" ] + + sources = [ "ipc_core_unittest.cpp" ] + + configs = [ + "$SUBSYSTEM_DIR:ipc_util_config", + "$IPC_TEST_ROOT:ipc_test_config", + ] + + deps = [ + "$IPC_TEST_ROOT/auxiliary/native:TestAssistance", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + resource_config_file = + "//foundation/communication/ipc/test/resource/ipc/ohos_test.xml" +} + +ohos_unittest("IPCFileDescOpsTest") { + module_out_path = MODULE_OUTPUT_PATH + sources = [ "ipc_file_desc_unittest.cpp" ] + + configs = [ + "$SUBSYSTEM_DIR:ipc_util_config", + "$IPC_TEST_ROOT:ipc_test_config", + ] + + deps = [ + "$IPC_TEST_ROOT/auxiliary/native:TestAssistance", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + ] + + resource_config_file = + "//foundation/communication/ipc/test/resource/ipc/ohos_test.xml" +} + +############################################################################### +group("unittest") { + testonly = true + deps = [ + ":IPCFileDescOpsTest", + ":IPCNativeUnitTest", + ] +} + +############################################################################### + diff --git a/ipc/native/test/unittest/common/ipc_core_unittest.cpp b/ipc/native/test/unittest/common/ipc_core_unittest.cpp new file mode 100755 index 00000000..88e9e4a7 --- /dev/null +++ b/ipc/native/test/unittest/common/ipc_core_unittest.cpp @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 +#include "ipc_debug.h" +#include "ipc_skeleton.h" +#include "ipc_object_proxy.h" +#include "test_service_skeleton.h" +#include "test_service.h" +#include "test_service_command.h" +#include "test_service_client.h" +#include "ipc_test_helper.h" +#include "iservice_registry.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "log_tags.h" +#ifndef CONFIG_STANDARD_SYSTEM +#include "jni_help.h" +#endif + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +static constexpr int MAX_TEST_COUNT = 1000; +static constexpr bool SUPPORT_ZBINDER = false; + +class IPCNativeUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCUnitTest" }; + +private: + static inline IPCTestHelper *g_globalHelper = { nullptr }; +}; + +void IPCNativeUnitTest::SetUpTestCase() +{ + if (g_globalHelper == nullptr) { + g_globalHelper = new IPCTestHelper(); + bool res = g_globalHelper->PrepareTestSuite(); + ASSERT_TRUE(res); + } +} + +void IPCNativeUnitTest::TearDownTestCase() +{ + if (g_globalHelper != nullptr) { + bool res = g_globalHelper->TearDownTestSuite(); + ASSERT_TRUE(res); + delete g_globalHelper; + g_globalHelper = nullptr; + } +} + +/** + * @tc.name: DeathRecipient001 + * @tc.desc: The Stub should not support AddDeathRecipient + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, DeathRecipient001, TestSize.Level1) +{ + sptr testStub = new IPCObjectStub(u"testStub"); + bool res = testStub->AddDeathRecipient(nullptr); + EXPECT_FALSE(res); +} + +/** + * @tc.name: DeathRecipient002 + * @tc.desc: The Stub should not support RemoveDeathRecipient + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, DeathRecipient002, TestSize.Level1) +{ + sptr testStub = new IPCObjectStub(u"testStub"); + bool res = testStub->RemoveDeathRecipient(nullptr); + EXPECT_FALSE(res); +} + +/** + * @tc.name: DumpTest001 + * @tc.desc: The Stub should not support Dump + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, DumpTest001, TestSize.Level1) +{ + sptr testStub = new IPCObjectStub(u"testStub"); + std::vector args; + args.push_back(u"test"); + int res = testStub->Dump(0, args); + EXPECT_EQ(res, 0); +} + +/** + * @tc.name: ProxyJudgment001 + * @tc.desc: act as stub role, should return false + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, ProxyJudgment001, TestSize.Level1) +{ + sptr testStub = new IPCObjectStub(u"testStub"); + bool res = testStub->IsProxyObject(); + EXPECT_FALSE(res); +} + +#ifndef CONFIG_STANDARD_SYSTEM +/** + * @tc.name: ProxyJudgment002 + * @tc.desc: act as proxy role, should return true + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, ProxyJudgment002, TestSize.Level1) +{ + sptr remote = SystemAbilityManagerClient::GetInstance().GetRegistryRemoteObject(); + ASSERT_TRUE(remote != nullptr); + EXPECT_TRUE(remote->IsProxyObject()); +} + +/** + * @tc.name: RemoteId001. + * @tc.desc: + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, RemoteId001, TestSize.Level1) +{ + sptr remote = SystemAbilityManagerClient::GetInstance().GetRegistryRemoteObject(); + ASSERT_TRUE(remote != nullptr); + + IPCObjectProxy *proxy = reinterpret_cast(remote.GetRefPtr()); + ASSERT_TRUE(proxy != nullptr); + + int remoteId = proxy->GetHandle(); + EXPECT_GE(remoteId, 0); +} +#endif + +/** + * @tc.name: ProxyJudgment003 + * @tc.desc: transform interface instance to object. + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, ProxyJudgment003, TestSize.Level1) +{ + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr asObject = saMgr->AsObject(); + ASSERT_TRUE(asObject != nullptr); +} + +/** + * @tc.name: ProxyJudgment004 + * @tc.desc: Press test to validate Get Register instance.. + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, ProxyJudgment004, TestSize.Level1) +{ + std::vector> registryObjs; + registryObjs.resize(100); + + for (int i = 0; i < 100; i++) { + registryObjs[i] = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(registryObjs[i] != nullptr); + } +} + +/** + * @tc.name: MaxWorkThread001 + * @tc.desc: when multi-transaction called, + * the driver will spawn new thread.but it should not exceed the max num. + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, MaxWorkThread001, TestSize.Level1) +{ + IPCTestHelper helper; + IPCSkeleton::SetMaxWorkThreadNum(8); + std::vector childPids; + helper.GetChildPids(childPids); + ASSERT_GE(childPids.size(), (const unsigned long)1); +} + +/** + * @tc.name: SyncTransaction001 + * @tc.desc: Test IPC data transaction. + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction001, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr service = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + sptr testService = iface_cast(service); + ASSERT_TRUE(testService != nullptr); + + if (service->IsProxyObject()) { + int reply = 0; + ZLOGI(LABEL, "Got Proxy node"); + TestServiceProxy *proxy = static_cast(testService.GetRefPtr()); + int ret = proxy->TestSyncTransaction(2019, reply); + EXPECT_EQ(ret, 0); + EXPECT_EQ(reply, 9102); + } else { + ZLOGI(LABEL, "Got Stub node"); + } +} + +/** + * @tc.name: AsyncTransaction001 + * @tc.desc: Test IPC data transaction. + * @tc.type: FUNC + * @tc.require: AR000DPV5F + */ +HWTEST_F(IPCNativeUnitTest, AsyncTransaction001, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr service = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + sptr testService = iface_cast(service); + ASSERT_TRUE(testService != nullptr); + + ZLOGI(LABEL, "Get test.service OK\n"); + if (service->IsProxyObject()) { + ZLOGI(LABEL, "Got Proxy node\n"); + TestServiceProxy *proxy = static_cast(testService.GetRefPtr()); + int reply = 0; + int ret = proxy->TestAsyncTransaction(2019, reply); + EXPECT_EQ(ret, ERR_NONE); + } else { + ZLOGI(LABEL, "Got Stub node\n"); + } +} + +/** + * @tc.name: SyncTransaction002 + * @tc.desc: Test IPC data transaction. + * @tc.type: FUNC + * @tc.require: AR000DPV5E + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction002, TestSize.Level1) +{ + int refCount = 0; + IPCTestHelper helper; + sptr stub = new TestService(); + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + refCount = stub->GetObjectRefCount(); + EXPECT_EQ(refCount, 1); + + int result = saMgr->AddSystemAbility(IPC_TEST_SERVICE, new TestService()); + EXPECT_EQ(result, ERR_NONE); + + refCount = stub->GetObjectRefCount(); + + if (SUPPORT_ZBINDER) { + EXPECT_GE(refCount, 2); + } else { + EXPECT_GE(refCount, 1); + } + + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_CLIENT); + ASSERT_TRUE(res); + + refCount = stub->GetObjectRefCount(); + if (SUPPORT_ZBINDER) { + EXPECT_GE(refCount, 3); + } else { + EXPECT_GE(refCount, 1); + } + + helper.StopTestApp(IPCTestHelper::IPC_TEST_CLIENT); + refCount = stub->GetObjectRefCount(); + if (SUPPORT_ZBINDER) { + EXPECT_GE(refCount, 2); + } else { + EXPECT_GE(refCount, 1); + } +} + +/** + * @tc.name: SyncTransaction003 + * @tc.desc: Test IPC data transaction. + * @tc.type: FUNC + * @tc.require: AR000DPV5F + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction003, TestSize.Level1) +{ + int refCount = 0; + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr proxy = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(proxy != nullptr); + + refCount = proxy->GetObjectRefCount(); + if (SUPPORT_ZBINDER) { + EXPECT_GE(refCount, 2); + } else { + EXPECT_GE(refCount, 1); + } + + res = helper.StartTestApp(IPCTestHelper::IPC_TEST_CLIENT); + ASSERT_TRUE(res); + + refCount = proxy->GetObjectRefCount(); + if (SUPPORT_ZBINDER) { + EXPECT_GE(refCount, 3); + } else { + EXPECT_GE(refCount, 1); + } + + helper.StopTestApp(IPCTestHelper::IPC_TEST_CLIENT); + refCount = proxy->GetObjectRefCount(); + + if (SUPPORT_ZBINDER) { + EXPECT_GE(refCount, 2); + } else { + EXPECT_GE(refCount, 1); + } +} + +/** + * @tc.name: SyncTransaction004 + * @tc.desc: Test IPC data transaction. + * @tc.type: FUNC + * @tc.require: AR000DPV5E + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction004, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + res = helper.StartTestApp(IPCTestHelper::IPC_TEST_CLIENT, static_cast(TestCommand::TEST_CMD_LOOP_TRANSACTION)); + ASSERT_TRUE(res); + + std::unique_ptr testClient = std::make_unique(); + int result = testClient->ConnectService(); + ASSERT_EQ(result, 0); + + int count = testClient->StartLoopTest(MAX_TEST_COUNT); + EXPECT_EQ(count, MAX_TEST_COUNT); +} + +/** + * @tc.name: SyncTransaction005 + * @tc.desc: Test get context object. + * @tc.type: FUNC + * @tc.require: SR000DFJQF AR000DFJQG + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction005, TestSize.Level1) +{ + sptr remote = IPCSkeleton::GetContextObject(); + ASSERT_TRUE(remote != nullptr); +} + +/** + * @tc.name: SyncTransaction006 + * @tc.desc: Test set context object. + * @tc.type: FUNC + * @tc.require: SR000DFJQF AR000DFJQG + + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction006, TestSize.Level1) +{ + sptr remoteObj = IPCSkeleton::GetContextObject(); + ASSERT_TRUE(remoteObj != nullptr); + bool ret = IPCSkeleton::SetContextObject(remoteObj); + ASSERT_FALSE(ret); +} + +#ifndef CONFIG_STANDARD_SYSTEM +/** + * @tc.name: SyncTransaction007 + * @tc.desc: Test get context object through jni. + * @tc.type: FUNC + * @tc.require: SR000DFJQF AR000DFJQG + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction007, TestSize.Level1) +{ + JNIEnv *env = nullptr; + sptr remoteObj = IPCSkeleton::GetContextObject(); + ASSERT_TRUE(remoteObj != nullptr); + jobject testObj = JNIHelperGetJavaRemoteObject(env, remoteObj); + ASSERT_TRUE(testObj == nullptr); +} +#endif + +/** + * @tc.name: SyncTransaction008 + * @tc.desc: Test write and read interface token in MessageParcel. + * @tc.type: FUNC + * @tc.require: SR000DFJQF AR000DFJQG + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction008, TestSize.Level1) +{ + MessageParcel parcel; + std::u16string descriptor = u"TokenDescriptor"; + parcel.WriteInterfaceToken(descriptor); + std::u16string readDescriptor = parcel.ReadInterfaceToken(); + ASSERT_EQ(readDescriptor, descriptor); +} + + +/** + * @tc.name: SyncTransaction009 + * @tc.desc: Test IPC stub data Normal release. + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction009, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr service = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + sptr testService = iface_cast(service); + ASSERT_TRUE(testService != nullptr); + + ZLOGI(LABEL, "Get test.service OK\n"); + if (service->IsProxyObject()) { + ZLOGI(LABEL, "Got Proxy node\n"); + TestServiceProxy *proxy = static_cast(testService.GetRefPtr()); + int reply = 0; + int ret = proxy->TestAsyncTransaction(2019, reply); + EXPECT_EQ(ret, ERR_NONE); + } else { + ZLOGI(LABEL, "Got Stub node\n"); + } +} + +/** + * @tc.name: SyncTransaction010 + * @tc.desc: Test write and read exception. + * @tc.type: FUNC + * @tc.require: AR000E1QEG + */ +HWTEST_F(IPCNativeUnitTest, SyncTransaction010, TestSize.Level1) +{ + MessageParcel parcel; + parcel.WriteNoException(); + ASSERT_EQ(parcel.ReadException(), 0); +} + +/** + * @tc.name: MessageOptionTest001 + * @tc.desc: Test set waiting time. + * @tc.type: FUNC + * @tc.require: AR000ER7PF + */ +HWTEST_F(IPCNativeUnitTest, MessageOptionTest001, TestSize.Level1) +{ + MessageOption messageOption; + ASSERT_EQ(messageOption.GetWaitTime(), MessageOption::TF_WAIT_TIME); + messageOption.SetWaitTime(-1); + ASSERT_EQ(messageOption.GetWaitTime(), MessageOption::TF_WAIT_TIME); +} diff --git a/ipc/native/test/unittest/common/ipc_file_desc_unittest.cpp b/ipc/native/test/unittest/common/ipc_file_desc_unittest.cpp new file mode 100755 index 00000000..34e47816 --- /dev/null +++ b/ipc/native/test/unittest/common/ipc_file_desc_unittest.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 +#include +#include +#include +#include +#include "ipc_debug.h" +#include "ipc_file_descriptor.h" +#include "log_tags.h" + +namespace OHOS { +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +class IPCFileDescOpsTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + +public: + static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCFdTest" }; +}; + +void IPCFileDescOpsTest::SetUp() {} + +void IPCFileDescOpsTest::TearDown() {} + +void IPCFileDescOpsTest::SetUpTestCase() {} + +void IPCFileDescOpsTest::TearDownTestCase() {} + +HWTEST_F(IPCFileDescOpsTest, fd_parcelable_001, TestSize.Level1) +{ + int testFdNum; + testFdNum = open("/data/test/fd_unit_test.txt", O_RDWR | O_APPEND | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); + + if (testFdNum == -1) { + ZLOGI(LABEL, "%s(%d):open failed.", __func__, __LINE__); + } + ASSERT_TRUE(testFdNum >= 0); + + Parcel parcel(nullptr); + sptr wdesc = new IPCFileDescriptor(testFdNum); + bool result = false; + + result = parcel.WriteObject(wdesc); + EXPECT_EQ(true, result); + + sptr rdesc = parcel.ReadObject(); + ASSERT_TRUE(rdesc != nullptr); + EXPECT_EQ(testFdNum, rdesc->GetFd()); + close(testFdNum); +} + +HWTEST_F(IPCFileDescOpsTest, fd_parcelable_002, TestSize.Level1) +{ + int invalidFdNum = -2; + Parcel parcel(nullptr); + sptr wdesc = new IPCFileDescriptor(invalidFdNum); + bool result = false; + result = parcel.WriteObject(wdesc); + EXPECT_EQ(false, result); + + IPCFileDescriptor *rdesc = parcel.ReadObject(); + EXPECT_EQ(nullptr, rdesc); +} + +HWTEST_F(IPCFileDescOpsTest, fd_parcelable_003, TestSize.Level1) +{ + int fd = 9876; + IPCFileDescriptor fdesc; + + fdesc.SetFd(fd); + EXPECT_EQ(fd, fdesc.GetFd()); +} +} // namespace OHOS diff --git a/ipc/native/test/unittest/common/ipc_hitrace_unittest.cpp b/ipc/native/test/unittest/common/ipc_hitrace_unittest.cpp new file mode 100755 index 00000000..144124ef --- /dev/null +++ b/ipc/native/test/unittest/common/ipc_hitrace_unittest.cpp @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "ipc_debug.h" +#include "hitrace/trace.h" +#include "ipc_skeleton.h" +#include "ipc_object_proxy.h" +#include "test_service_skeleton.h" +#include "test_service.h" +#include "ipc_test_helper.h" +#include "binder_connector.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "log_tags.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC, "BinderTraceUnitTest" }; + +class BinderTraceTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + +private: + static IPCTestHelper *g_helper; +}; +IPCTestHelper *BinderTraceTest::g_helper = nullptr; +void BinderTraceTest::SetUpTestCase() +{ + if (g_helper == nullptr) { + g_helper = new IPCTestHelper(); + bool res = g_helper->PrepareTestSuite(); + ASSERT_TRUE(res); + } +} + +void BinderTraceTest::TearDownTestCase() +{ + if (g_helper != nullptr) { + bool res = g_helper->TearDownTestSuite(); + ASSERT_TRUE(res); + delete g_helper; + g_helper = nullptr; + } +} + +static std::string HitraceLongToString(unsigned long data) +{ + std::string result; + constexpr int BUFFER_SIZE = 16; + char str[BUFFER_SIZE] = {0}; + + if (sprintf_s(str, sizeof(str), "%lx", data) <= 0) { + return result; + } + + result = str; + return result; +} + +static std::string BinderTraceGetRemainLog(const std::string &tag) +{ + std::string logMsgs; + std::string remainLogMsgs; + constexpr int BUFFER_SIZE = 1024; + FILE *fp = popen("/system/bin/hilog -x -z 4096", "re"); + bool findTag = false; + + if (fp != nullptr) { + char buf[BUFFER_SIZE] = {0}; + size_t n; + n = fread(buf, 1, sizeof(buf), fp); + while (n > 0) { + logMsgs.append(buf, n); + n = fread(buf, 1, sizeof(buf), fp); + } + pclose(fp); + } else { + return remainLogMsgs; + } + + std::stringstream ss(logMsgs); + std::string str; + while (!ss.eof()) { + getline(ss, str); + + if (findTag == false && str.find(tag) != std::string::npos) { + findTag = true; + } + + if (findTag == true) { + remainLogMsgs.append(str); + } + } + + return remainLogMsgs; +} +static int BinderTraceCheckLog(const std::string &remainLogMsgs, const std::string &checkItem, + const std::string &chainId) +{ + std::stringstream rss(remainLogMsgs); + std::string str; + std::regex re(checkItem); + + while (!rss.eof()) { + getline(rss, str); + if (std::regex_search(str, re) == true && str.find(chainId) != std::string::npos) { + return 1; + } + } + + return 0; +} + +static std::string PrintTagLog(const std::string &tag) +{ + struct timeval tv = {}; + constexpr int SEC_TO_USEC = 1000000; + gettimeofday(&tv, nullptr); + long long timeStamp = tv.tv_sec * SEC_TO_USEC + tv.tv_usec; + std::string strTimeStamp; + std::stringstream ss; + ss << timeStamp; + ss >> strTimeStamp; + std::string logTag = strTimeStamp + tag; + HiLog::Info(LOG_LABEL, "%s\n", logTag.c_str()); + return logTag; +} + +HWTEST_F(BinderTraceTest, Sync001, TestSize.Level1) +{ + HiTraceId getId = HiTrace::GetId(); + EXPECT_EQ(0, getId.IsValid()); + HiTraceId traceId = HiTrace::Begin("ipc hitrace", 0); + std::string chainId = HitraceLongToString(traceId.GetChainId()); + EXPECT_NE(0UL, chainId.size()); + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + + ASSERT_TRUE(saMgr != nullptr); + + sptr service = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + sptr testService = iface_cast(service); + + ASSERT_TRUE(testService != nullptr); + HiLog::Info(LOG_LABEL, "Get test.service OK\n"); + std::string logTag = PrintTagLog(":BinderTraceTest_Sync001"); + + if (service->IsProxyObject()) { + HiLog::Info(LOG_LABEL, "Got Proxy node\n"); + TestServiceProxy *proxy = static_cast(testService.GetRefPtr()); + int reply = 0; + int ret = proxy->TestSyncTransaction(2019, reply); + EXPECT_EQ(ret, NO_ERROR); + EXPECT_EQ(reply, 9102); + } else { + HiLog::Info(LOG_LABEL, "Got Stub node\n"); + } + + getId = HiTrace::GetId(); + EXPECT_EQ(1, getId.IsValid()); + HiTrace::End(traceId); + getId = HiTrace::GetId(); + EXPECT_EQ(0, getId.IsValid()); + std::string remainLogMsgs = BinderTraceGetRemainLog(logTag); + EXPECT_EQ(0, BinderTraceCheckLog(remainLogMsgs, "HITRACE_TP_CS", chainId)); + EXPECT_EQ(0, BinderTraceCheckLog(remainLogMsgs, "HITRACE_TP_SR", chainId)); + EXPECT_EQ(0, BinderTraceCheckLog(remainLogMsgs, "HITRACE_TP_SS", chainId)); + EXPECT_EQ(0, BinderTraceCheckLog(remainLogMsgs, "HITRACE_TP_CR", chainId)); +} + +HWTEST_F(BinderTraceTest, Sync002, TestSize.Level1) +{ + const std::string HITRACE_TP_CS_LOG = + "\\[[a-f0-9]{1,16}, 0, 0\\] service = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + sptr testService = iface_cast(service); + + ASSERT_TRUE(testService != nullptr); + HiLog::Info(LOG_LABEL, "Get test.service OK\n"); + std::string logTag = PrintTagLog(":BinderTraceTest_Sync002"); + + if (service->IsProxyObject()) { + HiLog::Info(LOG_LABEL, "Got Proxy node\n"); + TestServiceProxy *proxy = static_cast(testService.GetRefPtr()); + int reply = 0; + int ret = proxy->TestSyncTransaction(2019, reply); + EXPECT_EQ(ret, NO_ERROR); + EXPECT_EQ(reply, 9102); + } else { + HiLog::Info(LOG_LABEL, "Got Stub node\n"); + } + + getId = HiTrace::GetId(); + EXPECT_EQ(1, getId.IsValid()); + HiTrace::End(traceId); + getId = HiTrace::GetId(); + EXPECT_EQ(0, getId.IsValid()); +} + +HWTEST_F(BinderTraceTest, Sync003, TestSize.Level1) +{ + const std::string HITRACE_TP_CS_LOG = "\\[[a-f0-9]{1,16}\\] service = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + sptr testService = iface_cast(service); + ASSERT_TRUE(testService != nullptr); + + HiLog::Info(LOG_LABEL, "Get test.service OK\n"); + std::string logTag = PrintTagLog(":BinderTraceTest_Sync003"); + if (service->IsProxyObject()) { + HiLog::Info(LOG_LABEL, "Got Proxy node\n"); + TestServiceProxy *proxy = static_cast(testService.GetRefPtr()); + int reply = 0; + int ret = proxy->TestSyncTransaction(2019, reply); + EXPECT_EQ(ret, NO_ERROR); + EXPECT_EQ(reply, 9102); + } else { + HiLog::Info(LOG_LABEL, "Got Stub node\n"); + } + + getId = HiTrace::GetId(); + EXPECT_EQ(1, getId.IsValid()); + HiTrace::End(traceId); + getId = HiTrace::GetId(); + EXPECT_EQ(0, getId.IsValid()); +} + +HWTEST_F(BinderTraceTest, Async001, TestSize.Level1) +{ + HiTraceId getId = HiTrace::GetId(); + EXPECT_EQ(0, getId.IsValid()); + HiTraceId traceId = HiTrace::Begin("ipc hitrace", HITRACE_FLAG_INCLUDE_ASYNC); + std::string chainId = HitraceLongToString(traceId.GetChainId()); + EXPECT_NE(0UL, chainId.size()); + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + + ASSERT_TRUE(saMgr != nullptr); + + sptr service = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + sptr testService = iface_cast(service); + + ASSERT_TRUE(testService != nullptr); + HiLog::Info(LOG_LABEL, "Get test.service OK\n"); + std::string logTag = PrintTagLog(":BinderTraceTest_Async001"); + + if (service->IsProxyObject()) { + HiLog::Info(LOG_LABEL, "Got Proxy node\n"); + TestServiceProxy *proxy = static_cast(testService.GetRefPtr()); + int ret = proxy->TestAsyncTransaction(2019); + EXPECT_EQ(ret, ERR_NONE); + } else { + HiLog::Info(LOG_LABEL, "Got Stub node\n"); + } + + getId = HiTrace::GetId(); + EXPECT_EQ(1, getId.IsValid()); + HiTrace::End(traceId); + getId = HiTrace::GetId(); + EXPECT_EQ(0, getId.IsValid()); + std::string remainLogMsgs = BinderTraceGetRemainLog(logTag); + EXPECT_EQ(0, BinderTraceCheckLog(remainLogMsgs, "HITRACE_TP_CS", chainId)); + EXPECT_EQ(0, BinderTraceCheckLog(remainLogMsgs, "HITRACE_TP_SR", chainId)); + EXPECT_EQ(0, BinderTraceCheckLog(remainLogMsgs, "HITRACE_TP_SS", chainId)); + EXPECT_EQ(0, BinderTraceCheckLog(remainLogMsgs, "HITRACE_TP_CR", chainId)); +} + +HWTEST_F(BinderTraceTest, Async002, TestSize.Level1) +{ + const std::string HITRACE_TP_CS_LOG = + "\\[[a-f0-9]{1,16}, 0, 0\\] service = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + sptr testService = iface_cast(service); + + ASSERT_TRUE(testService != nullptr); + HiLog::Info(LOG_LABEL, "Get test.service OK\n"); + std::string logTag = PrintTagLog(":BinderTraceTest_Async002"); + + if (service->IsProxyObject()) { + HiLog::Info(LOG_LABEL, "Got Proxy node\n"); + TestServiceProxy *proxy = static_cast(testService.GetRefPtr()); + int ret = proxy->TestAsyncTransaction(2019, 1); + EXPECT_EQ(ret, ERR_NONE); + } else { + HiLog::Info(LOG_LABEL, "Got Stub node\n"); + } + + getId = HiTrace::GetId(); + EXPECT_EQ(1, getId.IsValid()); + HiTrace::End(traceId); + getId = HiTrace::GetId(); + EXPECT_EQ(0, getId.IsValid()); +} + +HWTEST_F(BinderTraceTest, Async003, TestSize.Level1) +{ + const std::string HITRACE_TP_CS_LOG = "\\[[a-f0-9]{1,16}\\] service = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + sptr testService = iface_cast(service); + + ASSERT_TRUE(testService != nullptr); + HiLog::Info(LOG_LABEL, "Get test.service OK\n"); + std::string logTag = PrintTagLog(":BinderTraceTest_Async003"); + + if (service->IsProxyObject()) { + HiLog::Info(LOG_LABEL, "Got Proxy node\n"); + TestServiceProxy *proxy = static_cast(testService.GetRefPtr()); + int ret = proxy->TestAsyncTransaction(2019, 1); + EXPECT_EQ(ret, ERR_NONE); + } else { + HiLog::Info(LOG_LABEL, "Got Stub node\n"); + } + + getId = HiTrace::GetId(); + EXPECT_EQ(1, getId.IsValid()); + HiTrace::End(traceId); + getId = HiTrace::GetId(); + EXPECT_EQ(0, getId.IsValid()); +} diff --git a/ipc/test/BUILD.gn b/ipc/test/BUILD.gn new file mode 100755 index 00000000..a3ff7ee6 --- /dev/null +++ b/ipc/test/BUILD.gn @@ -0,0 +1,33 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +IPC_TEST_ROOT = "//foundation/communication/ipc/ipc/test" + +config("ipc_test_config") { + include_dirs = [ + "//utils/native/base/include", + "$IPC_TEST_ROOT/auxiliary/native/include", + "$SUBSYSTEM_DIR/utils/include", + "$SUBSYSTEM_DIR/ipc/native/src/mock/include", + ] +} + +#################################group######################################### +group("moduletest") { + testonly = true + deps = [ "moduletest/native:moduletest" ] +} +############################################################################### diff --git a/ipc/test/auxiliary/native/BUILD.gn b/ipc/test/auxiliary/native/BUILD.gn new file mode 100755 index 00000000..b95557f2 --- /dev/null +++ b/ipc/test/auxiliary/native/BUILD.gn @@ -0,0 +1,157 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. +import("//build/ohos.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +IPC_TEST_ROOT = "//foundation/communication/ipc/ipc/test" + +ohos_shared_library("ipc_test_helper") { + include_dirs = [ "//utils/system/safwk/native/include" ] + + sources = [ + "./src/assist_test_service.cpp", + "./src/foo_service.cpp", + "./src/ipc_test_helper.cpp", + "./src/test_service.cpp", + "./src/test_service_client.cpp", + "./src/test_service_skeleton.cpp", + ] + + configs = [ + "$IPC_TEST_ROOT:ipc_test_config", + "$SUBSYSTEM_DIR:ipc_util_config", + ] + + deps = [ "//utils/native/base:utils" ] + + external_deps = [ + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + part_name = "ipc" + subsystem_name = "communication" +} + +ohos_executable("ipc_server_test") { + sources = [ "./src/main_server.cpp" ] + + configs = [ + "$SUBSYSTEM_DIR:ipc_util_config", + "$IPC_TEST_ROOT:ipc_test_config", + ] + + deps = [ + ":ipc_test_helper", + "//utils/native/base:utils", + ] + + external_deps = [ + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + part_name = "ipc" + subsystem_name = "communication" +} + +ohos_executable("ipc_client_test") { + sources = [ "./src/main_client.cpp" ] + + configs = [ + "$SUBSYSTEM_DIR:ipc_util_config", + "$IPC_TEST_ROOT:ipc_test_config", + ] + + deps = [ + ":ipc_test_helper", + "//utils/native/base:utils", + ] + + external_deps = [ + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + part_name = "ipc" + subsystem_name = "communication" +} + +ohos_shared_library("ipc_test_helper_extra") { + include_dirs = [ "//utils/system/safwk/native/include" ] + + sources = [ + "./src/assist_test_service.cpp", + "./src/foo_service.cpp", + "./src/ipc_test_helper.cpp", + "./src/test_service.cpp", + "./src/test_service_client.cpp", + "./src/test_service_skeleton.cpp", + ] + + cflags = [ "-DIPCSERVERTESTEXTRA" ] + + configs = [ + "$IPC_TEST_ROOT:ipc_test_config", + "$SUBSYSTEM_DIR:ipc_util_config", + ] + + deps = [ "//utils/native/base:utils" ] + + external_deps = [ + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + part_name = "ipc" + subsystem_name = "communication" +} + +ohos_executable("ipc_server_test_extra") { + sources = [ "./src/main_server.cpp" ] + + configs = [ + "$SUBSYSTEM_DIR:ipc_util_config", + "$IPC_TEST_ROOT:ipc_test_config", + ] + + deps = [ + ":ipc_test_helper_extra", + "//utils/native/base:utils", + ] + + external_deps = [ + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + part_name = "ipc" + subsystem_name = "communication" +} + +############################################################################### +group("TestAssistance") { + testonly = true + deps = [ + ":ipc_client_test", + ":ipc_server_test", + ":ipc_server_test_extra", + ":ipc_test_helper", + ] +} +############################################################################### diff --git a/ipc/test/auxiliary/native/include/assist_test_service.h b/ipc/test/auxiliary/native/include/assist_test_service.h new file mode 100755 index 00000000..aaf19272 --- /dev/null +++ b/ipc/test/auxiliary/native/include/assist_test_service.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_ASSIST_TEST_SERVICE_H +#define OHOS_ASSIST_TEST_SERVICE_H + +#include "iremote_broker.h" +#include "iremote_proxy.h" + +namespace OHOS { +class IAssistTestService : public IRemoteBroker { +public: + enum { + TEST_PARCEL_INT32 = 0, + TEST_PARCEL_UINT32, + TEST_PARCEL_INT64, + TEST_PARCEL_UINT64, + TEST_PARCEL_FLOAT, + TEST_PARCEL_DOUBLE, + TEST_PARCEL_UINTPTR, + TEST_PARCEL_BOOL, + TEST_PARCEL_CHAR, + TEST_PARCEL_BYTE, + TEST_PARCEL_CSTRING = 10, + TEST_PARCEL_STRING8, + TEST_PARCEL_STRING16, + TEST_PARCEL_STRONGBINDER, + TEST_PARCEL_WEAKBINDER, + TEST_PARCEL_UINT8_FROM_UINT16, + WRITE_BYTEVECTOR_UNIQUE_PRT_INT8_CODE, + TEST_PARCEL_INT8_VECTOR, + WRITE_BYTEVECTOR_UNIQUE_PRT_U_INT8_CODE, + TEST_PARCEL_UINT8_VECTOR, + WRITE_INT32_VECTOR_UNIQUE_PRT_CODE = 20, + TEST_PARCEL_INT32_VECTOR, + WRITE_INT64_VECTOR_UNIQUE_PRT_CODE, + TEST_PARCEL_INT64_VECTOR, + WRITE_UINT64_VECTOR_UNIQUE_PRT_CODE, + TEST_PARCEL_UINT64_VECTOR, + WRITE_FLOAT_UNIQUE_PTR_CODE, + TEST_PARCEL_FLOAT_VECTOR, + WRITE_DOUBLE_UNIQUE_PTR_CODE, + TEST_PARCEL_DOUBLE_VECTOR, + WRITE_BOOL_UNIQUE_PTR_CODE = 30, + TEST_PARCEL_BOOL_VECTOR, + WRITE_CHAR_UNIQUE_PTR_CODE, + TEST_PARCEL_CHAR_VECTOR, + WRITE_STRING16_VECTOR_UNIQUE_PTR_CODE, + TEST_PARCEL_STRING16_VECTOR, + WRITE_UTF8_VECTOR_FROM_UNT16_VECTOR_UNIQUE_PTR_CODE, + WRITE_UTF8_VECTOR_FROM_UNT16_VECTOR_VECTOR_CODE, + WRITE_STRONGBINDERVECTOR_UNIQUE_PTR_CODE, + WRITE_STRONGBINDERVECTOR_VECTOR_CODE, + WRITE_MAP_CODE = 40, + WRITE_NULLABLE_MAP_CODE, + WRITE_NATIVE_HANDLE_CODE, + WRITE_EXCEPTION_CODE, + WRITE_FILE_DESCRIPTOR_CODE, + WRITE_PARCEL_FILE_DESCRIPTOR_CODE, + WRITE_UNIQUE_FILE_DESCRIPTOR_CODE, + WRITE_UNIQUE_FILE_DESCRIPTOR_VECTOR_UNIQUE_PTR_CODE, + WRITE_UNIQUE_FILE_DESCRIPTOR_VECTOR_VECTOR_CODE = 48, + WRITE_INVALID, + }; +public: + IAssistTestService() = default; + virtual ~IAssistTestService() = default; + virtual bool TestParcelBool(bool value) = 0; + virtual int16_t TestParcelChar(int16_t value) = 0; + virtual int32_t TestParcelInt32(int32_t value) = 0; + virtual int64_t TestParcelInt64(int64_t value) = 0; + virtual uint8_t TestParcelByte(uint8_t value) = 0; + virtual uint32_t TestParcelUint32(uint32_t value) = 0; + virtual uint64_t TestParcelUint64(uint64_t value) = 0; + virtual float TestParcelFloat(float value) = 0; + virtual double TestParcelDouble(double value) = 0; + virtual const char *TestParcelCString(const char *value) = 0; + virtual const std::string TestParcelString(const std::string& value) = 0; + virtual const std::u16string TestParcelString16(const std::u16string& val) = 0; + virtual bool TestParcelBoolVector() = 0; + virtual bool TestParcelInt8Vector() = 0; + virtual bool TestParcelUint8Vector() = 0; + virtual bool TestParcelCharVector() = 0; + virtual bool TestParcelInt64Vector() = 0; + virtual bool TestParcelUint64Vector() = 0; + virtual bool TestParcelInt32Vector() = 0; + virtual bool TestParcelFloatVector() = 0; + virtual bool TestParcelDoubleVector() = 0; + virtual bool TestParcelString16Vector() = 0; +public: + DECLARE_INTERFACE_DESCRIPTOR(u"test.ipc.IAssistTestService"); +}; + +class AssistTestServiceProxy : public IRemoteProxy { +public: + explicit AssistTestServiceProxy(const sptr& object); + ~AssistTestServiceProxy(); + + bool TestParcelBool(bool value) override; + int16_t TestParcelChar(int16_t value) override; + int32_t TestParcelInt32(int32_t value) override; + int64_t TestParcelInt64(int64_t value) override; + uint8_t TestParcelByte(uint8_t value) override; + uint32_t TestParcelUint32(uint32_t value) override; + uint64_t TestParcelUint64(uint64_t value) override; + float TestParcelFloat(float value) override; + double TestParcelDouble(double value) override; + const char *TestParcelCString(const char *value) override; + const std::string TestParcelString(const std::string& value) override; + const std::u16string TestParcelString16(const std::u16string& val) override; + bool TestParcelBoolVector() override; + bool TestParcelInt8Vector() override; + bool TestParcelUint8Vector() override; + bool TestParcelCharVector() override; + bool TestParcelInt64Vector() override; + bool TestParcelUint64Vector() override; + bool TestParcelInt32Vector() override; + bool TestParcelFloatVector() override; + bool TestParcelDoubleVector() override; + bool TestParcelString16Vector() override; +private: + static inline BrokerDelegator delegator_; +}; +} // namespace OHOS +#endif // OHOS_ASSIST_TEST_SERVICE_H diff --git a/ipc/test/auxiliary/native/include/foo_service.h b/ipc/test/auxiliary/native/include/foo_service.h new file mode 100755 index 00000000..8f0b5d38 --- /dev/null +++ b/ipc/test/auxiliary/native/include/foo_service.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_FOO_SERVICE_H +#define OHOS_IPC_FOO_SERVICE_H + +#include +#include +#include "iremote_broker.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" +#include "hilog/log.h" +#include "log_tags.h" + +namespace OHOS { + +class IFoo : public IRemoteBroker { +public: + enum FooInterFaceId { + GET_FOO_NAME = 0, + SEND_ASYNC_REPLY = 1, + SEND_WRONG_REPLY = 2, + }; + virtual std::string GetFooName() = 0; + virtual void SendAsyncReply(int &reply) = 0; + virtual int TestNestingSend(int sendCode) = 0; +public: + DECLARE_INTERFACE_DESCRIPTOR(u"test.ipc.IFoo"); +}; + +class FooStub : public IRemoteStub { +public: + virtual ~FooStub(); + virtual int OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + std::string GetFooName() override; + void SendAsyncReply(int &reply) override; + int WaitForAsyncReply(int timeout); + static void CleanDecTimes(); + static int GetDecTimes(); + int TestNestingSend(int sendCode) override; +public: + static std::mutex decTimeMutex_; + static int decTimes_; +private: + int asyncReply_ = { 0 }; + std::mutex mutex_; + std::condition_variable cv_; + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "FooStub" }; +}; + +class FooProxy : public IRemoteProxy { +public: + explicit FooProxy(const sptr &impl); + ~FooProxy() = default; + std::string GetFooName() override; + void SendAsyncReply(int &reply) override; + int TestNestingSend(int sendCode) override; +private: + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "FooProxy" }; + static inline BrokerDelegator delegator_; +}; +} // namespace OHOS +#endif // OHOS_IPC_FOO_SERVICE_H + diff --git a/ipc/test/auxiliary/native/include/ipc_test_helper.h b/ipc/test/auxiliary/native/include/ipc_test_helper.h new file mode 100755 index 00000000..df465249 --- /dev/null +++ b/ipc/test/auxiliary/native/include/ipc_test_helper.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_TEST_HELPER_H +#define OHOS_IPC_TEST_HELPER_H + +#include +#include +#include +#include +#include +#include +#include "ipc_debug.h" +#include "log_tags.h" + +namespace OHOS { +const static int INVALID_PID = -1; + +class IPCTestHelper { +public: + enum { + IPC_TEST_SAMGR, + IPC_TEST_SERVER, + IPC_TEST_CLIENT, + IPC_TEST_MSG_SERVER, + IPC_TEST_MSG_CLIENT, + IPC_TEST_SERVER_EXTRA, + IPC_TEST_NONE = 0xFF, + }; + + IPCTestHelper() = default; + ~IPCTestHelper(); + static const std::string &GetTestAppName(int appId); + pid_t GetPidByName(std::string task_name); + bool GetChildPids(std::vector &childPids); + + pid_t StartExecutable(std::string name, std::string args = ""); + + bool StopExecutable(pid_t pid); + bool StopExecutable(std::string name); + + bool PrepareTestSuite(); + bool TearDownTestSuite(); + + void AddTestAppPid(const std::string &appName, const int &pid); + void RemoveTestAppPid(const std::string &appName); + + bool StartTestApp(int appId, const int &cmdId = 0); + bool StopTestApp(int appId); + + pid_t GetTestAppPid(int appId); + + pid_t GetPid(); + uid_t GetUid(); + + long GetCurrentTimeMs(); + +private: + std::mutex mutex_; + std::map testPids_; + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCTestHelper" }; +}; +} // namespace OHOS +#endif // OHOS_IPC_TEST_HELPER_H diff --git a/ipc/test/auxiliary/native/include/ohos_rpc_test_testhelper.h b/ipc/test/auxiliary/native/include/ohos_rpc_test_testhelper.h new file mode 100755 index 00000000..22f1591e --- /dev/null +++ b/ipc/test/auxiliary/native/include/ohos_rpc_test_testhelper.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_TEST_TESTHELP_H +#define OHOS_RPC_TEST_TESTHELP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeNewInstance + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_ohos_rpc_test_TestHelper_nativeNewInstance( + JNIEnv *env, jclass clazz); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeFreeInstance + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_ohos_rpc_test_TestHelper_nativeFreeInstance( + JNIEnv *env, jobject object, jlong); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativePrepareTestSuite + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativePrepareTestSuite( + JNIEnv *env, jobject object); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeTearDownTestSuite + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeTearDownTestSuite( + JNIEnv *env, jobject object); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeStartTestServer + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeStartTestApp( + JNIEnv *env, jobject object, jint appId, jint commandId); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: StopTestApp + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeStopTestApp( + JNIEnv *env, jobject object, jlong appId); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeGetTestServerPid + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_ohos_rpc_test_TestHelper_nativeGetTestAppPid( + JNIEnv *env, jobject object, jint appId); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeGetUid + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_ohos_rpc_test_TestHelper_nativeGetUid( + JNIEnv *env, jobject object); +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeGetPid + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_ohos_rpc_test_TestHelper_nativeGetPid( + JNIEnv *env, jobject object); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeStartExecutable + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeStartExecutable( + JNIEnv *env, jobject object, jstring, jint); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeStopExecutable + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeStopExecutable( + JNIEnv *env, jobject object, jstring string, jint length); + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeRunCommand + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeRunCommand( + JNIEnv *env, jobject object, jstring string, jint length); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_TEST_TESTHELP_H diff --git a/ipc/test/auxiliary/native/include/test_service.h b/ipc/test/auxiliary/native/include/test_service.h new file mode 100755 index 00000000..585bfb02 --- /dev/null +++ b/ipc/test/auxiliary/native/include/test_service.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_TEST_SERVICE_H +#define OHOS_IPC_TEST_SERVICE_H + +#include "hilog/log.h" +#include "log_tags.h" +#include "test_service_skeleton.h" + +namespace OHOS { + +class TestService : public TestServiceStub { +public: + TestService(); + ~TestService(); + static int Instantiate(); + int TestSyncTransaction(int data, int &rep, int delayTime = 0) override; + int TestAsyncTransaction(int data, int timeout = 0) override; + int TestAsyncCallbackTrans(int data, int &reply, int timeout) override; + int TestPingService(const std::u16string &serviceName) override; + int TestGetFileDescriptor() override; + int TestStringTransaction(const std::string& data) override; + int TestZtraceTransaction(std::string& send, std::string& reply, int len) override; + void TestDumpService() override; + int TestRawDataTransaction(int length, int &reply) override; + int TestRawDataReply(int length) override; + sptr TestGetFooService() override; + int Dump(int fd, const std::vector& args) override; + int TestCallingUidPid() override; + int TestFlushAsyncCalls(int count, int length) override; + int TestMultipleProcesses(int data, int &rep, int delayTime) override; + std::u16string TestAshmem(sptr ashmem, int32_t contentSize) override; + void TestAsyncDumpService() override; + int TestNestingSend(int sendCode, int &replyCode) override; +private: + int testFd_; + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestService" }; +}; +} // namespace OHOS +#endif // OHOS_IPC_TEST_SERVICE_H + diff --git a/ipc/test/auxiliary/native/include/test_service_client.h b/ipc/test/auxiliary/native/include/test_service_client.h new file mode 100755 index 00000000..90952b9b --- /dev/null +++ b/ipc/test/auxiliary/native/include/test_service_client.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_TEST_SERVICE_CLIENT_H +#define OHOS_IPC_TEST_SERVICE_CLIENT_H + +#include +#include +#include "test_service_skeleton.h" +#include "log_tags.h" + +namespace OHOS { +struct TraceParam { + int dataSize; + int testTimes; + int sleepUs; +}; + +class TestServiceClient { +public: + int ConnectService(); + void StartSyncTransaction(); + void StartSyncDelayReply(); + void StartAsyncTransaction(); + void StartPingService(); + void StartGetFooService(); + int StartLoopTest(int maxCount); + void StartDumpService(); + void StartTestFileDescriptor(); + void StartAsyncDumpService(); +private: + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestServiceClient" }; + sptr testService_; +}; +} // namespace OHOS +#endif // OHOS_IPC_TEST_SERVICE_CLIENT_H diff --git a/ipc/test/auxiliary/native/include/test_service_command.h b/ipc/test/auxiliary/native/include/test_service_command.h new file mode 100755 index 00000000..aa9c3d7b --- /dev/null +++ b/ipc/test/auxiliary/native/include/test_service_command.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_TEST_SERVICE_COMMAND_H +#define OHOS_IPC_TEST_SERVICE_COMMAND_H + +enum class TestCommand : int { + TEST_CMD_NONE = 0, + TEST_CMD_SYNC_TRANS = 1, + TEST_CMD_ASYNC_TRANS = 2, + TEST_CMD_PING_SERVICE = 3, + TEST_CMD_GET_FOO_SERVICE = 4, + TEST_CMD_TRANS_FILE_DESC = 5, + TEST_CMD_TRANSACTION = 6, + TEST_CMD_DUMP_SERVICE = 8, + TEST_CMD_LOOP_TRANSACTION = 9, + TEST_CMD_ASYNC_DUMP_SERVICE = 10, +}; +#endif // OHOS_IPC_TEST_SERVICE_COMMAND_H diff --git a/ipc/test/auxiliary/native/include/test_service_skeleton.h b/ipc/test/auxiliary/native/include/test_service_skeleton.h new file mode 100755 index 00000000..d8d89f40 --- /dev/null +++ b/ipc/test/auxiliary/native/include/test_service_skeleton.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_TEST_SERVICE_SKELETON_H +#define OHOS_TEST_SERVICE_SKELETON_H + +#include "ipc_debug.h" +#include "iremote_broker.h" +#include "iremote_stub.h" +#include "iremote_proxy.h" +#include "foo_service.h" +#include "ipc_file_descriptor.h" +#include "log_tags.h" + +namespace OHOS { + +class ITestService : public IRemoteBroker { +public: + enum { + TRANS_ID_SYNC_TRANSACTION = 1, + TRANS_ID_ASYNC_TRANSACTION = 2, + TRANS_ID_PING_SERVICE = 3, + TRANS_ID_GET_FOO_SERVICE = 4, + TRANS_ID_TRANSACT_FILE_DESC = 5, + TRANS_ID_STRING_TRANSACTION = 6, + TRANS_ID_ZTRACE_TRANSACTION = 7, + TRANS_ID_LOOP_TRANSACTION = 8, + TRANS_ID_DUMP_SERVICE = 9, + TRANS_ID_RAWDATA_TRANSACTION = 10, + TRANS_ID_RAWDATA_REPLY = 11, + TRANS_ID_CALLING_UID_PID = 12, + TRANS_ID_FLUSH_ASYNC_CALLS = 13, + TRANS_ID_MULTIPLE_PROCESSES = 14, + TRANS_ID_ASHMEM = 15, + TRANS_ID_ASYNC_DUMP_SERVICE = 16, + TRANS_ID_NESTING_SEND = 17, + }; +public: + virtual int TestSyncTransaction(int data, int &reply, int delayTime = 0) = 0; + virtual int TestAsyncTransaction(int data, int timeout = 0) = 0; + virtual int TestAsyncCallbackTrans(int data, int &reply, int timeout = 0) = 0; + virtual int TestGetFileDescriptor() = 0; + virtual int TestPingService(const std::u16string &serviceName) = 0; + virtual int TestStringTransaction(const std::string &data) = 0; + virtual int TestZtraceTransaction(std::string &send, std::string &reply, int len) = 0; + virtual void TestDumpService() = 0; + virtual int TestRawDataTransaction(int length, int &reply) = 0; + virtual int TestRawDataReply(int length) = 0; + virtual sptr TestGetFooService() = 0; + virtual int TestCallingUidPid() = 0; + virtual int TestFlushAsyncCalls(int count, int length) = 0; + virtual int TestMultipleProcesses(int data, int &rep, int delayTime) = 0; + virtual std::u16string TestAshmem(sptr ashmem, int32_t contentSize) = 0; + virtual void TestAsyncDumpService() = 0; + virtual int TestNestingSend(int sendCode, int &replyCode) = 0; +public: + DECLARE_INTERFACE_DESCRIPTOR(u"test.ipc.ITestService"); +}; + +class TestServiceStub : public IRemoteStub { +public: + virtual int OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) override; +private: + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestServiceStub" }; + int TransferRawData(MessageParcel &data, MessageParcel &reply); + int ReplyRawData(MessageParcel &data, MessageParcel &reply); + void TransferToNextProcess(MessageParcel &data, MessageParcel &reply); + void ReadAshmem(MessageParcel &data, MessageParcel &reply); +}; + +class TestServiceProxy : public IRemoteProxy { +public: + explicit TestServiceProxy(const sptr &impl); + ~TestServiceProxy() = default; + int TestSyncTransaction(int data, int &reply, int delayTime = 0) override; + int TestAsyncTransaction(int data, int timeout = 0) override; + int TestAsyncCallbackTrans(int data, int &reply, int timeout = 0) override; + int TestPingService(const std::u16string &serviceName) override; + int TestGetFileDescriptor() override; + int TestStringTransaction(const std::string &data) override; + int TestZtraceTransaction(std::string &send, std::string &reply, int len) override; + void TestDumpService() override; + int TestRawDataTransaction(int length, int &reply) override; + int TestRawDataReply(int length) override; + sptr TestGetFooService() override; + int TestCallingUidPid() override; + int TestFlushAsyncCalls(int count, int length) override; + int TestMultipleProcesses(int data, int &rep, int delayTime) override; + std::u16string TestAshmem(sptr ashmem, int32_t contentSize) override; + void TestAsyncDumpService() override; + int TestNestingSend(int sendCode, int &replyCode) override; +private: + static inline BrokerDelegator delegator_; + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestServiceProxy" }; +}; + +class TestDeathRecipient : public IRemoteObject::DeathRecipient { +public: + virtual void OnRemoteDied(const wptr &remote); + TestDeathRecipient(); + virtual ~TestDeathRecipient(); + static bool GotDeathRecipient(); + static bool gotDeathRecipient_; +private: + static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestDeathRecipient" }; +}; + +} // namespace OHOS +#endif // OHOS_TEST_SERVICE_SKELETON_H diff --git a/ipc/test/auxiliary/native/src/assist_test_service.cpp b/ipc/test/auxiliary/native/src/assist_test_service.cpp new file mode 100755 index 00000000..0f99d1d3 --- /dev/null +++ b/ipc/test/auxiliary/native/src/assist_test_service.cpp @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_types.h" +#include "assist_test_service.h" + +namespace OHOS { +AssistTestServiceProxy::AssistTestServiceProxy(const sptr& object) + : IRemoteProxy(object) +{ +} + +AssistTestServiceProxy::~AssistTestServiceProxy() +{ +} + +bool AssistTestServiceProxy::TestParcelBool(bool value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteBool(value); + int res = Remote()->SendRequest(TEST_PARCEL_BOOL, data, reply, option); + return (res == ERR_NONE) ? reply.ReadBool() : false; +} + +int16_t AssistTestServiceProxy::TestParcelChar(int16_t value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteInt16(value); + int res = Remote()->SendRequest(TEST_PARCEL_CHAR, data, reply, option); + return (res == ERR_NONE) ? reply.ReadInt16() : 0; +} + +int32_t AssistTestServiceProxy::TestParcelInt32(int32_t value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteInt32(value); + int res = Remote()->SendRequest(TEST_PARCEL_INT32, data, reply, option); + return (res == ERR_NONE) ? reply.ReadInt32() : 0; +} + +int64_t AssistTestServiceProxy::TestParcelInt64(int64_t value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteInt64(value); + int res = Remote()->SendRequest(TEST_PARCEL_INT64, data, reply, option); + return (res == ERR_NONE) ? reply.ReadInt64() : 0; +} + +uint8_t AssistTestServiceProxy::TestParcelByte(uint8_t value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteUint8(value); + int res = Remote()->SendRequest(TEST_PARCEL_BYTE, data, reply, option); + return (res == ERR_NONE) ? reply.ReadUint8() : 0; +} + +uint32_t AssistTestServiceProxy::TestParcelUint32(uint32_t value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteUint32(value); + int res = Remote()->SendRequest(TEST_PARCEL_UINT32, data, reply, option); + return (res == ERR_NONE) ? reply.ReadUint32() : 0; +} + +uint64_t AssistTestServiceProxy::TestParcelUint64(uint64_t value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteUint64(value); + int res = Remote()->SendRequest(TEST_PARCEL_UINT64, data, reply, option); + return (res == ERR_NONE) ? reply.ReadUint64() : 0; +} + +float AssistTestServiceProxy::TestParcelFloat(float value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteFloat(value); + int res = Remote()->SendRequest(TEST_PARCEL_FLOAT, data, reply, option); + return (res == ERR_NONE) ? reply.ReadFloat() : 0; +} + +double AssistTestServiceProxy::TestParcelDouble(double value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteDouble(value); + int res = Remote()->SendRequest(TEST_PARCEL_DOUBLE, data, reply, option); + return (res == ERR_NONE) ? reply.ReadDouble() : 0; +} + +const char *AssistTestServiceProxy::TestParcelCString(const char *value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteCString(value); + int res = Remote()->SendRequest(TEST_PARCEL_CSTRING, data, reply, option); + return (res == ERR_NONE) ? reply.ReadCString() : nullptr; +} + +const std::string AssistTestServiceProxy::TestParcelString(const std::string& value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteString(value); + int res = Remote()->SendRequest(TEST_PARCEL_STRING8, data, reply, option); + return (res == ERR_NONE) ? reply.ReadString() : std::string(); +} + +const std::u16string AssistTestServiceProxy::TestParcelString16(const std::u16string& value) +{ + MessageParcel data, reply; + MessageOption option; + data.WriteString16(value); + int res = Remote()->SendRequest(TEST_PARCEL_STRING16, data, reply, option); + return (res == ERR_NONE) ? reply.ReadString16() : std::u16string(); +} + +bool AssistTestServiceProxy::TestParcelBoolVector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readBoolVector; + std::vector writeBoolVector = { false, false, true, false, true }; + data.WriteBoolVector(writeBoolVector); + + if (Remote()->SendRequest(TEST_PARCEL_BOOL_VECTOR, data, reply, option) != ERR_NONE) { + return false; + } + + if (!reply.ReadBoolVector(&readBoolVector)) { + return false; + } + + for (size_t i = 0; i < writeBoolVector.size(); i++) { + if (writeBoolVector[i] != readBoolVector[i]) { + bool write = writeBoolVector[i]; + bool read = readBoolVector[i]; + printf("index:%zu write:%d, read:%d\n", i, write, read); + return false; + } + } + + return true; +} + +bool AssistTestServiceProxy::TestParcelInt8Vector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readInt8Vector; + std::vector writeInt8Vector = { 0x01, 0x10, -0x20, 0x30, 0x40 }; + data.WriteInt8Vector(writeInt8Vector); + int res = Remote()->SendRequest(TEST_PARCEL_INT8_VECTOR, data, reply, option); + if (res != ERR_NONE) { + return false; + } + + if (!reply.ReadInt8Vector(&readInt8Vector)) { + return false; + } + + for (size_t i = 0; i < writeInt8Vector.size(); i++) { + if (writeInt8Vector[i] != readInt8Vector[i]) { + return false; + } + } + + return true; +} + +bool AssistTestServiceProxy::TestParcelUint8Vector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readUint8Vector; + std::vector writeUint8Vector = { 0xA1, 0xA1, 0xA2, 0x30, 0x40 }; + data.WriteUInt8Vector(writeUint8Vector); + + if (Remote()->SendRequest(TEST_PARCEL_UINT8_VECTOR, data, reply, option) != ERR_NONE) { + return false; + } + + if (!reply.ReadUInt8Vector(&readUint8Vector)) { + return false; + } + + for (size_t i = 0; i < writeUint8Vector.size(); i++) { + if (writeUint8Vector[i] != readUint8Vector[i]) { + return false; + } + } + + return true; +} + +bool AssistTestServiceProxy::TestParcelCharVector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readInt16Vector; + std::vector writeInt16Vector = { 0x1234, -0x2345, 0x3456, -0x4567, 0x5678 }; + data.WriteInt16Vector(writeInt16Vector); + + if (Remote()->SendRequest(TEST_PARCEL_CHAR_VECTOR, data, reply, option) != ERR_NONE) { + return false; + } + + if (!reply.ReadInt16Vector(&readInt16Vector)) { + return false; + } + + for (size_t i = 0; i < writeInt16Vector.size(); i++) { + if (writeInt16Vector[i] != readInt16Vector[i]) { + return false; + } + } + + return true; +} + +bool AssistTestServiceProxy::TestParcelInt64Vector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readInt64Vector; + std::vector writeInt64Vector = { 0x1234567887654321, -0x2345678998765432 }; + data.WriteInt64Vector(writeInt64Vector); + + if (Remote()->SendRequest(TEST_PARCEL_INT64_VECTOR, data, reply, option) != ERR_NONE) { + return false; + } + + if (!reply.ReadInt64Vector(&readInt64Vector)) { + return false; + } + + for (size_t i = 0; i < writeInt64Vector.size(); i++) { + if (writeInt64Vector[i] != readInt64Vector[i]) { + return false; + } + } + + return true; +} + +bool AssistTestServiceProxy::TestParcelUint64Vector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readUint64Vector; + std::vector writeUint64Vector = { 0x1234567887654321, 0x2345678998765432 }; + data.WriteUInt64Vector(writeUint64Vector); + + if (Remote()->SendRequest(TEST_PARCEL_UINT64_VECTOR, data, reply, option) != ERR_NONE) { + return false; + } + + bool result = reply.ReadUInt64Vector(&readUint64Vector); + if (result != true) { + return false; + } + + for (size_t i = 0; i < writeUint64Vector.size(); i++) { + if (writeUint64Vector[i] != readUint64Vector[i]) { + return false; + } + } + + return true; +} + +bool AssistTestServiceProxy::TestParcelInt32Vector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readInt32Vector; + std::vector writeInt32Vector = { 0x12345678, -0x23456789, 0x34567890, -0x45678901 };; + data.WriteInt32Vector(writeInt32Vector); + + if (Remote()->SendRequest(TEST_PARCEL_INT32_VECTOR, data, reply, option) != ERR_NONE) { + return false; + } + + if (!reply.ReadInt32Vector(&readInt32Vector)) { + return false; + } + + for (size_t i = 0; i < writeInt32Vector.size(); i++) { + if (writeInt32Vector[i] != readInt32Vector[i]) { + return false; + } + } + + return true; +} + +bool AssistTestServiceProxy::TestParcelFloatVector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readFloatVector; + std::vector writeFloatVector{ 11221.132313, 11221.45678 }; + data.WriteFloatVector(writeFloatVector); + + if (Remote()->SendRequest(TEST_PARCEL_FLOAT_VECTOR, data, reply, option) != ERR_NONE) { + return false; + } + + if (!reply.ReadFloatVector(&readFloatVector)) { + return false; + } + + for (size_t i = 0; i < writeFloatVector.size(); i++) { + if (writeFloatVector[i] != readFloatVector[i]) { + return false; + } + } + + return true; +} + +bool AssistTestServiceProxy::TestParcelDoubleVector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readDoubleVector; + std::vector writeDoubleVector{ 1122.132313, 1122.45678 }; + data.WriteDoubleVector(writeDoubleVector); + + if (Remote()->SendRequest(TEST_PARCEL_DOUBLE_VECTOR, data, reply, option) != ERR_NONE) { + return false; + } + + if (!reply.ReadDoubleVector(&readDoubleVector)) { + return false; + } + + for (size_t i = 0; i < writeDoubleVector.size(); i++) { + if (writeDoubleVector[i] != readDoubleVector[i]) { + return false; + } + } + + return true; +} + +bool AssistTestServiceProxy::TestParcelString16Vector() +{ + MessageParcel data, reply; + MessageOption option; + std::vector readString16Vector; + std::vector writeString16Vector{ + u"test", u"test for", u"test for write", u"test for write vector" + }; + data.WriteString16Vector(writeString16Vector); + if (Remote()->SendRequest(TEST_PARCEL_STRING16_VECTOR, data, reply, option) != ERR_NONE) { + return false; + } + + if (!reply.ReadString16Vector(&readString16Vector)) { + return false; + } + + for (size_t i = 0; i < writeString16Vector.size(); i++) { + if (writeString16Vector[i].compare(readString16Vector[i])) { + return false; + } + } + + return true; +} +} // namespace OHOS \ No newline at end of file diff --git a/ipc/test/auxiliary/native/src/foo_service.cpp b/ipc/test/auxiliary/native/src/foo_service.cpp new file mode 100755 index 00000000..6526b387 --- /dev/null +++ b/ipc/test/auxiliary/native/src/foo_service.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "foo_service.h" +#include "ipc_debug.h" +#include "ipc_types.h" + +namespace OHOS { +std::mutex FooStub::decTimeMutex_; +int FooStub::decTimes_ = 0; + +int FooStub::OnRemoteRequest(uint32_t code, + MessageParcel& data, MessageParcel& reply, MessageOption& option) +{ + int result = ERR_NONE; + + switch (code) { + case GET_FOO_NAME: { + ZLOGI(LABEL, "%{public}s:called\n", __func__); + reply.WriteString(GetFooName()); + break; + } + case SEND_ASYNC_REPLY: { + int32_t replyData = data.ReadInt32(); + SendAsyncReply(replyData); + break; + } + case SEND_WRONG_REPLY: { + return TestNestingSend(data.ReadInt32()); + } + default: + result = ERR_TRANSACTION_FAILED; + break; + } + + return result; +} + +std::string FooStub::GetFooName() +{ + return "ReallFoo"; +} + +int FooStub::WaitForAsyncReply(int timeout) +{ + asyncReply_ = 0; + std::unique_lock lck(mutex_); + cv_.wait_for(lck, std::chrono::milliseconds(timeout), [&]() { + return asyncReply_ != 0; + }); + return asyncReply_; +} + +void FooStub::SendAsyncReply(int &replyValue) +{ + std::unique_lock lck(mutex_); + asyncReply_ = replyValue; + cv_.notify_all(); +} + +FooStub::~FooStub() +{ + std::unique_lock lck(decTimeMutex_); + decTimes_++; +} + +void FooStub::CleanDecTimes() +{ + std::unique_lock lck(decTimeMutex_); + decTimes_ = 0; +} + +int FooStub::GetDecTimes() +{ + std::unique_lock lck(decTimeMutex_); + return decTimes_; +} + +int FooStub::TestNestingSend(int sendCode) +{ + return sendCode; +} +FooProxy::FooProxy(const sptr &impl) + : IRemoteProxy(impl) +{ +} + +std::string FooProxy::GetFooName() +{ + ZLOGI(LABEL, "%{public}s:called\n", __func__); + MessageParcel data, reply; + MessageOption option; + Remote()->SendRequest(GET_FOO_NAME, data, reply, option); + return reply.ReadString(); +} + +void FooProxy::SendAsyncReply(int &replyValue) +{ + ZLOGI(LABEL, "%{public}s:called\n", __func__); + MessageParcel data, reply; + MessageOption option = { MessageOption::TF_ASYNC }; + data.WriteInt32(replyValue); + Remote()->SendRequest(SEND_ASYNC_REPLY, data, reply, option); +} + +int FooProxy::TestNestingSend(int sendCode) +{ + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(sendCode)) { + return -1; + } + int error = Remote()->SendRequest(SEND_WRONG_REPLY, dataParcel, replyParcel, option); + ZLOGE(LABEL, "send foo result = %{public}d", error); + return error; +} +} // namespace OHOS \ No newline at end of file diff --git a/ipc/test/auxiliary/native/src/ipc_test_helper.cpp b/ipc/test/auxiliary/native/src/ipc_test_helper.cpp new file mode 100755 index 00000000..1ed8a3f1 --- /dev/null +++ b/ipc/test/auxiliary/native/src/ipc_test_helper.cpp @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_test_helper.h" +#include +#include +#include +#include +#include +#include +#include +#include "ipc_debug.h" +#include "test_service_client.h" + +using namespace OHOS::HiviewDFX; +namespace OHOS { +static const int MAX_NAME_LEN = 256; +static const int MAX_BUFFER_SIZE = 1024; +static const int SLEEP_TIME = 500000; // ms +static const int SECOND_TO_MS = 1000; +static const int ONE_SECOND = 1; // seconds +static const int MAX_CHECK_COUNT = 10; +static const int SIG_KILL = 9; + +const std::string &IPCTestHelper::GetTestAppName(int appId) +{ + static std::map appNames = { + { IPC_TEST_NONE, ""}, + { IPC_TEST_SAMGR, "samgr" }, + { IPC_TEST_SERVER, "ipc_server_test" }, + { IPC_TEST_SERVER_EXTRA, "ipc_server_test_extra" }, + { IPC_TEST_CLIENT, "ipc_client_test" }, + { IPC_TEST_MSG_SERVER, "ipcmsg_server" }, + { IPC_TEST_MSG_CLIENT, "ipcmsg_client" }, + }; + + if (appNames.count(appId)) { + return appNames[appId]; + } + + return appNames[IPC_TEST_NONE]; +} + +IPCTestHelper::~IPCTestHelper() +{ + TearDownTestSuite(); +} + +pid_t IPCTestHelper::GetPidByName(std::string task_name) +{ + struct dirent *ptr = nullptr; + FILE *fp = nullptr; + + char filepath[MAX_NAME_LEN + 1]; + char curTaskName[MAX_NAME_LEN + 1]; + char buf[MAX_BUFFER_SIZE]; + pid_t pid = INVALID_PID; + + DIR *dir = opendir("/proc"); + if (dir == nullptr) { + return pid; + } + + for (;;) { + ptr = readdir(dir); + if (ptr == nullptr) { + break; + } + + if ((strcmp(ptr->d_name, ".") == 0) || + (strcmp(ptr->d_name, "..") == 0) || + (ptr->d_type != DT_DIR)) { + continue; + } + + if (sprintf_s(filepath, sizeof(filepath), "/proc/%s/status", ptr->d_name) <= 0) { + ZLOGE(LABEL, "format file failed"); + closedir(dir); + return INVALID_PID; + } + + fp = fopen(filepath, "r"); + if (fp == nullptr) { + continue; + } + + if (fgets(buf, MAX_BUFFER_SIZE - 1, fp) == nullptr) { + fclose(fp); + continue; + } + + if (sscanf_s(buf, "%*s %s", curTaskName, sizeof(curTaskName)) <= 0) { + ZLOGE(LABEL, "could not find current task"); + } + + if (!strcmp(task_name.c_str(), curTaskName)) { + if (sscanf_s(ptr->d_name, "%d", &pid) <= 0) { + ZLOGE(LABEL, "could not find target task"); + } + } + + fclose(fp); + } + + closedir(dir); + + return pid; +} + +bool IPCTestHelper::GetChildPids(std::vector &childPids) +{ + pid_t current = getpid(); + ZLOGI(LABEL, "current pid %d\n", current); + const std::string taskPath = "/proc/" + std::to_string(current) + "/task"; + DIR *dir = opendir(taskPath.c_str()); + if (dir == nullptr) { + return false; + } + struct dirent *ptr = nullptr; + for (;;) { + ptr = readdir(dir); + if (ptr == nullptr) { + break; + } + + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) { + continue; + } + + if (ptr->d_type != DT_DIR) { + continue; + } + + pid_t child = std::stoi(ptr->d_name); + if (child == current) { + continue; + } + + childPids.push_back(child); + ZLOGI(LABEL, "child pid %d", child); + } + + closedir(dir); + + return true; +} + +pid_t IPCTestHelper::StartExecutable(std::string name, std::string args) +{ + pid_t execPid; + int checkCount = 0; + const char *ld_library_path = getenv("LD_LIBRARY_PATH"); + + if (ld_library_path != nullptr) { + unsetenv("LD_LIBRARY_PATH"); + } + + std::string cmd1 = "chmod +x /system/bin/" + name; + int res = system(cmd1.c_str()); + ZLOGI(LABEL, "%s, res = %d\n", cmd1.c_str(), res); + + // kill the program if the program is already exist. + execPid = GetPidByName(name); + StopExecutable(execPid); + + std::string cmd2 = name + " " + args + "&"; + res = system(cmd2.c_str()); + + if (ld_library_path != nullptr) { + setenv("LD_LIBRARY_PATH", ld_library_path, 1); + } + + ZLOGI(LABEL, "%s res = %d\n", cmd2.c_str(), res); + + do { + execPid = GetPidByName(name); + sleep(ONE_SECOND); + + if (execPid != INVALID_PID) { + break; + } + } while (checkCount++ < MAX_CHECK_COUNT); + + ZLOGI(LABEL, "start %s done, pid:%d\n", name.c_str(), execPid); + return execPid; +} + +bool IPCTestHelper::StopExecutable(pid_t pid) +{ + if (pid != INVALID_PID) { + ZLOGI(LABEL, "kill pid = %d\n", pid); + kill(pid, SIG_KILL); + } + + return true; +} + +bool IPCTestHelper::StopExecutable(std::string name) +{ + pid_t pid = GetPidByName(name); + if (pid != INVALID_PID) { + ZLOGI(LABEL, "%s pid = %d, kill it\n", name.c_str(), pid); + kill(pid, SIG_KILL); + } + + return true; +} + +bool IPCTestHelper::PrepareTestSuite() +{ + pid_t pid = GetTestAppPid(IPC_TEST_SAMGR); + if (pid == INVALID_PID) { + usleep(SLEEP_TIME); + pid = StartTestApp(IPC_TEST_SAMGR); + ZLOGI(LABEL, "StartSystemServer done"); + } + + return (pid != INVALID_PID); +} + +bool IPCTestHelper::TearDownTestSuite() +{ + for (auto it = testPids_.begin(); it != testPids_.end();) { + ZLOGI(LABEL, "kill %s", it->first.c_str()); + StopExecutable(it->second); + it = testPids_.erase(it); + } + + return true; +} +void IPCTestHelper::AddTestAppPid(const std::string &appName, const int &pid) +{ + std::lock_guard auto_lock(mutex_); + testPids_.insert(std::make_pair(appName, pid)); +} + +void IPCTestHelper::RemoveTestAppPid(const std::string &appName) +{ + std::lock_guard auto_lock(mutex_); + auto it = testPids_.find(appName); + if (it != testPids_.end()) { + testPids_.erase(appName); + } +} + +bool IPCTestHelper::StartTestApp(int appId, const int &cmdId) +{ + int pid = INVALID_PID; + std::string appName = GetTestAppName(appId); + if (!appName.empty()) { + if (cmdId > 0) { + pid = StartExecutable(appName, std::to_string(cmdId)); + } else { + pid = StartExecutable(appName); + } + } + + if (pid != INVALID_PID) { + RemoveTestAppPid(appName); // should remove it if exist; + AddTestAppPid(appName, pid); + } + + ZLOGI(LABEL, "StartTestApp:%d cmdId=%d pid = %d", appId, cmdId, pid); + return (pid != INVALID_PID); +} + +bool IPCTestHelper::StopTestApp(int appId) +{ + std::string appName = GetTestAppName(appId); + if (appName.empty()) { + return false; + } + + pid_t pid = GetTestAppPid(appId); + if (pid != INVALID_PID) { + pid = StopExecutable(pid); + RemoveTestAppPid(appName); + usleep(SLEEP_TIME); + } + + return (pid != INVALID_PID); +} + + +pid_t IPCTestHelper::GetTestAppPid(int appId) +{ + ZLOGE(LABEL, "GetTestAppPid appId=%d", appId); + int pid = INVALID_PID; + std::string appName = GetTestAppName(appId); + if (appName.empty()) { + return INVALID_PID; + } + + auto it = testPids_.find(appName); + if (it != testPids_.end()) { + pid = it->second; + } else { + pid = GetPidByName(appName); + } + + ZLOGE(LABEL, "GetTestAppPid return pid=%d", pid); + return pid; +} + +pid_t IPCTestHelper::GetPid() +{ + pid_t pid = getpid(); + ZLOGI(LABEL, "return pid=%{public}d", pid); + return pid; +} + +uid_t IPCTestHelper::GetUid() +{ + uid_t uid = getuid(); + ZLOGI(LABEL, "return uid=%{public}d", uid); + return uid; +} + +long IPCTestHelper::GetCurrentTimeMs() +{ + struct timeval tv; + gettimeofday(&tv, nullptr); + return tv.tv_sec * SECOND_TO_MS + tv.tv_usec / SECOND_TO_MS; +} +} // namespace OHOS diff --git a/ipc/test/auxiliary/native/src/main_client.cpp b/ipc/test/auxiliary/native/src/main_client.cpp new file mode 100755 index 00000000..2d6c845b --- /dev/null +++ b/ipc/test/auxiliary/native/src/main_client.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 +#include +#include +#include +#include +#include +#include "ipc_debug.h" +#include "ipc_skeleton.h" +#include "test_service_command.h" +#include "test_service_client.h" +#include "test_service_skeleton.h" +#include "if_system_ability_manager.h" +#include "log_tags.h" + +using namespace OHOS; +using namespace OHOS::HiviewDFX; +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCTestClient" }; + +std::vector GetArgvOptions(int argc, char **argv) +{ + std::vector argvOptions; + for (int i = 1; i < argc; i++) { + argvOptions.emplace_back(std::string(argv[i])); + } + return argvOptions; +} + +int main(int argc, char *argv[]) +{ + int result = 0; + TestCommand commandId = TestCommand::TEST_CMD_SYNC_TRANS; + if (argc > 1) { + commandId = { atoi(argv[1]) }; + } else { + ZLOGE(LABEL, "unknown command"); + } + std::vector argvOptions; + argvOptions = GetArgvOptions(argc, argv); + std::unique_ptr testClient = std::make_unique(); + if (testClient->ConnectService()) { + return -1; + } + + ZLOGE(LABEL, "commandId= : %{public}d", commandId); + switch (commandId) { + case TestCommand::TEST_CMD_SYNC_TRANS: + testClient->StartSyncTransaction(); + break; + case TestCommand::TEST_CMD_ASYNC_TRANS: { + testClient->StartAsyncTransaction(); + break; + } + case TestCommand::TEST_CMD_PING_SERVICE: { + testClient->StartPingService(); + break; + } + case TestCommand::TEST_CMD_GET_FOO_SERVICE: { + testClient->StartGetFooService(); + break; + } + case TestCommand::TEST_CMD_TRANS_FILE_DESC: { + testClient->StartTestFileDescriptor(); + break; + } + case TestCommand::TEST_CMD_LOOP_TRANSACTION: { + constexpr int maxTestCount = 1000; + testClient->StartLoopTest(maxTestCount); + break; + } + case TestCommand::TEST_CMD_DUMP_SERVICE: { + testClient->StartDumpService(); + break; + } + case TestCommand::TEST_CMD_ASYNC_DUMP_SERVICE: { + testClient->StartAsyncDumpService(); + break; + } + default: + ZLOGI(LABEL, "main arg error"); + break; + } + + ZLOGE(LABEL, "get from service: %{public}d", result); + IPCSkeleton::JoinWorkThread(); + return 0; +} diff --git a/ipc/test/auxiliary/native/src/main_server.cpp b/ipc/test/auxiliary/native/src/main_server.cpp new file mode 100755 index 00000000..1f2800ac --- /dev/null +++ b/ipc/test/auxiliary/native/src/main_server.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ipc_debug.h" +#include "ipc_skeleton.h" +#include "test_service.h" +#include "log_tags.h" + +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +[[maybe_unused]]static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCTestServer" }; + +int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) +{ + TestService::Instantiate(); + ZLOGI(LABEL, "call StartThreadPool"); + IPCSkeleton::JoinWorkThread(); +} diff --git a/ipc/test/auxiliary/native/src/ohos_rpc_test_testhelper.cpp b/ipc/test/auxiliary/native/src/ohos_rpc_test_testhelper.cpp new file mode 100755 index 00000000..110453da --- /dev/null +++ b/ipc/test/auxiliary/native/src/ohos_rpc_test_testhelper.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "ohos_rpc_test_testhelper.h" +#include +#include "ipc_debug.h" +#include "jni_helper.h" +#include "ipc_test_helper.h" +#include "log_tags.h" + +using namespace OHOS; +using namespace OHOS::HiviewDFX; +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCTestHelperJNI" }; + +static bool g_isTestHelperMethodRegistered = false; +static struct ParcelDesc { + jclass klass; + jfieldID fieldNativeInstance; +} g_jTestHelper; + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeNewInstance + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_ohos_rpc_test_TestHelper_nativeNewInstance( + JNIEnv *env, jclass classz) +{ + IPCTestHelper *helper = new IPCTestHelper(); + return (jlong)helper; +} + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeFreeInstance + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_ohos_rpc_test_TestHelper_nativeFreeInstance( + JNIEnv *env, jobject object, jlong instance) +{ + IPCTestHelper *nativeHolder = reinterpret_cast(instance); + delete nativeHolder; +} + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativePrepareTestSuite + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativePrepareTestSuite( + JNIEnv *env, jobject object) +{ + IPCTestHelper *helper = reinterpret_cast( + env->GetLongField(object, g_jTestHelper.fieldNativeInstance)); + + if (helper != nullptr) { + return (jboolean)helper->PrepareTestSuite(); + } + + return JNI_FALSE; +} + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeTearDownTestSuite + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeTearDownTestSuite( + JNIEnv *env, jobject object) +{ + IPCTestHelper *helper = reinterpret_cast( + env->GetLongField(object, g_jTestHelper.fieldNativeInstance)); + + if (helper != nullptr) { + return (jboolean)helper->TearDownTestSuite(); + } + + return JNI_FALSE; +} + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeStartTestServer + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeStartTestApp( + JNIEnv *env, jobject object, jint appId, jint commandId) +{ + IPCTestHelper *helper = reinterpret_cast( + env->GetLongField(object, g_jTestHelper.fieldNativeInstance)); + + if (helper == nullptr) { + return JNI_FALSE; + } + + return (jboolean)helper->StartTestApp(appId, commandId); +} + +/* + * Class: ohos_rpc_test_TestHelper + * Method: StopTestApp + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeStopTestApp( + JNIEnv *env, jobject object, jlong appId) +{ + IPCTestHelper *helper = reinterpret_cast( + env->GetLongField(object, g_jTestHelper.fieldNativeInstance)); + + if (helper != nullptr) { + return (jboolean)helper->StopTestApp(appId); + } + + return JNI_FALSE; +} + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeGetTestServerPid + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_ohos_rpc_test_TestHelper_nativeGetTestAppPid( + JNIEnv *env, jobject object, jint appId) +{ + jint pid = 0; + IPCTestHelper *helper = reinterpret_cast( + env->GetLongField(object, g_jTestHelper.fieldNativeInstance)); + + if (helper != nullptr) { + pid = (jint)helper->GetTestAppPid(appId); + } + + ZLOGI(LABEL, "nativeGetTestAppPid:%d", pid); + return pid; +} + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeGetUid + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_ohos_rpc_test_TestHelper_nativeGetUid( + JNIEnv *env, jobject object) +{ + ZLOGE(LABEL, "Java_ohos_rpc_test_TestHelper_nativeGetUid"); + + jint uid = 0; + IPCTestHelper *helper = reinterpret_cast( + env->GetLongField(object, g_jTestHelper.fieldNativeInstance)); + + if (helper != nullptr) { + uid = static_cast(helper->GetUid()); + } + + return uid; +} + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeGetPid + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_ohos_rpc_test_TestHelper_nativeGetPid( + JNIEnv *env, jobject object) +{ + jint pid = 0; + IPCTestHelper *helper = reinterpret_cast( + env->GetLongField(object, g_jTestHelper.fieldNativeInstance)); + + if (helper != nullptr) { + pid = static_cast(helper->GetPid()); + } + + return pid; +} + +/* + * Class: ohos.rpc.test.TestHelper + * Method: nativeStartExecutable + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeStartExecutable( + JNIEnv *env, jobject object, jstring string, jint length) +{ + IPCTestHelper *helper = reinterpret_cast( + env->GetLongField(object, g_jTestHelper.fieldNativeInstance)); + + const char *utfString = env->GetStringUTFChars(string, 0); + + if (utfString != nullptr) { + std::string exectubeFile = std::string(utfString, length); + ZLOGI(LABEL, "StartExecutable:%s", exectubeFile.c_str()); + helper->StartExecutable(exectubeFile); + env->ReleaseStringUTFChars(string, utfString); + return JNI_TRUE; + } + + return JNI_FALSE; +} + +/* + * Class: ohos.rpc.test.TestHelper + * Method: nativeStopExecutable + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeStopExecutable( + JNIEnv *env, jobject object, jstring string, jint length) +{ + IPCTestHelper *helper = reinterpret_cast( + env->GetLongField(object, g_jTestHelper.fieldNativeInstance)); + + const char *utfString = env->GetStringUTFChars(string, 0); + + if (utfString != nullptr) { + std::string exectubeFile = std::string(utfString, length); + ZLOGI(LABEL, "StopExecutable:%s", exectubeFile.c_str()); + helper->StopExecutable(exectubeFile); + env->ReleaseStringUTFChars(string, utfString); + return JNI_TRUE; + } + + return JNI_FALSE; +} + +/* + * Class: ohos_rpc_test_TestHelper + * Method: nativeRunCommand + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_ohos_rpc_test_TestHelper_nativeRunCommand( + JNIEnv *env, jobject object, jstring string, jint length) +{ + const char *utfString = env->GetStringUTFChars(string, 0); + + if (utfString != nullptr) { + std::string shellCommand = std::string(utfString, length); + ZLOGI(LABEL, "StartExecutable:%s", shellCommand.c_str()); + system(shellCommand.c_str()); + env->ReleaseStringUTFChars(string, utfString); + return JNI_TRUE; + } + + return JNI_FALSE; +} + +int JTestHelpertRegisterNativeMethods(JNIEnv *env) +{ + jclass clazz; + clazz = env->FindClass("ohos/rpc/test/TestHelper"); + if (clazz == nullptr) { + ZLOGI(LABEL, "Could not find class:TestHelper"); + return -1; + } + + g_jTestHelper.klass = (jclass)env->NewGlobalRef(clazz); + g_jTestHelper.fieldNativeInstance = env->GetFieldID(clazz, "mNativeInstance", "J"); + + if (g_jTestHelper.fieldNativeInstance == nullptr) { + ZLOGE(LABEL, "TestHelper get field mNativeInstance failed"); + return -1; + } + + ZLOGI(LABEL, "TestHelper Register Native Methods success\n"); + return 0; +} + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + if (vm == nullptr) { + return -1; + } + if (g_isTestHelperMethodRegistered) { + return JNI_VERSION_1_4; + } + + JNIEnv *env = nullptr; + + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { + return -1; + } + + if (JTestHelpertRegisterNativeMethods(env) < 0) { + return -1; + } + + ZLOGI(LABEL, "JNI_OnLoad success\n"); + g_isTestHelperMethodRegistered = true; + return JNI_VERSION_1_4; +} diff --git a/ipc/test/auxiliary/native/src/test_service.cpp b/ipc/test/auxiliary/native/src/test_service.cpp new file mode 100755 index 00000000..de6f6970 --- /dev/null +++ b/ipc/test/auxiliary/native/src/test_service.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "test_service.h" +#include +#include +#include "ipc_skeleton.h" +#include "ipc_debug.h" +#include "string_ex.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS { +using namespace OHOS::HiviewDFX; + +static int Reverse(int x) +{ + int result = 0; + int decimal = 10; // decimal value. + + while (x != 0) { + result = result * decimal + x % decimal; + x = x / decimal; + } + + return result; +} + +int TestService::Instantiate() +{ + ZLOGI(LABEL, "%{public}s call in", __func__); + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (saMgr == nullptr) { + ZLOGE(LABEL, "%{public}s:fail to get Registry", __func__); + return -ENODEV; + } + + sptr newInstance = new TestService(); +#ifdef IPCSERVERTESTEXTRA + int result = saMgr->AddSystemAbility(IPC_EXTRA_TEST_SERVICE, newInstance); + ZLOGI(LABEL, "%{public}s: IPC_EXTRA_TEST_SERVICE result = %{public}d", __func__, result); +#else + int result = saMgr->AddSystemAbility(IPC_TEST_SERVICE, newInstance); + ZLOGI(LABEL, "%{public}s: IPC_TEST_SERVICE result = %{public}d", __func__, result); +#endif + + ZLOGI(LABEL, "TestService: strong = %d", newInstance->GetSptrRefCount()); + return result; +} + +TestService::TestService() : testFd_(INVALID_FD) +{ +} + +TestService::~TestService() +{ + if (testFd_ != INVALID_FD) { + close(testFd_); + } +} + +int TestService::TestSyncTransaction(int data, int &rep, int delayTime) +{ + rep = Reverse(data); + + if (delayTime > 0) { + sleep(delayTime); + } + + ZLOGE(LABEL, "TestServiceStub:read from client data = %{public}d", data); + return ERR_NONE; +} + +int TestService::TestAsyncTransaction(int data, int timeout) +{ + ZLOGE(LABEL, "TestServiceStub:read from client data = %{public}d", data); + + if (timeout > 0) { + sleep(timeout); + } + + return Reverse(data); +} + +int TestService::TestAsyncCallbackTrans(int data, int &reply, int timeout) +{ + if (timeout > 0) { + timeout = 0; + } + + return Reverse(data); +} + +int TestService::TestZtraceTransaction(std::string &send, std::string &receive, int len) +{ + receive = send; + transform(receive.begin(), receive.end(), receive.begin(), ::tolower); + return 0; +} +int TestService::TestPingService(const std::u16string &serviceName) +{ + std::u16string localServiceName = GetObjectDescriptor(); + if (localServiceName.compare(serviceName) != 0) { + ZLOGE(LABEL, "local name is ""%s, passing is %s", + Str16ToStr8(localServiceName).c_str(), Str16ToStr8(serviceName).c_str()); + return -1; + } + + return 0; +} + +sptr TestService::TestGetFooService() +{ + return new FooStub(); +} + +int TestService::TestGetFileDescriptor() +{ + if (testFd_ != INVALID_FD) { + close(testFd_); + } + + testFd_ = open("/data/test/test.txt", + O_RDWR | O_APPEND | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); + + if (testFd_ == INVALID_FD) { + ZLOGE(LABEL, "%s(%d):open failed.", __func__, __LINE__); + return !INVALID_FD; + } + + ssize_t writeLen = write(testFd_, "Sever write!\n", strlen("Sever write!\n")); + if (writeLen < 0) { + ZLOGE(LABEL, "%s(%d): server write file failed.", __func__, __LINE__); + close(testFd_); + return INVALID_FD; + } else { + ZLOGI(LABEL, "%s(%d): server write file success.", __func__, __LINE__); + } + + return testFd_; +} + +int TestService::TestStringTransaction(const std::string &data) +{ + return data.size(); +} + +void TestService::TestDumpService() +{ + // use for proxy only. +} + +void TestService::TestAsyncDumpService() +{ + // use for proxy only. +} + +int TestService::TestRawDataTransaction(int length, int &reply) +{ + return 0; +} + +int TestService::TestRawDataReply(int length) +{ + return 0; +} + +int TestService::TestCallingUidPid() +{ + return 0; +} + +int TestService::TestFlushAsyncCalls(int count, int length) +{ + return 0; +} + +int TestService::TestMultipleProcesses(int data, int &rep, int delayTime) +{ + return 0; +} + +int TestService::Dump(int fd, const std::vector &args) +{ + ssize_t writeCount = 0; + if (fd > 0) { + std::u16string argsParam = args.front(); + std::string context; + context.append(Str16ToStr8(argsParam)); + context.append(1, '\r'); + writeCount = write(fd, context.data(), context.size()); + } + + return writeCount > 0 ? ERR_NONE : ERR_TRANSACTION_FAILED; +} + +std::u16string TestService::TestAshmem(sptr ashmem, int32_t contentSize) +{ + return u""; +} + +int TestService::TestNestingSend(int sendCode, int &replyCode) +{ + return 0; +} +} // namespace OHOS diff --git a/ipc/test/auxiliary/native/src/test_service_client.cpp b/ipc/test/auxiliary/native/src/test_service_client.cpp new file mode 100755 index 00000000..158aa0e2 --- /dev/null +++ b/ipc/test/auxiliary/native/src/test_service_client.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "test_service_client.h" +#include +#include +#include "ipc_debug.h" +#include "ipc_skeleton.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS { +int TestServiceClient::ConnectService() +{ + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (saMgr == nullptr) { + ZLOGE(LABEL, "get registry fail"); + return -1; + } + + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + + if (object != nullptr) { + ZLOGE(LABEL, "Got test Service object"); + sptr death(new TestDeathRecipient()); + object->AddDeathRecipient(death.GetRefPtr()); + testService_ = iface_cast(object); + } + + if (testService_ == nullptr) { + ZLOGE(LABEL, "Could not find Test Service!"); + return -1; + } + + return 0; +} + +void TestServiceClient::StartSyncTransaction() +{ + if (testService_ != nullptr) { + ZLOGI(LABEL, "StartSyncTransaction"); + [[maybe_unused]] int result = 0; + testService_->TestSyncTransaction(2019, result); + } +} + +void TestServiceClient::StartSyncDelayReply() +{ + if (testService_ != nullptr) { + ZLOGI(LABEL, "StartSyncDelayReply"); + [[maybe_unused]] int result = 0; + testService_->TestSyncTransaction(2019, result, 2); + } +} + +void TestServiceClient::StartAsyncTransaction() +{ + if (testService_ != nullptr) { + ZLOGI(LABEL, "StartAsyncTransaction"); + [[maybe_unused]] int result = 0; + testService_->TestAsyncTransaction(2019, result); + } +} + +void TestServiceClient::StartPingService() +{ + if (testService_ != nullptr) { + ZLOGI(LABEL, "StartPingService"); + const std::u16string descriptor = ITestService::GetDescriptor(); + testService_->TestPingService(descriptor); + } +} + +void TestServiceClient::StartGetFooService() +{ + if (testService_ != nullptr) { + ZLOGI(LABEL, "StartGetFooService"); + sptr foo = testService_->TestGetFooService(); + if (foo == nullptr) { + ZLOGI(LABEL, "Fail to get foo service"); + } + } +} + +void TestServiceClient::StartDumpService() +{ + if (testService_ != nullptr) { + ZLOGI(LABEL, "StartDumpService"); + testService_->TestDumpService(); + } +} + +void TestServiceClient::StartAsyncDumpService() +{ + if (testService_ != nullptr) { + ZLOGI(LABEL, "StartAsyncDumpService"); + testService_->TestAsyncDumpService(); + } +} + +void TestServiceClient::StartTestFileDescriptor() +{ + if (testService_ != nullptr) { + ZLOGI(LABEL, "StartTestFileDescriptor"); + int fd = testService_->TestGetFileDescriptor(); + if (fd != INVALID_FD) { + if (write(fd, "client write!\n", strlen("client write!\n")) < 0) { + ZLOGE(LABEL, "write fd error"); + } + close(fd); + } + } +} + +int TestServiceClient::StartLoopTest(int maxCount) +{ + if (testService_ != nullptr) { + ZLOGI(LABEL, "StartLoopTest"); + int count = 0; + std::string testString; + // start loop test, test times is 1000 + for (count = 0; count < maxCount; count++) { + testString += "0123456789abcdefghijklmnopqrstuvwxyz~!@#$%^&*()_+{}?/[]<>-='|~"; + testService_->TestStringTransaction(testString); + } + return count; + } + return 0; +} +} // namespace OHOS diff --git a/ipc/test/auxiliary/native/src/test_service_skeleton.cpp b/ipc/test/auxiliary/native/src/test_service_skeleton.cpp new file mode 100755 index 00000000..d6d5e553 --- /dev/null +++ b/ipc/test/auxiliary/native/src/test_service_skeleton.cpp @@ -0,0 +1,686 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "test_service_skeleton.h" +#include +#include +#include +#include +#include "ipc_debug.h" +#include "string_ex.h" +#include "iremote_proxy.h" +#include "ipc_skeleton.h" +#include "ipc_file_descriptor.h" +#include "ipc_test_helper.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS { +using namespace OHOS::HiviewDFX; + +TestServiceProxy::TestServiceProxy(const sptr &impl) + : IRemoteProxy(impl) +{ +} + +int TestServiceProxy::TestSyncTransaction(int data, int &reply, int delayTime) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + ZLOGI(LABEL, "send to server data = %{public}d", data); + if (data > 0) { + dataParcel.WriteInt32(data); + dataParcel.WriteInt32(delayTime); + } + error = Remote()->SendRequest(TRANS_ID_SYNC_TRANSACTION, dataParcel, replyParcel, option); + reply = replyParcel.ReadInt32(); + ZLOGI(LABEL, "get result from server data = %{public}d", reply); + return error; +} + +int TestServiceProxy::TestAsyncTransaction(int data, int timeout) +{ + MessageOption option = { MessageOption::TF_ASYNC }; + MessageParcel dataParcel, replyParcel; + ZLOGI(LABEL, "%{public}s:in, data = %{public}d", __func__, data); + dataParcel.WriteInt32(data); + dataParcel.WriteInt32(timeout); + dataParcel.WriteBool(false); + return Remote()->SendRequest(TRANS_ID_ASYNC_TRANSACTION, dataParcel, replyParcel, option); +} + +int TestServiceProxy::TestAsyncCallbackTrans(int data, int &reply, int timeout) +{ + int error; + MessageOption option = { MessageOption::TF_ASYNC }; + MessageParcel dataParcel, replyParcel; + ZLOGI(LABEL, "%{public}s:in, data = %{public}d", __func__, data); + dataParcel.WriteInt32(data); + dataParcel.WriteInt32(timeout); + dataParcel.WriteBool(true); + sptr fooCallback = new FooStub(); + dataParcel.WriteRemoteObject(fooCallback->AsObject()); + error = Remote()->SendRequest(TRANS_ID_ASYNC_TRANSACTION, dataParcel, replyParcel, option); + reply = fooCallback->WaitForAsyncReply(timeout); + + FooStub::CleanDecTimes(); + fooCallback = nullptr; + if (FooStub::GetDecTimes() != 1) { + error = ERR_TRANSACTION_FAILED; + } + return error; +} + +int TestServiceProxy::TestZtraceTransaction(std::string &send, std::string &reply, int len) +{ + int error; + MessageParcel dataParcel, replyParcel; + MessageOption option; + + dataParcel.WriteInt32(len); + dataParcel.WriteString(send); + error = Remote()->SendRequest(TRANS_ID_ZTRACE_TRANSACTION, dataParcel, replyParcel, option); + reply = replyParcel.ReadString(); + + return error; +} + +int TestServiceProxy::TestPingService(const std::u16string &serviceName) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + ZLOGI(LABEL, "PingService"); + dataParcel.WriteString16(serviceName); + error = Remote()->SendRequest(TRANS_ID_PING_SERVICE, dataParcel, replyParcel, option); + int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1; + ZLOGI(LABEL, "PingService result = %d", result); + return result; +} + +sptr TestServiceProxy::TestGetFooService() +{ + MessageOption option; + MessageParcel dataParcel, replyParcel; + Remote()->SendRequest(TRANS_ID_GET_FOO_SERVICE, dataParcel, replyParcel, option); + auto rep = replyParcel.ReadRemoteObject(); + if (rep == nullptr) { + ZLOGE(LABEL, "null foo service"); + return nullptr; + } + return iface_cast(rep); +} + +int TestServiceProxy::TestGetFileDescriptor() +{ + MessageOption option; + MessageParcel dataParcel, replyParcel; + sptr desc; + option.SetFlags(MessageOption::TF_ACCEPT_FDS); + Remote()->SendRequest(TRANS_ID_TRANSACT_FILE_DESC, dataParcel, replyParcel, option); + int fd = replyParcel.ReadFileDescriptor(); + return fd; +} + +int TestServiceProxy::TestStringTransaction(const std::string &data) +{ + MessageOption option; + MessageParcel dataParcel, replyParcel; + dataParcel.WriteString(data); + Remote()->SendRequest(TRANS_ID_STRING_TRANSACTION, dataParcel, replyParcel, option); + int testSize = replyParcel.ReadInt32(); + return testSize; +} + +void TestServiceProxy::TestDumpService() +{ + ZLOGI(LABEL, "call StartDumpService"); + int fd = open("/data/test/dump.txt", + O_RDWR | O_APPEND | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd != INVALID_FD) { + ZLOGI(LABEL, "Start Dump Service"); + std::vector args; + args.push_back(u"DumpTest"); + Remote()->Dump(fd, args); + close(fd); + } +} + +void TestServiceProxy::TestAsyncDumpService() +{ + int fd = open("/data/test/nonblockingDump.txt", + O_RDWR | O_APPEND | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd == INVALID_FD) { + return; + } + + ZLOGI(LABEL, "Start Async Dump Service"); + std::vector args; + args.push_back(u"NonblockingDumpTest"); + MessageParcel data, reply; + MessageOption option {MessageOption::TF_ASYNC}; + data.WriteFileDescriptor(fd); + data.WriteString16Vector(args); + (void)Remote()->SendRequest(DUMP_TRANSACTION, data, reply, option); + close(fd); +} + +int TestServiceProxy::TestRawDataTransaction(int length, int &reply) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + ZLOGE(LABEL, "send to server data length = %{public}d", length); + if (length <= 1 || static_cast(length) > dataParcel.GetRawDataCapacity()) { + ZLOGE(LABEL, "length should > 1, length is %{public}d", length); + return -1; + } + unsigned char *buffer = new (std::nothrow) unsigned char[length]; + if (buffer == nullptr) { + ZLOGE(LABEL, "new buffer failed of length = %{public}d", length); + return -1; + } + buffer[0] = 'a'; + buffer[length - 1] = 'z'; + + dataParcel.WriteInt32(length); + dataParcel.WriteRawData(buffer, length); + dataParcel.WriteInt32(length); + error = Remote()->SendRequest(TRANS_ID_RAWDATA_TRANSACTION, dataParcel, replyParcel, option); + reply = replyParcel.ReadInt32(); + ZLOGE(LABEL, "get result from server data = %{public}d", reply); + delete [] buffer; + return error; +} + +int TestServiceProxy::TestRawDataReply(int length) +{ + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (length <= 1 || static_cast(length) > dataParcel.GetRawDataCapacity()) { + ZLOGE(LABEL, "length should > 1, length is %{public}d", length); + return ERR_INVALID_STATE; + } + + if (!dataParcel.WriteInt32(length)) { + ZLOGE(LABEL, "fail to write parcel"); + return ERR_INVALID_STATE; + } + + int ret = Remote()->SendRequest(TRANS_ID_RAWDATA_REPLY, dataParcel, replyParcel, option); + if (ret != ERR_NONE) { + ZLOGE(LABEL, "ret = %{public}d", ret); + return ret; + } + + if (replyParcel.ReadInt32() != length) { + ZLOGE(LABEL, "reply false data"); + return ERR_INVALID_DATA; + } + + if (!replyParcel.ContainFileDescriptors()) { + ZLOGE(LABEL, "replied raw data is less than 32k"); + } + + const char *buffer = nullptr; + if ((buffer = reinterpret_cast(replyParcel.ReadRawData(length))) == nullptr) { + ZLOGE(LABEL, "read raw data failed, length = %{public}d", length); + return ERR_INVALID_DATA; + } + if (buffer[0] != 'a' || buffer[length - 1] != 'z') { + ZLOGE(LABEL, "buffer error, length = %{public}d", length); + return ERR_INVALID_DATA; + } + + if (replyParcel.ReadInt32() != length) { + ZLOGE(LABEL, "read raw data after failed, length = %{public}d", length); + return ERR_INVALID_DATA; + } + + return ERR_NONE; +} + + +int TestServiceProxy::TestCallingUidPid() +{ + MessageOption option; + MessageParcel dataParcel, replyParcel; + int ret = Remote()->SendRequest(TRANS_ID_CALLING_UID_PID, dataParcel, replyParcel, option); + if (ret != ERR_NONE) { + ZLOGE(LABEL, "ret = %{public}d", ret); + return ret; + } + + int uid = replyParcel.ReadInt32(); + int pid = replyParcel.ReadInt32(); + + IPCTestHelper helper; + int actualUid = helper.GetUid(); + int actualPid = helper.GetPid(); + ZLOGI(LABEL, "uid = %{public}d, pid = %{public}d, actualUid = %{public}d, actualPid = %{public}d", + uid, pid, actualUid, actualPid); + + if (uid == actualUid && pid == actualPid) { + return 0; + } + return -1; +} + +int TestServiceProxy::TestFlushAsyncCalls(int count, int length) +{ + int ret; + MessageOption option = { MessageOption::TF_ASYNC }; + MessageParcel dataParcel, replyParcel; + std::u16string legalData(length, 'a'); + dataParcel.WriteString16(legalData); + for (int i = 0; i < count; i++) { + ret = Remote()->SendRequest(TRANS_ID_FLUSH_ASYNC_CALLS, dataParcel, replyParcel, option); + if (ret != ERR_NONE) { + ZLOGE(LABEL, "fail to send request when count = %{public}d, ret = %{public}d", count, ret); + return ret; + } + } + + ret = IPCSkeleton::FlushCommands(this->AsObject()); + return ret; +} + +int TestServiceProxy::TestMultipleProcesses(int data, int &rep, int delayTime) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + ZLOGI(LABEL, "send to server data = %{public}d", data); + if (data > 0) { + dataParcel.WriteInt32(data); + dataParcel.WriteInt32(delayTime); + } + error = Remote()->SendRequest(TRANS_ID_MULTIPLE_PROCESSES, dataParcel, replyParcel, option); + rep = replyParcel.ReadInt32(); + error += replyParcel.ReadInt32(); + return error; +} + +std::u16string TestServiceProxy::TestAshmem(sptr ashmem, int32_t contentSize) +{ + if (ashmem == nullptr || contentSize <= 0) { + return u""; + } + + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(contentSize) || !dataParcel.WriteAshmem(ashmem)) { + return u""; + } + + int error = Remote()->SendRequest(TRANS_ID_ASHMEM, dataParcel, replyParcel, option); + if (error != ERR_NONE) { + return u""; + } + + int32_t readContentSize = replyParcel.ReadInt32(); + if (readContentSize <= 0) { + return u""; + } + + sptr ashmem2 = replyParcel.ReadAshmem(); + if (ashmem2 == nullptr || !ashmem2->MapReadAndWriteAshmem()) { + return u""; + } + + const void *content = ashmem2->ReadFromAshmem(readContentSize, 0); + if (content == nullptr) { + ashmem2->UnmapAshmem(); + return u""; + } + + auto readContent = static_cast(content); + std::string str(readContent, readContentSize); + + ashmem2->UnmapAshmem(); + ashmem2->CloseAshmem(); + return Str8ToStr16(str); +} + +int TestServiceProxy::TestNestingSend(int sendCode, int &replyCode) +{ + ZLOGW(LABEL, "%{public}s", __func__); + MessageOption option; + MessageParcel dataParcel, replyParcel; + sptr foo = new FooStub(); + sptr sendFoo = foo->AsObject(); + sendFoo->SetBehavior(Parcelable::BehaviorFlag::HOLD_OBJECT); + if (!dataParcel.WriteRemoteObject(sendFoo) || !dataParcel.WriteInt32(sendCode)) { + ZLOGE(LABEL, "%{public}s: fail to write data", __func__); + return -1; + } + int error = Remote()->SendRequest(TRANS_ID_NESTING_SEND, dataParcel, replyParcel, option); + replyCode = replyParcel.ReadInt32(); + ZLOGW(LABEL, "%{public}s: outer = %{public}d, inner = %{public}d", __func__, error, replyCode); + return error; +} + +int TestServiceStub::OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int ret = 0; + int result = 0; + ZLOGI(LABEL, "OnRemoteRequest, cmd = %{public}d, flags= %{public}d", code, option.GetFlags()); + switch (code) { + case TRANS_ID_SYNC_TRANSACTION: { + int32_t reqData = data.ReadInt32(); + int32_t delayTime = data.ReadInt32(); + ret = TestSyncTransaction(reqData, result, delayTime); + reply.WriteInt32(result); + break; + } + case TRANS_ID_ASYNC_TRANSACTION: { + int32_t reqData = data.ReadInt32(); + int timeout = data.ReadInt32(); + bool acquireResult = data.ReadBool(); + if (acquireResult) { + sptr fooProxy = iface_cast(data.ReadRemoteObject()); + if (fooProxy != nullptr) { + TestAsyncCallbackTrans(reqData, result, timeout); + fooProxy->SendAsyncReply(result); + } + } else { + result = TestAsyncTransaction(reqData, timeout); + } + break; + } + case TRANS_ID_PING_SERVICE: { + std::u16string serviceName = data.ReadString16(); + result = TestPingService(serviceName); + ZLOGI(LABEL, "%s:PingService: result=%d", __func__, result); + reply.WriteInt32(result); + break; + } + case TRANS_ID_GET_FOO_SERVICE: { + sptr fooService = TestGetFooService(); + sptr object = fooService->AsObject(); + object->SetBehavior(Parcelable::BehaviorFlag::HOLD_OBJECT); + reply.WriteRemoteObject(object); + break; + } + case TRANS_ID_TRANSACT_FILE_DESC: { + int desc = TestGetFileDescriptor(); + reply.WriteFileDescriptor(desc); + close(desc); + break; + } + case TRANS_ID_STRING_TRANSACTION: { + const std::string testString = data.ReadString(); + int testSize = TestStringTransaction(testString); + reply.WriteInt32(testSize); + reply.WriteString(testString); + break; + } + case TRANS_ID_ZTRACE_TRANSACTION: { + int32_t len = data.ReadInt32(); + if (len < 0) { + ZLOGE(LABEL, "%s:get len failed, len = %d", __func__, len); + break; + } + std::string recvString; + std::string replyString(len, 0); + recvString = data.ReadString(); + ret = TestZtraceTransaction(recvString, replyString, len); + if (!ret) { + reply.WriteString(replyString); + } + break; + } + case TRANS_ID_RAWDATA_TRANSACTION: { + ret = TransferRawData(data, reply); + break; + } + case TRANS_ID_RAWDATA_REPLY: { + ret = ReplyRawData(data, reply); + break; + } + case TRANS_ID_CALLING_UID_PID: { + reply.WriteInt32(IPCSkeleton::GetCallingUid()); + reply.WriteInt32(IPCSkeleton::GetCallingPid()); + + ZLOGE(LABEL, "calling before reset uid = %{public}d, pid = %{public}d", + IPCSkeleton::GetCallingUid(), IPCSkeleton::GetCallingPid()); + std::string token = IPCSkeleton::ResetCallingIdentity(); + + ZLOGE(LABEL, "calling before set uid = %{public}d, pid = %{public}d", + IPCSkeleton::GetCallingUid(), IPCSkeleton::GetCallingPid()); + if (!IPCSkeleton::SetCallingIdentity(token)) { + ZLOGE(LABEL, "Set Calling Identity fail"); + break; + } + + ZLOGE(LABEL, "calling after set uid = %{public}d, pid = %{public}d", + IPCSkeleton::GetCallingUid(), IPCSkeleton::GetCallingPid()); + break; + } + case TRANS_ID_FLUSH_ASYNC_CALLS: { + (void)data.ReadString16(); + break; + } + case TRANS_ID_MULTIPLE_PROCESSES: { + TransferToNextProcess(data, reply); + break; + } + case TRANS_ID_ASHMEM: { + ReadAshmem(data, reply); + break; + } + case TRANS_ID_NESTING_SEND: { + sptr object = data.ReadRemoteObject(); + sptr foo = iface_cast(object); + int innerResult = foo->TestNestingSend(data.ReadInt32()); + reply.WriteInt32(innerResult); + break; + } + default: + ret = IPCObjectStub::OnRemoteRequest(code, data, reply, option); + break; + } + + return ret; +} + +int TestServiceStub::TransferRawData(MessageParcel &data, MessageParcel &reply) +{ + ZLOGI(LABEL, "enter transfer raw data"); + int length = data.ReadInt32(); + if (length <= 1) { + ZLOGE(LABEL, "%{public}s: length should > 1, length is %{public}d", __func__, length); + if (!reply.WriteInt32(length)) { + ZLOGE(LABEL, "fail to write parcel"); + } + return ERR_INVALID_DATA; + } + + if (!data.ContainFileDescriptors()) { + ZLOGE(LABEL, "sent raw data is less than 32k"); + } + + const char *buffer = nullptr; + if ((buffer = reinterpret_cast(data.ReadRawData(length))) == nullptr) { + ZLOGE(LABEL, "%{public}s:read raw data failed, length = %{public}d", __func__, length); + if (reply.WriteInt32(0)) { + ZLOGE(LABEL, "fail to write parcel"); + } + return ERR_INVALID_DATA; + } + if (buffer[0] != 'a' || buffer[length - 1] != 'z') { + ZLOGE(LABEL, "%{public}s:buffer error, length = %{public}d", __func__, length); + if (reply.WriteInt32(0)) { + ZLOGE(LABEL, "fail to write parcel"); + } + return ERR_INVALID_DATA; + } + if (data.ReadInt32() != length) { + ZLOGE(LABEL, "%{public}s:read raw data after failed, length = %{public}d", __func__, length); + if (!reply.WriteInt32(0)) { + ZLOGE(LABEL, "fail to write parcel"); + } + return ERR_INVALID_DATA; + } + if (!reply.WriteInt32(length)) { + ZLOGE(LABEL, "fail to write parcel"); + return ERR_INVALID_DATA; + } + return ERR_NONE; +} + +int TestServiceStub::ReplyRawData(MessageParcel &data, MessageParcel &reply) +{ + ZLOGI(LABEL, "enter reply raw data"); + int length = data.ReadInt32(); + if (length <= 1) { + ZLOGE(LABEL, "%{public}s: length should > 1, length is %{public}d", __func__, length); + if (!reply.WriteInt32(length)) { + ZLOGE(LABEL, "fail to write parcel"); + } + return ERR_INVALID_DATA; + } + + unsigned char *buffer = new (std::nothrow) unsigned char[length]; + if (buffer == nullptr) { + ZLOGE(LABEL, "new buffer failed of length = %{public}d", length); + return ERR_INVALID_STATE; + } + buffer[0] = 'a'; + buffer[length - 1] = 'z'; + if (!reply.WriteInt32(length) || + !reply.WriteRawData(buffer, length) || + !reply.WriteInt32(length)) { + ZLOGE(LABEL, "fail to write parcel"); + delete [] buffer; + return ERR_INVALID_STATE; + } + + delete [] buffer; + return ERR_NONE; +} + +void TestServiceStub::TransferToNextProcess(MessageParcel &data, MessageParcel &reply) +{ + int32_t reqData = data.ReadInt32(); + int32_t delayTime = data.ReadInt32(); + int result; + int ret = TestSyncTransaction(reqData, result, delayTime); + reply.WriteInt32(result); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (saMgr == nullptr) { + reply.WriteInt32(ERR_TRANSACTION_FAILED); + return; + } + + sptr object = saMgr->GetSystemAbility(IPC_EXTRA_TEST_SERVICE); + if (object == nullptr) { + reply.WriteInt32(ERR_TRANSACTION_FAILED); + return; + } + + sptr testService = iface_cast(object); + if (testService == nullptr) { + reply.WriteInt32(ERR_TRANSACTION_FAILED); + return; + } + + ret += testService->TestSyncTransaction(reqData, result, delayTime); + ret += testService->TestAsyncCallbackTrans(reqData, result, delayTime); + if (ret != 0) { + reply.WriteInt32(ERR_TRANSACTION_FAILED); + return; + } + + reply.WriteInt32(ERR_NONE); +} + +void TestServiceStub::ReadAshmem(MessageParcel &data, MessageParcel &reply) +{ + int32_t contentSize = data.ReadInt32(); + if (contentSize < 0) { + reply.WriteInt32(-1); + return; + } + + sptr ashmem = data.ReadAshmem(); + if (ashmem == nullptr) { + reply.WriteInt32(-1); + return; + } + + int32_t ashmemSize = ashmem->GetAshmemSize(); + if (ashmemSize < contentSize || !ashmem->MapReadOnlyAshmem()) { + reply.WriteInt32(-1); + return; + } + + const void *content = ashmem->ReadFromAshmem(contentSize, 0); + if (content == nullptr) { + reply.WriteInt32(-1); + ashmem->UnmapAshmem(); + ashmem->CloseAshmem(); + return; + } + + auto pt = static_cast(content); + std::string str(pt, contentSize); + ashmem->UnmapAshmem(); + ashmem->CloseAshmem(); + + std::string name = "ashmem2"; + sptr ashmem2 = Ashmem::CreateAshmem(name.c_str(), ashmemSize); + if (ashmem2 == nullptr || !ashmem2->MapReadAndWriteAshmem() || + !ashmem2->WriteToAshmem(str.c_str(), contentSize, 0)) { + reply.WriteInt32(-1); + if (ashmem2 != nullptr) { + ashmem2->UnmapAshmem(); + ashmem2->CloseAshmem(); + } + return; + } + + reply.WriteInt32(contentSize); + reply.WriteAshmem(ashmem2); + + ashmem2->UnmapAshmem(); + ashmem2->CloseAshmem(); +} + +bool TestDeathRecipient::gotDeathRecipient_ = false; + +bool TestDeathRecipient::GotDeathRecipient() +{ + return gotDeathRecipient_; +} + +void TestDeathRecipient::OnRemoteDied(const wptr &remote) +{ + gotDeathRecipient_ = true; + ZLOGI(LABEL, "recv death notice"); +} + +TestDeathRecipient::TestDeathRecipient() +{ +} + +TestDeathRecipient::~TestDeathRecipient() +{ +} +} // namespace OHOS diff --git a/ipc/test/moduletest/native/BUILD.gn b/ipc/test/moduletest/native/BUILD.gn new file mode 100755 index 00000000..109612c3 --- /dev/null +++ b/ipc/test/moduletest/native/BUILD.gn @@ -0,0 +1,51 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +IPC_TEST_ROOT = "//foundation/communication/ipc/ipc/test" +MODULE_OUTPUT_PATH = "ipc" + +ohos_moduletest("IPCNativeFrameworksTest") { + module_out_path = MODULE_OUTPUT_PATH + include_dirs = [ "//utils/system/safwk/native/include" ] + sources = [ "./common/ipc_core_module_test.cpp" ] + configs = [ + "$SUBSYSTEM_DIR:ipc_util_config", + "$IPC_TEST_ROOT:ipc_test_config", + ] + deps = [ + "$IPC_TEST_ROOT/auxiliary/native:TestAssistance", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + resource_config_file = + "//foundation/communication/ipc/test/resource/ipc/ohos_test.xml" +} + +############################################################################### +group("moduletest") { + testonly = true + deps = [ ":IPCNativeFrameworksTest" ] +} + +############################################################################### + diff --git a/ipc/test/moduletest/native/common/ipc_core_module_test.cpp b/ipc/test/moduletest/native/common/ipc_core_module_test.cpp new file mode 100755 index 00000000..1f27d87d --- /dev/null +++ b/ipc/test/moduletest/native/common/ipc_core_module_test.cpp @@ -0,0 +1,740 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 +#include +#include +#include +#include "ipc_debug.h" +#include "ipc_skeleton.h" +#include "ipc_test_helper.h" +#include "test_service.h" +#include "test_service_skeleton.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "ipc_object_proxy.h" + +#include "log_tags.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +class IPCNativeFrameworkTest : public testing::Test { +public: + static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCModuleTest" }; + static constexpr int saId = 3202; + static constexpr int checkTimes = 1000; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + static void RegisterThread(); + const int threadNums = 10; + const int flushTimes = 10; + const int repeatTimes = 30000; + // Test transferring big data with different sizes + const int rawData10K = 10 * 1024; + const int rawData10M = 10 * 1024 * 1024; + const int rawData100M = 100 * 1024 * 1024; + const int rawData33K = 33 * 1024; + const int errorCode = 2020; + std::string ashmemName = "AshmemIpc"; + std::string ashmemString = "HelloWorld2020"; +private: + static inline IPCTestHelper *g_globalHelper = { nullptr }; +}; + +void IPCNativeFrameworkTest::SetUpTestCase() +{ + if (g_globalHelper == nullptr) { + g_globalHelper = new IPCTestHelper(); + bool res = g_globalHelper->PrepareTestSuite(); + ASSERT_TRUE(res); + } +} + +void IPCNativeFrameworkTest::TearDownTestCase() +{ + if (g_globalHelper != nullptr) { + bool res = g_globalHelper->TearDownTestSuite(); + ASSERT_TRUE(res); + delete g_globalHelper; + g_globalHelper = nullptr; + } +} + +void IPCNativeFrameworkTest::RegisterThread() +{ + auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(samgr != nullptr); + for (int i = 0; i < checkTimes; i++) { + auto remoteObject = samgr->CheckSystemAbility(saId); + if (remoteObject != nullptr) { + ASSERT_TRUE(remoteObject->IsProxyObject()); + } else { + ZLOGI(LABEL, "proxy is null"); + } + } +} + +/** + * @tc.name: function_test_001 + * @tc.desc: Test get system ability. + * @tc.type: FUNC + * @tc.require: SR000CQDI2 SR000CQDI7 AR000CQDI8 + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_001, TestSize.Level1) +{ + ZLOGI(LABEL, "Start IPC Testcase001"); + // service instance + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + EXPECT_TRUE(saMgr != NULL); +} + +/** + * @tc.name: function_test_002 + * @tc.desc: Test basic ipc communication. + * @tc.type: FUNC + * @tc.require: SR000CQDI2 SR000CQDI7 AR000CQDI8 + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_002, TestSize.Level1) +{ + ZLOGI(LABEL, "Start IPC Testcase002"); + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != NULL); + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + sptr death(new TestDeathRecipient()); + int result = object->AddDeathRecipient(death.GetRefPtr()); + + ZLOGI(LABEL, "AddDeathRecipient result = %d", result); + EXPECT_TRUE(result != ERR_INVALID_OPERATION); + + sptr testService = iface_cast(object); + + int reply = 0; + result = testService->TestSyncTransaction(2019, reply); + ZLOGI(LABEL, "testService ReverseInt result = %d, get reply = %d", result, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + res = helper.StopTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + EXPECT_EQ(TestDeathRecipient::GotDeathRecipient(), true); + + bool returnResult = object->RemoveDeathRecipient(death.GetRefPtr()); + EXPECT_EQ(returnResult, false); +} + +/** + * @tc.name: function_test_003 + * @tc.desc: Test basic ipc communication in one process and Link Death. + * @tc.type: FUNC + * @tc.require: AR000CT7RU AR000CQDI9 + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_003, TestSize.Level1) +{ + ZLOGI(LABEL, "Start IPC Testcase003"); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + ISystemAbilityManager *smp = saMgr.GetRefPtr(); + ASSERT_TRUE(smp != nullptr); + + sptr service = new TestService(); + int result = smp->AddSystemAbility(IPC_EXTRA_TEST_SERVICE, service); + + ZLOGI(LABEL, "Testcase003: Add TestService result=%d", result); + EXPECT_EQ(result, 0); + + // test get service and call it + ASSERT_TRUE(smp != nullptr); + + sptr object = smp->GetSystemAbility(IPC_EXTRA_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + ZLOGI(LABEL, "Testcase003: Get test.service OK"); + + sptr death(new TestDeathRecipient()); + bool ret = object->AddDeathRecipient(death.GetRefPtr()); + + ZLOGI(LABEL, "Testcase003: AddDeathRecipient result = %d", result); + EXPECT_TRUE(ret == false); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + int reply = 0; + result = testService->TestSyncTransaction(0, reply); + ZLOGI(LABEL, "Testcase003: ReverseInt result = %d, get reply = %d", result, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 0); +} + +/** + * @tc.name: function_test_004 + * @tc.desc: Test sync ipc communication call and ipc thread poll. + * @tc.type: FUNC + * @tc.require: SR000CT84J AR000CQDI3 AR000CQDI6 + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_004, TestSize.Level1) +{ + ZLOGI(LABEL, "Start IPC Testcase004"); + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + ZLOGI(LABEL, "get test.service OK"); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + long startTime = helper.GetCurrentTimeMs(); + int reply = 0; + int result = 0; + result = testService->TestSyncTransaction(2019, reply, 2); + ZLOGI(LABEL, "testService ReverseInt result = %d, get reply = %d", result, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + long finishTime = helper.GetCurrentTimeMs(); + ZLOGI(LABEL, "startTime = %ld, finishTime = %ld", startTime, finishTime); + EXPECT_GE(finishTime - startTime, 2000); +} + +/** + * @tc.name: function_test_005 + * @tc.desc: Test async ipc communication call. + * @tc.type: FUNC + * @tc.require: SR000CT84J AR000CQDI4 AR000CT84K + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_005, TestSize.Level1) +{ + ZLOGI(LABEL, "Start IPC Testcase005"); + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + ZLOGI(LABEL, "get test.service OK"); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + long startTime = helper.GetCurrentTimeMs(); + int result = 0; + result = testService->TestAsyncTransaction(2019, 0); + ZLOGI(LABEL, "testService ReverseInt result = %d, get reply = %d", result, reply); + EXPECT_EQ(result, 0); + long finishTime = helper.GetCurrentTimeMs(); + ZLOGI(LABEL, "startTime = %ld, finishTime = %ld", startTime, finishTime); + EXPECT_LT(finishTime - startTime, 100); +} + +/** + * @tc.name: function_test_006 + * @tc.desc: Test for GetFileDescriptor. + * @tc.type: FUNC + * @tc.require: AR000CQDI5 + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_006, TestSize.Level1) +{ + ZLOGI(LABEL, "Start IPC Testcase006"); + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + ZLOGI(LABEL, "get test.service OK"); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + for (int i = 0; i < repeatTimes; i++) { + int fd = testService->TestGetFileDescriptor(); + ZLOGW(LABEL, "Got fd:%{public}d!\n", fd); + ASSERT_TRUE(fd > 0); + + ssize_t len = write(fd, "client write!\n", strlen("client write!\n")); + EXPECT_GT(len, 0); + + close(fd); + } +} + +/** + * @tc.name: function_test_007 + * @tc.desc: Get the Strong reference of Service. + * @tc.type: FUNC + * @tc.require: SR000CRQIJ AR000CT7RS AR000CT7RT + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_007, TestSize.Level1) +{ + ZLOGI(LABEL, "Start IPC Testcase007"); + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + ZLOGI(LABEL, "get test.service OK"); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + sptr fooService = testService->TestGetFooService(); + EXPECT_TRUE(fooService != nullptr); + + std::string fooName = fooService->GetFooName(); + EXPECT_EQ(fooName, "ReallFoo"); +} + +/** + * @tc.name: function_test_008 + * @tc.desc: Test Dump Interface. + * @tc.type: FUNC + * @tc.require: AR000CRQIK AR000CPNKQ + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_008, TestSize.Level1) +{ + ZLOGI(LABEL, "Start IPC Testcase008"); + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + + ASSERT_TRUE(saMgr != nullptr); + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + ZLOGI(LABEL, "get test.service OK"); + + int fd = open("/data/test/dump.txt", + O_RDWR | O_APPEND | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); + + ASSERT_TRUE(fd > 0); + + std::vector args; + args.push_back(u"test"); + + int result = object->Dump(fd, args); + close(fd); + EXPECT_TRUE(result == ERR_NONE); +} + +/** + * @tc.name: function_test_009 + * @tc.desc: Test ipc communication big raw data call. + * @tc.type: FUNC + * @tc.require: SR000D48A6 AR000D4CFM + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_009, TestSize.Level1) +{ + ZLOGE(LABEL, "Start IPC Testcase009"); + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + ZLOGE(LABEL, "get test.service OK"); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + long startTime = helper.GetCurrentTimeMs(); + int reply = 0; + // TestRawDataTransaction cannot transfer data less than 2. + int result = testService->TestRawDataTransaction(rawData10M, reply); + ZLOGE(LABEL, "testService ReverseInt result = %{public}d, get reply = %{public}d", result, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, rawData10M); + + result = testService->TestRawDataTransaction(rawData100M, reply); + ZLOGE(LABEL, "testService ReverseInt result = %{public}d, get reply = %{public}d", result, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, rawData100M); + + long finishTime = helper.GetCurrentTimeMs(); + ZLOGE(LABEL, "startTime = %{public}ld, finishTime = %{public}ld", startTime, finishTime); + EXPECT_LT(finishTime - startTime, 2000); +} + +/** + * @tc.name: function_test_010 + * @tc.desc: Test ipc reply big raw data. + * @tc.type: FUNC + * @tc.require: SR000CQSAB AR000DAPPO + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_010, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + long startTime = helper.GetCurrentTimeMs(); + // TestRawDataTransaction cannot transfer data less than 2. + int result = testService->TestRawDataReply(rawData10M); + ZLOGE(LABEL, "testService ReverseInt result = %{public}d", result); + EXPECT_EQ(result, 0); + + result = testService->TestRawDataReply(rawData100M); + ZLOGE(LABEL, "testService ReverseInt result = %{public}d", result); + EXPECT_EQ(result, 0); + + long finishTime = helper.GetCurrentTimeMs(); + ZLOGE(LABEL, "startTime = %{public}ld, finishTime = %{public}ld", startTime, finishTime); + EXPECT_LT(finishTime - startTime, 2000); +} + +/** + * @tc.name: function_test_011 + * @tc.desc: Test ipc get calling uid and pid. + * @tc.type: FUNC + * @tc.require: SR000CQSAB AR000DAPPO + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_011, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + long startTime = helper.GetCurrentTimeMs(); + int result = testService->TestCallingUidPid(); + EXPECT_EQ(result, 0); + + long finishTime = helper.GetCurrentTimeMs(); + EXPECT_LT(finishTime - startTime, 2000); +} + +/** + * @tc.name: function_test_016 + * @tc.desc: Test ipc flush asynchronous calls. + * @tc.type: FUNC + * @tc.require: AR000DPV5I + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_016, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + long startTime = helper.GetCurrentTimeMs(); + int result = testService->TestFlushAsyncCalls(flushTimes, rawData10K); + EXPECT_EQ(result, 0); + + long finishTime = helper.GetCurrentTimeMs(); + EXPECT_LT(finishTime - startTime, 2000); +} + +/** + * @tc.name: function_test_017 + * @tc.desc: Test ipc proxy gets descriptor. + * @tc.type: FUNC + * @tc.require: AR000DPV5I + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_017, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + auto proxy = reinterpret_cast(object.GetRefPtr()); + std::u16string descriptor = proxy->GetInterfaceDescriptor(); + ASSERT_TRUE(IsSameTextStr(Str16ToStr8(descriptor), "test.ipc.ITestService")); +} + +/** + * @tc.name: function_test_018 + * @tc.desc: Test ashmem reads and writes. + * @tc.type: FUNC + * @tc.require: SR000ER7PG + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_018, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + for (int i = 0; i < repeatTimes; i++) { + sptr ashmem = Ashmem::CreateAshmem(ashmemName.c_str(), rawData10K); + ASSERT_TRUE(ashmem != nullptr); + bool ret = ashmem->MapReadAndWriteAshmem(); + ASSERT_TRUE(ret); + ret = ashmem->WriteToAshmem(ashmemString.c_str(), strlen(ashmemString.c_str()), 0); + ASSERT_TRUE(ret); + + long startTime = helper.GetCurrentTimeMs(); + std::u16string readStr = testService->TestAshmem(ashmem, strlen(ashmemString.c_str())); + + long finishTime = helper.GetCurrentTimeMs(); + EXPECT_EQ(readStr, Str8ToStr16(ashmemString)); + EXPECT_LT(finishTime - startTime, 2000); + ashmem->UnmapAshmem(); + ashmem->CloseAshmem(); + } +} + +#ifndef CONFIG_STANDARD_SYSTEM +/** + * @tc.name: function_test_019 + * @tc.desc: Test raw data reads and writes. + * @tc.type: FUNC + * @tc.require: SR000ER7PG + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_019, TestSize.Level1) +{ + for (int i = 0; i < repeatTimes; i++) { + unsigned char *buffer = new (std::nothrow) unsigned char[rawData10M]; + if (buffer == nullptr) { + ZLOGE(LABEL, "new buffer failed of length = %{public}d", rawData10M); + return; + } + buffer[0] = 'a'; + buffer[rawData10M - 1] = 'z'; + + MessageParcel dataParcel; + dataParcel.WriteRawData(buffer, rawData10M); + dataParcel.RewindRead(0); + const char *buffer2 = nullptr; + buffer2 = reinterpret_cast(dataParcel.ReadRawData(rawData10M)); + ASSERT_TRUE(buffer2 != nullptr); + EXPECT_EQ(buffer2[0], 'a'); + EXPECT_EQ(buffer2[rawData10M - 1], 'z'); + delete[] buffer; + } +} +#endif + +/** + * @tc.name: function_test_020 + * @tc.desc: Test ipc communication big raw data call. + * @tc.type: FUNC + * @tc.require: SR000ER7PG + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_020, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + ZLOGE(LABEL, "get test.service OK"); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + int reply = 0; + for (int i = 0; i < repeatTimes; i++) { + int result = testService->TestRawDataTransaction(rawData33K, reply); + ZLOGE(LABEL, "testService ReverseInt result = %{public}d, get reply = %{public}d", result, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, rawData33K); + } +} + +/** + * @tc.name: function_test_021 + * @tc.desc: Test ipc communication big raw data call. + * @tc.type: FUNC + * @tc.require: SR000ER7PG + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_021, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + // test get service and call it + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + ZLOGE(LABEL, "get test.service OK"); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + for (int i = 0; i < repeatTimes; i++) { + int result = testService->TestRawDataReply(rawData33K); + ZLOGE(LABEL, "testService ReverseInt result = %{public}d", result); + EXPECT_EQ(result, 0); + } +} + +/** + * @tc.name: function_test_022 + * @tc.desc: Test marshalling and unmarshalling Ashmem. + * @tc.type: FUNC + * @tc.require: SR000ER7PG + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_022, TestSize.Level1) +{ + for (int i = 0; i < repeatTimes; i++) { + sptr ashmem = Ashmem::CreateAshmem(ashmemName.c_str(), 1024); + ASSERT_TRUE(ashmem != nullptr); + bool ret = ashmem->MapReadAndWriteAshmem(); + ASSERT_TRUE(ret); + ret = ashmem->WriteToAshmem(ashmemString.c_str(), strlen(ashmemString.c_str()), 0); + ASSERT_TRUE(ret); + + MessageParcel parcel; + parcel.WriteAshmem(ashmem); + parcel.RewindRead(0); + + sptr ashmem2 = parcel.ReadAshmem(); + ASSERT_TRUE(ashmem2 != nullptr); + ASSERT_TRUE(ashmem2->MapReadOnlyAshmem()); + const void *content = ashmem2->ReadFromAshmem(strlen(ashmemString.c_str()), 0); + ASSERT_TRUE(content != nullptr); + + auto readContent = static_cast(content); + std::string str(readContent, strlen(ashmemString.c_str())); + EXPECT_EQ(str, ashmemString); + + ashmem->UnmapAshmem(); + ashmem->CloseAshmem(); + ashmem2->UnmapAshmem(); + ashmem2->CloseAshmem(); + } +} + +/** + * @tc.name: function_test_023 + * @tc.desc: Test sending again after error. + * @tc.type: FUNC + * @tc.require: AR000CQDI5 + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_023, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + int reply = 0; + int ret = testService->TestNestingSend(errorCode, reply); + EXPECT_EQ(ret, 0); + EXPECT_EQ(reply, errorCode); +} + +/** + * @tc.name: function_test_024 + * @tc.desc: Test obtaining the same proxy by multiple threads concurrently. + * @tc.type: FUNC + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_024, TestSize.Level1) +{ + std::vector> threads; + for (int i = 0; i < threadNums; i++) { + threads.emplace_back(std::make_unique(&IPCNativeFrameworkTest::RegisterThread)); + } + + ZLOGI(LABEL, "Sleep IPC Testcase024"); + sleep(10); + std::cout << "ok\n" << std::endl; + for (auto &thread : threads) { + thread->join(); + } +} diff --git a/ohos.build b/ohos.build new file mode 100755 index 00000000..07b476a4 --- /dev/null +++ b/ohos.build @@ -0,0 +1,73 @@ +{ + "subsystem": "communication", + "parts": { + "ipc": { + "module_list": [ + "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "//foundation/communication/ipc/interfaces/innerkits/ipc_single:ipc_single", + "//foundation/communication/ipc/interfaces/innerkits/libdbinder:libdbinder" + ], + "inner_kits": [ + { + "type": "so", + "name": "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "header": { + "header_files": [ + "ipc_types.h", + "ipc_skeleton.h", + "iremote_object.h", + "iremote_proxy.h", + "iremote_stub.h", + "message_parcel.h", + "message_option.h", + "iremote_broker.h", + "ipc_object_proxy.h", + "ipc_object_stub.h", + "peer_holder.h", + "ipc_file_descriptor.h", + "jni_help.h" + ], + "header_base": "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include" + } + }, + { + "type": "so", + "name": "//foundation/communication/ipc/interfaces/innerkits/ipc_single:ipc_single", + "header": { + "header_files": [ + "ipc_types.h", + "ipc_skeleton.h", + "iremote_object.h", + "iremote_proxy.h", + "iremote_stub.h", + "message_parcel.h", + "message_option.h", + "iremote_broker.h", + "ipc_object_proxy.h", + "ipc_object_stub.h", + "peer_holder.h", + "ipc_file_descriptor.h", + "jni_help.h" + ], + "header_base": "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include" + } + }, + { + "type": "so", + "name": "//foundation/communication/ipc/interfaces/innerkits/libdbinder:libdbinder", + "header": { + "header_files": [ + "dbinder_service.h", + "dbinder_service_stub.h" + ], + "header_base": "//foundation/communication/ipc/interfaces/innerkits/libdbinder/include" + } + } + ], + "test_list": [ + "//foundation/communication/ipc/ipc/test:moduletest", + "//foundation/communication/ipc/ipc/native/test:unittest" + ] + } + } +} diff --git a/services/dbinder/dbinder_service/include/dbinder_death_recipient.h b/services/dbinder/dbinder_service/include/dbinder_death_recipient.h new file mode 100755 index 00000000..55383af0 --- /dev/null +++ b/services/dbinder/dbinder_service/include/dbinder_death_recipient.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_DBINDER_DEATH_RECIPIENT_H +#define OHOS_IPC_DBINDER_DEATH_RECIPIENT_H + +#include "iremote_object.h" + +namespace OHOS { +class DbinderDeathRecipient : public IRemoteObject::DeathRecipient { +public: + virtual void OnRemoteDied(const wptr &remote); + DbinderDeathRecipient() = default; + virtual ~DbinderDeathRecipient() = default; +}; +} // namespace OHOS +#endif // OHOS_IPC_DBINDER_DEATH_RECIPIENT_H diff --git a/services/dbinder/dbinder_service/include/dbinder_log.h b/services/dbinder/dbinder_service/include/dbinder_log.h new file mode 100755 index 00000000..7a27e286 --- /dev/null +++ b/services/dbinder/dbinder_service/include/dbinder_log.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_SERVICES_DBINDER_DBINDRR_LOG_H +#define OHOS_IPC_SERVICES_DBINDER_DBINDRR_LOG_H + +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif +#include "hilog/log.h" +#include "log_tags.h" + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, OHOS::LOG_ID_RPC, LOG_TAG }; + +#define DBINDER_LOGF(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGW(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Warn(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGD(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Debug(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + + +#endif // OHOS_IPC_SERVICES_DBINDER_DBINDRR_LOG_H \ No newline at end of file diff --git a/services/dbinder/dbinder_service/include/dbinder_remote_listener.h b/services/dbinder/dbinder_service/include/dbinder_remote_listener.h new file mode 100755 index 00000000..317568cd --- /dev/null +++ b/services/dbinder/dbinder_service/include/dbinder_remote_listener.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_DBINDER_REMOTE_LISTENER_H +#define OHOS_IPC_DBINDER_REMOTE_LISTENER_H + +#include +#include +#include + +#include "dbinder_service.h" +#include "ISessionService.h" +#include "Session.h" +#include "ISessionListener.h" + +using Communication::SoftBus::ISessionListener; +using Communication::SoftBus::ISessionService; +using Communication::SoftBus::Session; + +namespace OHOS { +class DBinderRemoteListener : public ISessionListener { +public: + DBinderRemoteListener(const sptr &dBinderService); + ~DBinderRemoteListener(); + int OnSessionOpened(std::shared_ptr session) override; + void OnSessionClosed(std::shared_ptr session) override; + void OnMessageReceived(std::shared_ptr session, const char *data, ssize_t len) override {}; + void OnBytesReceived(std::shared_ptr session, const char *data, ssize_t len) override; + bool OnDataAvailable(std::shared_ptr session, uint32_t status) override + { + return true; + }; + + bool SendDataToRemote(const std::string &deviceId, const struct DHandleEntryTxRx *msg); + bool StartListener(); + bool StopListener(); + bool CloseDatabusSession(const std::string &deviceId); + +private: + std::shared_ptr OpenSoftbusSession(const std::string &deviceId); + + const std::string OWN_SESSION_NAME = "DBinderService"; + const std::string PEER_SESSION_NAME = "DBinderService"; + static constexpr int PACKET_SIZE = 64 * 1024; + static constexpr int SEND_MSG_TIMEOUT_MS = 200; + + DISALLOW_COPY_AND_MOVE(DBinderRemoteListener); + std::mutex busManagerMutex_; + std::shared_ptr softbusManager_; + sptr dBinderService_; +}; +} // namespace OHOS +#endif // OHOS_IPC_DBINDER_REMOTE_LISTENER_H diff --git a/services/dbinder/dbinder_service/include/dbinder_sa_death_recipient.h b/services/dbinder/dbinder_service/include/dbinder_sa_death_recipient.h new file mode 100755 index 00000000..a0946dc9 --- /dev/null +++ b/services/dbinder/dbinder_service/include/dbinder_sa_death_recipient.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_DBINDER_SA_DEATH_RECIPIENT_H +#define OHOS_IPC_DBINDER_SA_DEATH_RECIPIENT_H + +#include "iremote_object.h" + +namespace OHOS { +class DbinderSaDeathRecipient : public IRemoteObject::DeathRecipient { +public: + virtual void OnRemoteDied(const wptr &remote); + DbinderSaDeathRecipient(binder_uintptr_t binderObject); + virtual ~DbinderSaDeathRecipient() = default; +private: + binder_uintptr_t binderObject_; +}; +} // namespace OHOS +#endif // OHOS_IPC_DBINDER_SA_DEATH_RECIPIENT_H diff --git a/services/dbinder/dbinder_service/src/dbinder_death_recipient.cpp b/services/dbinder/dbinder_service/src/dbinder_death_recipient.cpp new file mode 100755 index 00000000..386705d6 --- /dev/null +++ b/services/dbinder/dbinder_service/src/dbinder_death_recipient.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_death_recipient.h" +#include "dbinder_service.h" +#include "dbinder_log.h" +#include "log_tags.h" + +namespace OHOS { +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "DbinderDeathRecipient" }; +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +void DbinderDeathRecipient::OnRemoteDied(const wptr &remote) +{ + if (remote == nullptr) { + DBINDER_LOGE("remote object is null"); + return; + } + + sptr object = remote.promote(); + IPCObjectProxy *callbackProxy = reinterpret_cast(object.GetRefPtr()); + + sptr dBinderService = DBinderService::GetInstance(); + if (dBinderService == nullptr) { + DBINDER_LOGE("dBinderService is null"); + return; + } + + sptr death = dBinderService->QueryDeathRecipient(object); + if (death != nullptr) { + // Continue to clear subsequent data + callbackProxy->RemoveDeathRecipient(death); + } + + if (!dBinderService->DetachDeathRecipient(object)) { + DBINDER_LOGE("detaching death recipient is failed"); + return; + } + + if (!dBinderService->DetachCallbackProxy(object)) { + DBINDER_LOGE("detaching callback proxy is failed"); + return; + } +} +} // namespace OHOS diff --git a/services/dbinder/dbinder_service/src/dbinder_sa_death_recipient.cpp b/services/dbinder/dbinder_service/src/dbinder_sa_death_recipient.cpp new file mode 100755 index 00000000..028964a2 --- /dev/null +++ b/services/dbinder/dbinder_service/src/dbinder_sa_death_recipient.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_sa_death_recipient.h" +#include "dbinder_service.h" +#include "dbinder_log.h" +#include "log_tags.h" + +namespace OHOS { +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "DbinderSaDeathRecipient" }; +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +DbinderSaDeathRecipient::DbinderSaDeathRecipient(binder_uintptr_t binderObject) : binderObject_(binderObject) +{ +} + +void DbinderSaDeathRecipient::OnRemoteDied(const wptr &remote) +{ + if (remote == nullptr) { + DBINDER_LOGE("remote object is null"); + return; + } + + sptr object = remote.promote(); + IPCObjectProxy *proxy = reinterpret_cast(object.GetRefPtr()); + + sptr dBinderService = DBinderService::GetInstance(); + if (dBinderService == nullptr) { + DBINDER_LOGE("dBinderService is null"); + return; + } + + (void)dBinderService->DetachBusNameObject(proxy); + (void)dBinderService->DetachProxyObject(binderObject_); +} +} // namespace OHOS diff --git a/services/dbinder/dbinder_service/src/dbinder_service.cpp b/services/dbinder/dbinder_service/src/dbinder_service.cpp new file mode 100755 index 00000000..761959f8 --- /dev/null +++ b/services/dbinder/dbinder_service/src/dbinder_service.cpp @@ -0,0 +1,941 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_service.h" + +#include +#include +#include +#include +#include "securec.h" +#include "string_ex.h" +#include "iservice_registry.h" +#include "ipc_skeleton.h" +#include "ipc_thread_skeleton.h" + +#include "dbinder_log.h" +#include "dbinder_service_stub.h" +#include "dbinder_remote_listener.h" +#include "if_system_ability_manager.h" +#include "dbinder_error_code.h" +#include "softbus_bus_center.h" +#include "dbinder_sa_death_recipient.h" + +namespace OHOS { +using namespace Communication; + +sptr DBinderService::instance_ = nullptr; +bool DBinderService::mainThreadCreated_ = false; +std::mutex DBinderService::instanceMutex_; +std::shared_ptr DBinderService::remoteListener_ = nullptr; + +DBinderService::DBinderService() +{ + DBINDER_LOGI("create dbinder service"); +} + +DBinderService::~DBinderService() +{ + StopRemoteListener(); + + DBinderStubRegisted_.clear(); + mapRemoteBinderObjects_.clear(); + threadLockInfo_.clear(); + proxyObject_.clear(); + sessionObject_.clear(); + noticeProxy_.clear(); + deathRecipients_.clear(); + busNameObject_.clear(); + + DBINDER_LOGI("dbinder service died"); +} + +std::string DBinderService::GetLocalDeviceID() +{ + std::string pkgName = "dbinderService"; + NodeBasicInfo nodeBasicInfo; + if (GetLocalNodeDeviceInfo(pkgName.c_str(), &nodeBasicInfo) != 0) { + DBINDER_LOGE("Get local node device info failed"); + return ""; + } + std::string networkId(nodeBasicInfo.networkId); + return networkId; +} + +bool DBinderService::StartDBinderService() +{ + if (mainThreadCreated_) { + return true; + } + + bool result = StartRemoteListener(); + if (!result) { + return false; + } + mainThreadCreated_ = true; + + return true; +} + +bool DBinderService::StartRemoteListener() +{ + if (remoteListener_ != nullptr) { + DBINDER_LOGI("remote listener started"); + return true; + } + + remoteListener_ = std::make_shared(GetInstance()); + if (remoteListener_ == nullptr) { + DBINDER_LOGE("failed to create remote listener"); + return false; + } + + if (remoteListener_->StartListener() != true) { + StopRemoteListener(); + return false; + } + + DBINDER_LOGI("start remote listener ok"); + return true; +} + +void DBinderService::StopRemoteListener() +{ + if (remoteListener_ != nullptr) { + remoteListener_->StopListener(); + remoteListener_ = nullptr; + } +} + +std::shared_ptr DBinderService::GetRemoteListener() +{ + if (remoteListener_ == nullptr && !StartRemoteListener()) { + return nullptr; + } + return remoteListener_; +} + +sptr DBinderService::GetInstance() +{ + if (instance_ == nullptr) { + std::lock_guard lockGuard(instanceMutex_); + if (instance_ == nullptr) { + sptr temp = new DBinderService(); + instance_ = temp; + } + } + + return instance_; +} + +uint32_t DBinderService::GetSeqNumber() +{ + std::lock_guard lockGuard(instanceMutex_); + seqNumber_++; // can be overflow + return seqNumber_; +} + +bool DBinderService::IsDeviceIdIllegal(const std::string &deviceID) +{ + if (deviceID.empty() || deviceID.length() > DEVICEID_LENGTH) { + return true; + } + return false; +} + +bool DBinderService::CheckBinderObject(const sptr &stub, binder_uintptr_t binderObject) +{ + if (stub == nullptr) { + return false; + } + + if (stub->GetBinderObject() == binderObject) { + DBINDER_LOGI("found registered stub"); + return true; + } + return false; +} + +bool DBinderService::HasDBinderStub(binder_uintptr_t binderObject) +{ + auto checkStub = [&binderObject, this](const sptr &stub) { + return CheckBinderObject(stub, binderObject); + }; + + std::lock_guard lockGuard(handleEntryMutex_); + auto it = std::find_if(DBinderStubRegisted_.begin(), DBinderStubRegisted_.end(), checkStub); + if (it != DBinderStubRegisted_.end()) { + return true; + } + return false; +} + +bool DBinderService::IsSameStubObject(const sptr &stub, const std::u16string &service, + const std::string &device) +{ + if (stub == nullptr) { + return false; + } + if (IsSameTextStr(stub->GetServiceName(), Str16ToStr8(service)) && IsSameTextStr(stub->GetDeviceID(), device)) { + DBINDER_LOGI("found registered service with name = %s", Str16ToStr8(service).c_str()); + return true; + } + return false; +} +sptr DBinderService::FindDBinderStub(const std::u16string &service, const std::string &device) +{ + auto checkStub = [&service, &device, this](const sptr &stub) { + return IsSameStubObject(stub, service, device); + }; + + std::lock_guard lockGuard(handleEntryMutex_); + auto it = std::find_if(DBinderStubRegisted_.begin(), DBinderStubRegisted_.end(), checkStub); + if (it == DBinderStubRegisted_.end()) { + return nullptr; + } + return (*it); +} + +bool DBinderService::DeleteDBinderStub(const std::u16string &service, const std::string &device) +{ + auto checkStub = [&service, &device, this](const sptr &stub) { + return IsSameStubObject(stub, service, device); + }; + + std::lock_guard lockGuard(handleEntryMutex_); + auto it = std::find_if(DBinderStubRegisted_.begin(), DBinderStubRegisted_.end(), checkStub); + if (it == DBinderStubRegisted_.end()) { + return false; + } + DBinderStubRegisted_.erase(it); + return true; +} + +sptr DBinderService::FindOrNewDBinderStub(const std::u16string &service, const std::string &device, + binder_uintptr_t binderObject) +{ + auto checkStub = [&service, &device, this](const sptr &stub) { + return IsSameStubObject(stub, service, device); + }; + + std::lock_guard lockGuard(handleEntryMutex_); + auto it = std::find_if(DBinderStubRegisted_.begin(), DBinderStubRegisted_.end(), checkStub); + if (it != DBinderStubRegisted_.end()) { + return (*it); + } + + sptr dBinderServiceStub = new DBinderServiceStub(Str16ToStr8(service), device, binderObject); + DBinderStubRegisted_.push_back(dBinderServiceStub); + return dBinderServiceStub; +} + +sptr DBinderService::MakeRemoteBinder(const std::u16string &serviceName, + const std::string &deviceID, binder_uintptr_t binderObject, uint64_t pid) +{ + if (IsDeviceIdIllegal(deviceID) || serviceName.length() == 0 || binderObject == 0) { + DBINDER_LOGE("para is wrong device id length = %zu, service name length = %zu", deviceID.length(), + serviceName.length()); + return nullptr; + } + DBINDER_LOGI("name = %{public}s, deviceID = %{public}s", Str16ToStr8(serviceName).c_str(), + DBinderService::ConvertToSecureDeviceID(deviceID).c_str()); + + sptr dBinderServiceStub = FindOrNewDBinderStub(serviceName, deviceID, binderObject); + if (dBinderServiceStub == nullptr) { + DBINDER_LOGE("fail to find or new service, service name = %{public}s", Str16ToStr8(serviceName).c_str()); + return nullptr; + } + + /* if not found dBinderServiceStub, should send msg to toDeviceID + * to invoker socket thread and add authentication info for create softbus session + */ + int retryTimes = 0; + bool ret = false; + do { + ret = InvokerRemoteDBinder(dBinderServiceStub, GetSeqNumber()); + retryTimes++; + } while (!ret && (retryTimes < RETRY_TIMES)); + + if (!ret) { + DBINDER_LOGE("fail to invoke service, service name = %{public}s", Str16ToStr8(serviceName).c_str()); + /* invoke fail, delete dbinder stub info */ + (void)DeleteDBinderStub(serviceName, deviceID); + (void)DetachSessionObject(reinterpret_cast(dBinderServiceStub.GetRefPtr())); + return nullptr; + } + + return dBinderServiceStub; +} + +bool DBinderService::SendEntryToRemote(const sptr stub, uint32_t seqNumber) +{ + const std::string deviceID = stub->GetDeviceID(); + const std::string localDevID = GetLocalDeviceID(); + if (IsDeviceIdIllegal(deviceID) || IsDeviceIdIllegal(localDevID)) { + DBINDER_LOGE("wrong device ID"); + return false; + } + + std::shared_ptr message = std::make_shared(); + message->head.len = sizeof(DHandleEntryTxRx); + message->head.version = VERSION_NUM; + message->dBinderCode = MESSAGE_AS_INVOKER; + message->transType = GetRemoteTransType(); + message->fromPort = 0; + message->toPort = 0; + message->stubIndex = 0; + message->seqNumber = seqNumber; + message->binderObject = stub->GetBinderObject(); + message->stub = reinterpret_cast(stub.GetRefPtr()); + message->deviceIdInfo.afType = DATABBUS_TYPE; + message->pid = IPCSkeleton::GetCallingPid(); + message->uid = IPCSkeleton::GetCallingUid(); + if (memcpy_s(message->deviceIdInfo.fromDeviceId, DEVICEID_LENGTH, localDevID.data(), localDevID.length()) != 0 || + memcpy_s(message->deviceIdInfo.toDeviceId, DEVICEID_LENGTH, deviceID.data(), deviceID.length()) != 0) { + DBINDER_LOGE("fail to copy memory"); + return false; + } + message->deviceIdInfo.fromDeviceId[localDevID.length()] = '\0'; + message->deviceIdInfo.toDeviceId[deviceID.length()] = '\0'; + + std::shared_ptr remoteListener = GetRemoteListener(); + if (remoteListener == nullptr) { + DBINDER_LOGE("remoteListener is null"); + return false; + } + bool result = remoteListener->SendDataToRemote(deviceID, message.get()); + if (result != true) { + DBINDER_LOGE("send to remote dbinderService failed"); + return false; + } + return true; +} + +bool DBinderService::InvokerRemoteDBinder(const sptr stub, uint32_t seqNumber) +{ + if (stub == nullptr) { + DBINDER_LOGE("stub is nullptr"); + return false; + } + bool result = SendEntryToRemote(stub, seqNumber); + if (!result) { + DBINDER_LOGE("send entry to remote dbinderService fail"); + return false; + } + + /* pend to wait reply */ + std::shared_ptr threadLockInfo = std::make_shared(); + result = AttachThreadLockInfo(seqNumber, threadLockInfo); + if (result != true) { + DBINDER_LOGE("attach lock info fail"); + return false; + } + + std::unique_lock lock(threadLockInfo->mutex); + if (threadLockInfo->condition.wait_for(lock, std::chrono::seconds(WAIT_FOR_REPLY_MAX_SEC), + [&threadLockInfo] { return threadLockInfo->ready; }) == false) { + DBINDER_LOGE("get remote data failed"); + DetachThreadLockInfo(seqNumber); + threadLockInfo->ready = false; + return false; + } + /* if can not find session, means invoke failed or nothing in OnRemoteReplyMessage() */ + auto session = QuerySessionObject(reinterpret_cast(stub.GetRefPtr())); + if (session == nullptr) { + DBINDER_LOGE("client find session is null"); + return false; + } + return true; +} + +sptr DBinderService::FindOrNewProxy(binder_uintptr_t binderObject) +{ + sptr proxy = QueryProxyObject(binderObject); + if (proxy != nullptr) { + DBINDER_LOGI("already have proxy"); + return proxy; + } + /* proxy is null, attempt to get a new proxy */ + std::u16string serviceName = GetRegisterService(binderObject); + if (serviceName.empty()) { + DBINDER_LOGE("service is not registered in this device"); + return nullptr; + } + + DBINDER_LOGI("new proxy serviceName = %s", Str16ToStr8(serviceName).c_str()); + + auto manager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (manager == nullptr) { + DBINDER_LOGE("when new proxy, find samgr fail!"); + return nullptr; + } + + int digitalName = std::atoi(Str16ToStr8(serviceName).c_str()); + proxy = manager->GetSystemAbility(digitalName); + if (proxy != nullptr) { + /* When the stub object dies, you need to delete the corresponding busName information */ + IPCObjectProxy *saProxy = reinterpret_cast(proxy.GetRefPtr()); + sptr death(new DbinderSaDeathRecipient(binderObject)); + if (!saProxy->AddDeathRecipient(death)) { + DBINDER_LOGE("fail to add death recipient"); + return nullptr; + } + bool ret = AttachProxyObject(proxy, binderObject); + if (!ret) { + DBINDER_LOGE("attach proxy object fail"); + return nullptr; + } + } + return proxy; +} +uint16_t DBinderService::AllocFreeSocketPort() +{ + /* alloc port by system */ + return 0; +} + +bool DBinderService::OnRemoteInvokerMessage(const struct DHandleEntryTxRx *message) +{ + sptr proxy = FindOrNewProxy(message->binderObject); + if (proxy == nullptr) { + DBINDER_LOGE("find and new proxy fail"); + return false; + } + IPCObjectProxy *ipcProxy = reinterpret_cast(proxy.GetRefPtr()); + std::shared_ptr replyMessage = std::make_shared(); + if (memcpy_s(replyMessage.get(), sizeof(DHandleEntryTxRx), message, sizeof(DHandleEntryTxRx)) != 0) { + DBINDER_LOGE("fail to copy memory"); + return false; + } + std::string deviceId = replyMessage->deviceIdInfo.fromDeviceId; + + switch (replyMessage->transType) { + case IRemoteObject::DATABUS_TYPE: { + if (!OnRemoteInvokerDataBusMessage(ipcProxy, replyMessage.get(), deviceId, message->pid, message->uid)) { + DBINDER_LOGE("Invoker Databus Message fail"); + return false; + } + break; + } + default: { + DBINDER_LOGE("Invalid Message Type"); + return false; + } + } + std::shared_ptr remoteListener = GetRemoteListener(); + if (remoteListener == nullptr) { + DBINDER_LOGE("remoteListener is null"); + return false; + } + bool ret = remoteListener->SendDataToRemote(deviceId, replyMessage.get()); + if (ret != true) { + DBINDER_LOGE("fail to send data from server DBS to client DBS"); + return false; + } + + return true; +} + +std::string DBinderService::GetDatabusNameByProxy(IPCObjectProxy *proxy) +{ + if (proxy == nullptr) { + DBINDER_LOGE("proxy can not be null"); + return ""; + } + std::string sessionName = QueryBusNameObject(proxy); + if (!sessionName.empty()) { + DBINDER_LOGI("sessionName has been granded"); + return sessionName; + } + sessionName = proxy->GetPidAndUidInfo(); + if (sessionName.empty()) { + DBINDER_LOGE("grand session name failed"); + return ""; + } + return sessionName; +} + +std::string DBinderService::CreateDatabusName(int uid, int pid) +{ + std::shared_ptr softbusManager = ISessionService::GetInstance(); + if (softbusManager == nullptr) { + DBINDER_LOGE("fail to get softbus service"); + return ""; + } + + std::string sessionName = "DBinder" + std::to_string(uid) + std::string("_") + std::to_string(pid); + if (softbusManager->GrantPermission(uid, pid, sessionName) != ERR_NONE) { + DBINDER_LOGE("fail to Grant Permission softbus name"); + return ""; + } + + return sessionName; +} + +bool DBinderService::OnRemoteInvokerDataBusMessage(IPCObjectProxy *proxy, struct DHandleEntryTxRx *replyMessage, + std::string &remoteDeviceId, int pid, int uid) +{ + if (IsDeviceIdIllegal(remoteDeviceId)) { + DBINDER_LOGE("remote device id is error"); + return false; + } + std::string sessionName = GetDatabusNameByProxy(proxy); + if (sessionName.empty()) { + DBINDER_LOGE("get bus name fail"); + return false; + } + + MessageParcel data; + MessageParcel reply; + if (!data.WriteUint16(IRemoteObject::DATABUS_TYPE) || !data.WriteString(GetLocalDeviceID()) || + !data.WriteUint32(pid) || !data.WriteUint32(uid) || !data.WriteString(remoteDeviceId) || + !data.WriteString(sessionName)) { + DBINDER_LOGE("write to parcel fail"); + return false; + } + int err = proxy->InvokeListenThread(data, reply); + if (err != ERR_NONE) { + DBINDER_LOGE("start service listen error = %d", err); + return false; + } + uint64_t stubIndex = reply.ReadUint64(); + std::string serverSessionName = reply.ReadString(); + if (stubIndex == 0 || serverSessionName.empty() || serverSessionName.length() > SERVICENAME_LENGTH) { + DBINDER_LOGE("stubindex or session name invalid"); + return false; + } + + replyMessage->dBinderCode = MESSAGE_AS_REPLY; + replyMessage->stubIndex = stubIndex; + replyMessage->serviceNameLength = serverSessionName.length(); + if (memcpy_s(replyMessage->serviceName, SERVICENAME_LENGTH, serverSessionName.data(), + replyMessage->serviceNameLength) != 0) { + DBINDER_LOGE("fail to copy memory"); + return false; + } + replyMessage->serviceName[replyMessage->serviceNameLength] = '\0'; + + (void)AttachBusNameObject(proxy, serverSessionName); + return true; +} + +std::u16string DBinderService::GetRegisterService(binder_uintptr_t binderObject) +{ + DBINDER_LOGI("get service binderObject"); + std::shared_lock lockGuard(remoteBinderMutex_); + for (auto it = mapRemoteBinderObjects_.begin(); it != mapRemoteBinderObjects_.end(); it++) { + if (it->second == binderObject) { + return it->first; + } + } + + return std::u16string(); +} + +bool DBinderService::RegisterRemoteProxy(std::u16string serviceName, sptr binderObject) +{ + DBINDER_LOGI("register remote proxy, service name = %{public}s", Str16ToStr8(serviceName).c_str()); + + if (serviceName.length() == 0 || binderObject == nullptr) { + DBINDER_LOGE("serviceName.length() = %zu", serviceName.length()); + return false; + } + + binder_uintptr_t binder = (binder_uintptr_t)binderObject.GetRefPtr(); + DBINDER_LOGI("register remote proxy"); + + std::unique_lock lockGuard(remoteBinderMutex_); + + // clear historical remnants, Don't care if it succeeds + (void)mapRemoteBinderObjects_.erase(serviceName); + auto result = mapRemoteBinderObjects_.insert(std::pair(serviceName, binder)); + return result.second; +} + +bool DBinderService::OnRemoteMessageTask(const struct DHandleEntryTxRx *message) +{ + if (message == nullptr) { + DBINDER_LOGE("message is null "); + return false; + } + + bool result = false; + switch (message->dBinderCode) { + case MESSAGE_AS_INVOKER: { + result = OnRemoteInvokerMessage(message); + break; + } + case MESSAGE_AS_REPLY: { + result = OnRemoteReplyMessage(message); + break; + } + default: { + DBINDER_LOGE("ERROR! DbinderCode is wrong value, code =%u", message->dBinderCode); + result = false; + break; + } + } + return result; +} + +bool DBinderService::OnRemoteReplyMessage(const struct DHandleEntryTxRx *replyMessage) +{ + MakeSessionByReplyMessage(replyMessage); + WakeupThreadByStub(replyMessage->seqNumber); + DetachThreadLockInfo(replyMessage->seqNumber); + return true; +} + +void DBinderService::MakeSessionByReplyMessage(const struct DHandleEntryTxRx *replyMessage) +{ + if (HasDBinderStub(replyMessage->binderObject) == false) { + DBINDER_LOGE("invalid stub object"); + return; + } + if (QuerySessionObject(replyMessage->stub) != nullptr) { + DBINDER_LOGI("invoker remote session already, do nothing"); + return; + } + std::shared_ptr session = std::make_shared(); + if (session == nullptr) { + DBINDER_LOGE("new SessionInfo fail"); + return; + } + + if (memcpy_s(&session->deviceIdInfo, sizeof(struct DeviceIdInfo), &replyMessage->deviceIdInfo, + sizeof(struct DeviceIdInfo)) != 0) { + DBINDER_LOGE("fail to copy memory"); + return; + } + session->socketFd = 0; + session->stubIndex = replyMessage->stubIndex; + session->toPort = replyMessage->toPort; + session->fromPort = replyMessage->fromPort; + session->type = replyMessage->transType; + session->serviceName = replyMessage->serviceName; + + if (session->stubIndex == 0) { + DBINDER_LOGE("get stub index == 0, it is invalid"); + return; + } + + if (!AttachSessionObject(session, replyMessage->stub)) { + DBINDER_LOGE("attach SessionInfo fail"); + return; + } +} + +void DBinderService::WakeupThreadByStub(uint32_t seqNumber) +{ + std::shared_ptr threadLockInfo = QueryThreadLockInfo(seqNumber); + if (threadLockInfo == nullptr) { + DBINDER_LOGE("threadLockInfo is not exist"); + return; + } + /* Wake up the client processing thread */ + std::unique_lock lock(threadLockInfo->mutex); + threadLockInfo->ready = true; + threadLockInfo->condition.notify_all(); +} + +void DBinderService::DetachThreadLockInfo(uint32_t seqNumber) +{ + std::lock_guard lock(threadLockMutex_); + threadLockInfo_.erase(seqNumber); +} + +bool DBinderService::AttachThreadLockInfo(uint32_t seqNumber, std::shared_ptr object) +{ + std::lock_guard lock(threadLockMutex_); + auto result = + threadLockInfo_.insert(std::pair>(seqNumber, object)); + + return result.second; +} + +std::shared_ptr DBinderService::QueryThreadLockInfo(uint32_t seqNumber) +{ + std::lock_guard lock(threadLockMutex_); + + auto it = threadLockInfo_.find(seqNumber); + if (it != threadLockInfo_.end()) { + return it->second; + } + return nullptr; +} + + +bool DBinderService::DetachProxyObject(binder_uintptr_t binderObject) +{ + std::unique_lock lock(proxyMutex_); + + return (proxyObject_.erase(binderObject) > 0); +} + +bool DBinderService::AttachProxyObject(sptr object, binder_uintptr_t binderObject) +{ + std::unique_lock lock(proxyMutex_); + + auto result = proxyObject_.insert(std::pair>(binderObject, object)); + return result.second; +} + +sptr DBinderService::QueryProxyObject(binder_uintptr_t binderObject) +{ + std::shared_lock lock(proxyMutex_); + + auto it = proxyObject_.find(binderObject); + if (it != proxyObject_.end()) { + return it->second; + } + return nullptr; +} + +bool DBinderService::DetachSessionObject(binder_uintptr_t stub) +{ + std::unique_lock lock(sessionMutex_); + + return (sessionObject_.erase(stub) > 0); +} + +bool DBinderService::AttachSessionObject(std::shared_ptr object, binder_uintptr_t stub) +{ + std::unique_lock lock(sessionMutex_); + + auto ret = sessionObject_.insert(std::pair>(stub, object)); + + return ret.second; +} + +std::shared_ptr DBinderService::QuerySessionObject(binder_uintptr_t stub) +{ + std::shared_lock lock(sessionMutex_); + + auto it = sessionObject_.find(stub); + if (it != sessionObject_.end()) { + return it->second; + } + return nullptr; +} + +bool DBinderService::DetachBusNameObject(IPCObjectProxy *proxy) +{ + std::unique_lock lock(busNameMutex_); + + return (busNameObject_.erase(proxy) > 0); +} + +bool DBinderService::AttachBusNameObject(IPCObjectProxy *proxy, const std::string &name) +{ + std::unique_lock lock(busNameMutex_); + + auto ret = busNameObject_.insert(std::pair(proxy, name)); + + return ret.second; +} + +std::string DBinderService::QueryBusNameObject(IPCObjectProxy *proxy) +{ + std::shared_lock lock(busNameMutex_); + + auto it = busNameObject_.find(proxy); + if (it != busNameObject_.end()) { + return it->second; + } + return ""; +} + +bool DBinderService::DetachDeathRecipient(sptr object) +{ + std::unique_lock lockGuard(deathRecipientMutex_); + + return (deathRecipients_.erase(object) > 0); +} + +bool DBinderService::AttachDeathRecipient(sptr object, + sptr deathRecipient) +{ + std::unique_lock lockGuard(deathRecipientMutex_); + + auto ret = deathRecipients_.insert( + std::pair, sptr>(object, deathRecipient)); + + return ret.second; +} + +sptr DBinderService::QueryDeathRecipient(sptr object) +{ + std::shared_lock lockGuard(deathRecipientMutex_); + + auto it = deathRecipients_.find(object); + if (it != deathRecipients_.end()) { + return it->second; + } + + return nullptr; +} + + +bool DBinderService::DetachCallbackProxy(sptr object) +{ + std::lock_guard lockGuard(callbackProxyMutex_); + + return (noticeProxy_.erase(object) > 0); +} + +bool DBinderService::AttachCallbackProxy(sptr object, DBinderServiceStub *dbStub) +{ + std::lock_guard lockGuard(callbackProxyMutex_); + + auto result = noticeProxy_.insert(std::pair, DBinderServiceStub *>(object, dbStub)); + + return result.second; +} + +bool DBinderService::NoticeCallbackProxy(sptr dbStub) +{ + bool status = true; + const binder_uintptr_t binderObject = reinterpret_cast(dbStub.GetRefPtr()); + if (!DetachSessionObject(binderObject)) { + DBINDER_LOGE("fail to detach session object"); + status = false; + } + + if (!DeleteDBinderStub(Str8ToStr16(dbStub->GetServiceName()), dbStub->GetDeviceID())) { + DBINDER_LOGE("fail to delete DBinder stub"); + status = false; + } + + ProcessCallbackProxy(dbStub); + + return status; +} + +void DBinderService::ProcessCallbackProxy(sptr dbStub) +{ + std::lock_guard lockGuard(callbackProxyMutex_); + + for (auto it = noticeProxy_.begin(); it != noticeProxy_.end();) { + if (it->second == dbStub.GetRefPtr()) { + IPCObjectProxy *callbackProxy = reinterpret_cast((it->first).GetRefPtr()); + int status = callbackProxy->NoticeServiceDie(); + if (status != ERR_NONE) { + DBINDER_LOGE("fail to notice service"); + // do nothing, Continue to clear subsequent data + } + + sptr death = QueryDeathRecipient((it->first)); + if (death != nullptr) { + // Continue to clear subsequent data + callbackProxy->RemoveDeathRecipient(death); + } + + if (!DetachDeathRecipient((it->first))) { + DBINDER_LOGE("detaching death recipient is failed"); + } + + it = noticeProxy_.erase(it); + } else { + it++; + } + } +} + +int32_t DBinderService::NoticeServiceDieInner(const std::u16string &serviceName, const std::string &deviceID) +{ + if (serviceName.empty() || IsDeviceIdIllegal(deviceID)) { + DBINDER_LOGE("service name length = %zu, deviceID length = %zu", serviceName.length(), deviceID.length()); + return DBINDER_SERVICE_INVALID_DATA_ERR; + } + + sptr dbStub = FindDBinderStub(serviceName, deviceID); + if (dbStub == nullptr) { + DBINDER_LOGE("find null stub, do not need notice death"); + return ERR_NONE; + } + + if (!NoticeCallbackProxy(dbStub)) { + DBINDER_LOGE("find null proxy"); + return DBINDER_SERVICE_NOTICE_DIE_ERR; + } + return ERR_NONE; +} + +int32_t DBinderService::NoticeServiceDie(const std::u16string &serviceName, const std::string &deviceID) +{ + std::lock_guard lockGuard(deathNotificationMutex_); + return NoticeServiceDieInner(serviceName, deviceID); +} + +int32_t DBinderService::NoticeDeviceDie(const std::string &deviceID) +{ + if (IsDeviceIdIllegal(deviceID)) { + DBINDER_LOGE("deviceID length = %zu", deviceID.length()); + return DBINDER_SERVICE_INVALID_DATA_ERR; + } + DBINDER_LOGI("remote device is dead, device = %s", DBinderService::ConvertToSecureDeviceID(deviceID).c_str()); + + if (remoteListener_ == nullptr) { + DBINDER_LOGE("remote listener is null"); + return DBINDER_SERVICE_NOTICE_DIE_ERR; + } + + if (!remoteListener_->CloseDatabusSession(deviceID)) { + DBINDER_LOGE("close databus session fail"); + // do nothing + } + + std::list serviceNames = FindServicesByDeviceID(deviceID); + if (serviceNames.empty()) { + DBINDER_LOGE("the device does not have any registered service"); + return ERR_NONE; + } + + int status = ERR_NONE; + std::lock_guard lockGuard(deathNotificationMutex_); + + for (auto it = serviceNames.begin(); it != serviceNames.end(); it++) { + status += NoticeServiceDieInner((*it), deviceID); + } + + return status; +} + +std::list DBinderService::FindServicesByDeviceID(const std::string &deviceID) +{ + std::lock_guard lockGuard(handleEntryMutex_); + std::list serviceNames; + for (auto it = DBinderStubRegisted_.begin(); it != DBinderStubRegisted_.end(); it++) { + if ((*it)->GetDeviceID() == deviceID) { + serviceNames.push_back(Str8ToStr16((*it)->GetServiceName())); + } + } + + return serviceNames; +} + +uint32_t DBinderService::GetRemoteTransType() +{ + return IRemoteObject::DATABUS_TYPE; +} + +std::string DBinderService::ConvertToSecureDeviceID(const std::string &deviceID) +{ + if (strlen(deviceID.c_str()) <= ENCRYPT_LENGTH) { + return "****"; + } + return deviceID.substr(0, ENCRYPT_LENGTH) + "****" + deviceID.substr(strlen(deviceID.c_str()) - ENCRYPT_LENGTH); +} +} // namespace OHOS diff --git a/services/dbinder/dbinder_service/src/dbinder_service_stub.cpp b/services/dbinder/dbinder_service/src/dbinder_service_stub.cpp new file mode 100755 index 00000000..0a928047 --- /dev/null +++ b/services/dbinder/dbinder_service/src/dbinder_service_stub.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_service_stub.h" + +#include +#include "sys_binder.h" +#include "string_ex.h" +#include "dbinder_log.h" +#include "dbinder_service.h" +#include "dbinder_death_recipient.h" +#include "ipc_skeleton.h" + +namespace OHOS { +DBinderServiceStub::DBinderServiceStub(const std::string &service, const std::string &device, binder_uintptr_t object) + : IPCObjectStub(Str8ToStr16(device + service)), serviceName_(service), deviceID_(device), binderObject_(object) +{ + DBINDER_LOGI("new DBinderServiceStub created"); +} + +DBinderServiceStub::~DBinderServiceStub() +{ + DBINDER_LOGI("DBinderServiceStub delete"); +} + +const std::string &DBinderServiceStub::GetServiceName() +{ + return serviceName_; +} + +const std::string &DBinderServiceStub::GetDeviceID() +{ + return deviceID_; +} + +binder_uintptr_t DBinderServiceStub::GetBinderObject() const +{ + return binderObject_; +} + +int32_t DBinderServiceStub::ProcessProto(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + int result = ERR_NONE; + sptr dBinderService = DBinderService::GetInstance(); + if (dBinderService == nullptr) { + DBINDER_LOGE("DBinderService is nullptr"); + return DBINDER_SERVICE_PROCESS_PROTO_ERR; + } + auto session = dBinderService->QuerySessionObject(reinterpret_cast(this)); + if (session == nullptr) { + DBINDER_LOGE("client find session is null"); + return DBINDER_SERVICE_PROCESS_PROTO_ERR; + } + + DBINDER_LOGI("stubIndex = %" PRIu64 ", socketFd = %" PRIu32 "", session->stubIndex, session->socketFd); + DBINDER_LOGI("serviceName = %s", session->serviceName.c_str()); + + int uid = IPCSkeleton::GetCallingUid(); + int pid = IPCSkeleton::GetCallingPid(); + if (uid < 0 || pid < 0) { + DBINDER_LOGE("uid or pid err"); + return DBINDER_SERVICE_PROCESS_PROTO_ERR; + } + + std::string localBusName = dBinderService->CreateDatabusName(uid, pid); + if (localBusName.empty()) { + DBINDER_LOGE("local busname nil"); + return DBINDER_SERVICE_PROCESS_PROTO_ERR; + } + + switch (session->type) { + case IRemoteObject::DATABUS_TYPE: { + if (!reply.WriteUint32(IRemoteObject::IF_PROT_DATABUS) || !reply.WriteUint64(session->stubIndex) || + !reply.WriteString(session->serviceName) || !reply.WriteString(session->deviceIdInfo.toDeviceId) || + !reply.WriteString(session->deviceIdInfo.fromDeviceId) || !reply.WriteString(localBusName)) { + DBINDER_LOGE("write to parcel fail"); + return DBINDER_SERVICE_PROCESS_PROTO_ERR; + } + break; + } + default: { + DBINDER_LOGE("Invalid Type"); + return DBINDER_SERVICE_PROCESS_PROTO_ERR; + } + } + + return result; +} + +int32_t DBinderServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + int32_t result = ERR_NONE; + switch (code) { + case GET_PROTO_INFO: { + result = ProcessProto(code, data, reply, option); + break; + } + case DBINDER_OBITUARY_TRANSACTION: { + result = ProcessDeathRecipient(data, reply); + break; + } + default: { + DBINDER_LOGI("unknown code = %{public}u", code); + result = DBINDER_SERVICE_UNKNOW_TRANS_ERR; + break; + } + } + + return result; +} + +int32_t DBinderServiceStub::ProcessDeathRecipient(MessageParcel &data, MessageParcel &reply) +{ + int32_t processType = data.ReadInt32(); + if (processType == IRemoteObject::DeathRecipient::ADD_DEATH_RECIPIENT) { + return AddDbinderDeathRecipient(data, reply); + } + + if (processType == IRemoteObject::DeathRecipient::REMOVE_DEATH_RECIPIENT) { + return RemoveDbinderDeathRecipient(data, reply); + } + + return DBINDER_SERVICE_UNKNOW_TRANS_ERR; +} + +int32_t DBinderServiceStub::AddDbinderDeathRecipient(MessageParcel &data, MessageParcel &reply) +{ + sptr object = data.ReadRemoteObject(); + if (object == nullptr) { + DBINDER_LOGE("received proxy is null"); + return DBINDER_SERVICE_INVALID_DATA_ERR; + } + + IPCObjectProxy *callbackProxy = reinterpret_cast(object.GetRefPtr()); + sptr death(new DbinderDeathRecipient()); + + // If the client dies, notify DBS to delete information of callbackProxy + if (!callbackProxy->AddDeathRecipient(death)) { + DBINDER_LOGE("fail to add death recipient"); + return DBINDER_SERVICE_ADD_DEATH_ERR; + } + + sptr dBinderService = DBinderService::GetInstance(); + if (dBinderService == nullptr) { + DBINDER_LOGE("dBinder service is null"); + return DBINDER_SERVICE_ADD_DEATH_ERR; + } + + if (!dBinderService->AttachDeathRecipient(object, death)) { + DBINDER_LOGE("fail to attach death recipient"); + return DBINDER_SERVICE_ADD_DEATH_ERR; + } + + if (!dBinderService->AttachCallbackProxy(object, this)) { + DBINDER_LOGE("fail to attach callback proxy"); + return DBINDER_SERVICE_ADD_DEATH_ERR; + } + + return ERR_NONE; +} + +int32_t DBinderServiceStub::RemoveDbinderDeathRecipient(MessageParcel &data, MessageParcel &reply) +{ + sptr object = data.ReadRemoteObject(); + if (object == nullptr) { + DBINDER_LOGE("received proxy is null"); + return DBINDER_SERVICE_REMOVE_DEATH_ERR; + } + + IPCObjectProxy *callbackProxy = reinterpret_cast(object.GetRefPtr()); + + sptr dBinderService = DBinderService::GetInstance(); + if (dBinderService == nullptr) { + DBINDER_LOGE("dBinder service is null"); + return DBINDER_SERVICE_REMOVE_DEATH_ERR; + } + + sptr death = dBinderService->QueryDeathRecipient(object); + if (death != nullptr) { + // Continue to clear subsequent data + callbackProxy->RemoveDeathRecipient(death); + } + + if (!dBinderService->DetachDeathRecipient(object)) { + DBINDER_LOGE("fail to detach death recipient"); + return DBINDER_SERVICE_REMOVE_DEATH_ERR; + } + + if (!dBinderService->DetachCallbackProxy(object)) { + DBINDER_LOGE("fail to detach callback proxy"); + return DBINDER_SERVICE_REMOVE_DEATH_ERR; + } + + return ERR_NONE; +} +} // namespace OHOS diff --git a/services/dbinder/dbinder_service/src/socket/dbinder_remote_listener.cpp b/services/dbinder/dbinder_service/src/socket/dbinder_remote_listener.cpp new file mode 100755 index 00000000..b9f753a8 --- /dev/null +++ b/services/dbinder/dbinder_service/src/socket/dbinder_remote_listener.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_remote_listener.h" +#include +#include "securec.h" +#include "ipc_types.h" +#include "dbinder_log.h" +#include "dbinder_error_code.h" + +namespace OHOS { +DBinderRemoteListener::DBinderRemoteListener(const sptr &dBinderService) + : dBinderService_(dBinderService) +{ + DBINDER_LOGI("create dbinder remote listener"); +} + +DBinderRemoteListener::~DBinderRemoteListener() +{ + DBINDER_LOGI("delete dbinder remote listener"); +} + +bool DBinderRemoteListener::StartListener() +{ + std::lock_guard lockGuard(busManagerMutex_); + softbusManager_ = ISessionService::GetInstance(); + if (softbusManager_ == nullptr) { + DBINDER_LOGE("fail to get softbus service"); + return false; + } + std::shared_ptr callbacks(this); + int ret = softbusManager_->CreateSessionServer(OWN_SESSION_NAME, PEER_SESSION_NAME, callbacks); + if (ret != 0) { + DBINDER_LOGE("fail to create softbus server with ret = %{public}d", ret); + return false; + } + return true; +} + +bool DBinderRemoteListener::StopListener() +{ + std::lock_guard lockGuard(busManagerMutex_); + if (softbusManager_ == nullptr) { + DBINDER_LOGE("softbus manager is null"); + return false; + } + + int ret = softbusManager_->RemoveSessionServer(OWN_SESSION_NAME, PEER_SESSION_NAME); + if (ret != 0) { + DBINDER_LOGE("fail to remove softbus server"); + return false; + } + softbusManager_ = nullptr; + return true; +} + +bool DBinderRemoteListener::SendDataToRemote(const std::string &deviceId, const struct DHandleEntryTxRx *msg) +{ + if (msg == nullptr) { + DBINDER_LOGE("msg is null"); + return false; + } + + std::shared_ptr session = OpenSoftbusSession(deviceId); + if (session == nullptr) { + DBINDER_LOGE("fail to open session"); + return false; + } + + int ret = session->SendBytes(msg, msg->head.len); + if (ret != 0) { + DBINDER_LOGE("fail to send bytes, ret = %{public}d", ret); + return false; + } + return true; +} + +bool DBinderRemoteListener::CloseDatabusSession(const std::string &deviceId) +{ + std::lock_guard lockGuard(busManagerMutex_); + if (softbusManager_ == nullptr) { + DBINDER_LOGE("softbus manager is null"); + return false; + } + + std::shared_ptr session = softbusManager_->OpenSession(OWN_SESSION_NAME, PEER_SESSION_NAME, deviceId, + std::string(""), Session::TYPE_BYTES); + if (session == nullptr) { + DBINDER_LOGE("fail to open session before closing it"); + return false; + } + + return softbusManager_->CloseSession(session) == 0; +} + +std::shared_ptr DBinderRemoteListener::OpenSoftbusSession(const std::string &peerDeviceId) +{ + std::lock_guard lockGuard(busManagerMutex_); + if (softbusManager_ == nullptr) { + DBINDER_LOGE("softbus manager is null"); + return nullptr; + } + + return softbusManager_->OpenSession(OWN_SESSION_NAME, PEER_SESSION_NAME, peerDeviceId, std::string(""), + Session::TYPE_BYTES); +} + +int DBinderRemoteListener::OnSessionOpened(std::shared_ptr session) +{ + DBINDER_LOGI("peer session is open"); + if (session->GetPeerUid() != getuid() || session->GetPeerSessionName() != PEER_SESSION_NAME) { + DBINDER_LOGE("invalid session name, peer session name = %{public}s", session->GetPeerSessionName().c_str()); + return -DBINDER_SERVICE_WRONG_SESSION; + } + return 0; +} + +void DBinderRemoteListener::OnSessionClosed(std::shared_ptr session) +{ + DBINDER_LOGI("peer session name = %{public}s is closed", session->GetPeerSessionName().c_str()); +} + +void DBinderRemoteListener::OnBytesReceived(std::shared_ptr session, const char *data, ssize_t len) +{ + if (data == nullptr || len != static_cast(sizeof(struct DHandleEntryTxRx))) { + DBINDER_LOGE("session has wrong input, peer session name = %s, data length = %zd", + session->GetPeerSessionName().c_str(), len); + // ignore the package + return; + } + + if (dBinderService_ == nullptr) { + DBINDER_LOGE("dbinder service is not started"); + return; + } + + struct DHandleEntryTxRx *handleEntry = (struct DHandleEntryTxRx *)data; + if (handleEntry == nullptr) { + DBINDER_LOGE("msg is null"); + return; + } + + if (!dBinderService_->OnRemoteMessageTask(handleEntry)) { + DBINDER_LOGE("process remote message fail"); + } +} +} // namespace OHOS diff --git a/services/dbinder/test/BUILD.gn b/services/dbinder/test/BUILD.gn new file mode 100755 index 00000000..3fdad4b6 --- /dev/null +++ b/services/dbinder/test/BUILD.gn @@ -0,0 +1,164 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +DBINDER_TEST_ROOT = "//foundation/communication/ipc/services/dbinder/test" +MODULE_OUTPUT_PATH = "ipc/services/dbinder" + +############################################################################### +config("libtestdbinder_config") { + visibility = [ ":*" ] + cflags = [] + if (is_standard_system) { + cflags += [ "-DCONFIG_STANDARD_SYSTEM" ] + } + include_dirs = [ + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "//test/developertest/aw/distributed", + "$SUBSYSTEM_DIR/utils/include", + "$SUBSYSTEM_DIR/services/dbinder/dbinder_service/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_core/include", + "$DBINDER_TEST_ROOT/distributedtest/include", + ] +} + +ohos_distributedtest("DbinderTest") { + module_out_path = MODULE_OUTPUT_PATH + + sources = [ + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_distributed_test.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_service_test_helper.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_service.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_service_skeleton.cpp", + ] + + configs = [ ":libtestdbinder_config" ] + + deps = [ + ":dbinder_send", + ":dbinder_test", + "$SUBSYSTEM_DIR/interfaces/innerkits/libdbinder:libdbinder", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + subsystem_name = "communication" + resource_config_file = + "//foundation/communication/ipc/test/resource/services/ohos_test.xml" +} + +ohos_distributedtest("DbinderTestAgent") { + module_out_path = MODULE_OUTPUT_PATH + + sources = [ + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_service_test_helper.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_agent.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_service.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_service_skeleton.cpp", + ] + + configs = [ ":libtestdbinder_config" ] + + deps = [ + ":dbinder_send", + ":dbinder_test", + "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_core:ipc_core", + "//third_party/googletest:gtest", + "//utils/native/base:utils", + ] + + external_deps = [ + "dsoftbus_standard:softbus_client", + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + subsystem_name = "communication" + resource_config_file = + "//foundation/communication/ipc/test/resource/services/ohos_test.xml" +} + +############################################################################### +ohos_executable("dbinder_test") { + sources = [ + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_server_main.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_service.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_service_skeleton.cpp", + ] + + configs = [ ":libtestdbinder_config" ] + + deps = [ + "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_core:ipc_core", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + part_name = "ipc" + subsystem_name = "communication" +} + +ohos_executable("dbinder_send") { + sources = [ + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_server_main.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_service.cpp", + "$DBINDER_TEST_ROOT/distributedtest/src/dbinder_test_service_skeleton.cpp", + ] + + cflags_cc = [ "-DDBINDER_TEST_SECOND" ] + + configs = [ ":libtestdbinder_config" ] + + deps = [ + "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_core:ipc_core", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "samgr_L2:samgr_proxy", + ] + + part_name = "ipc" + subsystem_name = "communication" +} + +ohos_distributedtest_py("dbindertest_py") { + module_out_path = MODULE_OUTPUT_PATH + sources = [ "test_dbinder.py" ] +} + +############################################################################### +group("distributedtest") { + testonly = true + deps = [ + ":DbinderTest", + ":DbinderTestAgent", + ":dbinder_send", + ":dbinder_test", + ":dbindertest_py", + ] +} diff --git a/services/dbinder/test/distributedtest/include/dbinder_service_test_helper.h b/services/dbinder/test/distributedtest/include/dbinder_service_test_helper.h new file mode 100755 index 00000000..3caebdfa --- /dev/null +++ b/services/dbinder/test/distributedtest/include/dbinder_service_test_helper.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_DBINDER_SERVICE_TEST_HELPER_INCLUDE_H +#define OHOS_DBINDER_SERVICE_TEST_HELPER_INCLUDE_H + +#include +#include +#include +#include + +const std::string DBINDER_TEST_SERVICE_NAME = "dbinder_test"; +const std::string DBINDER_TEST_SERVICE_NAME_SECOND = "dbinder_send"; +const std::string SYSTEM_ABILITY_MANAGER_NAME = "SaManager"; + +const int BUF_SIZE = 1024 * 4; +const int PATH_LENGTH = 1024 * 4; +const static int INVALID_PID = -1; +const static int SECOND_TO_MS = 1000; +const static int KB_TO_B = 1024; + +enum { + /* + * Here's the list of DBinderService Test Case List. + * This list should be used for Trans-Mock. + */ + DBINDER_TEST_INIT = -1, + DBINDER_TEST_START = 0, + DBINDER_TEST_REGISTRY_001, + DBINDER_TEST_REGISTRY_002, + DBINDER_TEST_REGISTRY_003, + DBINDER_TEST_REGISTRY_004, + DBINDER_TEST_REMOTE_CALL_001, + DBINDER_TEST_REMOTE_CALL_002, + DBINDER_TEST_REMOTE_CALL_003, + DBINDER_TEST_REMOTE_CALL_004, + DBINDER_TEST_REMOTE_CALL_005, + DBINDER_TEST_REMOTE_CALL_006, + DBINDER_TEST_REMOTE_CALL_007, + DBINDER_TEST_REMOTE_CALL_008, + DBINDER_TEST_REMOTE_CALL_009, + DBINDER_TEST_REMOTE_CALL_010, + DBINDER_TEST_REMOTE_CALL_011, + DBINDER_TEST_REMOTE_CALL_012, + DBINDER_TEST_REMOTE_CALL_013, + DBINDER_TEST_REMOTE_CALL_014, + DBINDER_TEST_REMOTE_CALL_015, + DBINDER_TEST_REMOTE_CALL_016, + DBINDER_TEST_DEATH_RECIPIENT_001, + DBINDER_TEST_DEATH_RECIPIENT_002, + DBINDER_TEST_DEATH_RECIPIENT_003, + DBINDER_TEST_DEATH_RECIPIENT_004, + DBINDER_TEST_DEATH_RECIPIENT_005, + DBINDER_TEST_DEATH_RECIPIENT_006, + DBINDER_TEST_DEATH_RECIPIENT_007, + DBINDER_TEST_RAW_DATA_001, + DBINDER_TEST_RAW_DATA_002, + DBINDER_TEST_RAW_DATA_003, + DBINDER_TEST_RAW_DATA_004, + DBINDER_TEST_RAW_DATA_005, + DBINDER_TEST_RAW_DATA_006, + DBINDER_TEST_TRACE_001, + DBINDER_TEST_TRANS_STUB_001, + DBINDER_TEST_FLUSH_COMMAND_001, + DBINDER_TEST_END, +}; + +static int g_currentTestCase = DBINDER_TEST_INIT; + +pid_t GetPidByName(std::string taskName); +int StartDBinderServiceSARegistry(); +void StopDBinderServiceSARegistry(); +void StartDBinderServiceTestService(); +void StopDBinderServiceTestService(); +int GetChildPids(std::vector &childPids); +pid_t StartExecutable(std::string name, std::string args = ""); +void StopExecutable(pid_t pid); +void StopExecutable(std::string name); +int SetCurrentTestCase(int caseNum); +int GetCurrentTestCase(void); +int64_t GetCurrentTime(); +float GetSpeed(int64_t timeInterval, int size, int times); + +bool MakeIpLoop(void); +bool RevertIpLoop(void); + +#endif // OHOS_DBINDER_SERVICE_TEST_HELPER_INCLUDE_H diff --git a/services/dbinder/test/distributedtest/include/dbinder_test_service.h b/services/dbinder/test/distributedtest/include/dbinder_test_service.h new file mode 100755 index 00000000..7d54e3e4 --- /dev/null +++ b/services/dbinder/test/distributedtest/include/dbinder_test_service.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_DBINDER_TEST_SERVICE_H +#define OHOS_DBINDER_TEST_SERVICE_H + +#include "dbinder_test_service_skeleton.h" +#include "hilog/log.h" + +namespace OHOS { +class DBinderTestService : public DBinderTestServiceStub { +public: + DBinderTestService() = default; + virtual ~DBinderTestService(); + static int Instantiate(); + int ReverseInt(int data, int &rep) override; + int ReverseIntDelay(int data, int &rep) override; + int Delay(int data, int &rep) override; + int PingService(std::u16string &serviceName) override; + int TransProxyObject(int data, sptr &transObject, int operation, int &rep, + int &withdrawRes) override; + int TransStubObject(int data, sptr &transObject, int &rep, int &stubRep) override; + int TransOversizedPkt(const std::string &dataStr, std::string &repStr) override; + int ProxyTransRawData(int length) override; + int StubTransRawData(int length) override; +#ifndef CONFIG_STANDARD_SYSTEM + int GetChildId(uint64_t &rep) override; +#endif + sptr GetRemoteObject(int type) override; + int FlushAsyncCommands(int count, int length) override; + int GetRemoteDecTimes() override; + void ClearRemoteDecTimes() override; + +public: + static std::mutex destructTimesMutex_; + static int destructTimes_; + sptr object_; +}; +} // namespace OHOS + +#endif // OHOS_DBINDER_TEST_SERVICE_H diff --git a/services/dbinder/test/distributedtest/include/dbinder_test_service_skeleton.h b/services/dbinder/test/distributedtest/include/dbinder_test_service_skeleton.h new file mode 100755 index 00000000..b4ac69c3 --- /dev/null +++ b/services/dbinder/test/distributedtest/include/dbinder_test_service_skeleton.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_DBINDER_TEST_SERVICE_SKELETON_H +#define OHOS_DBINDER_TEST_SERVICE_SKELETON_H + +#include "ipc_types.h" +#include "iremote_broker.h" +#include "iremote_object.h" +#include "iremote_stub.h" +#include "iremote_proxy.h" +#include "hilog/log.h" +#include "log_tags.h" +#ifndef CONFIG_STANDARD_SYSTEM +#include "hitrace/trace.h" +#endif + +namespace OHOS { +class IDBinderTestService : public IRemoteBroker { +public: + enum { + REVERSEINT = 0, + REVERSEINTDELAY = 1, + PING_SERVICE = 2, + GET_FOO_SERVICE = 3, + ONLY_DELAY = 4, + TRANS_OBJECT = 5, + TRANS_OVERSIZED_PKT = 6, + TRANS_RAW_DATA = 7, + RECEIVE_RAW_DATA = 8, + TRANS_TRACE_ID = 9, + TRANS_STUB_OBJECT = 10, + GET_REMOTE_STUB_OBJECT = 11, + GET_REMOTE_DES_TIMES = 12, + CLEAR_REMOTE_DES_TIMES = 13, + }; + + enum { + NOT_SAVE = 0, + SAVE = 1, + WITHDRAW = 2, + }; + + enum { + FIRST_OBJECT = 0, // Acquired once will be released automatically + SECOND_OBJECT = 1, // Acquired twice will be released automatically + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.rpc.IDBinderTestService"); + virtual int ReverseInt(int data, int &rep) = 0; + virtual int ReverseIntDelay(int data, int &rep) = 0; + virtual int Delay(int data, int &rep) = 0; + virtual int PingService(std::u16string &serviceName) = 0; + virtual int ReverseIntDelayAsync(int data, int &rep) = 0; + virtual int TransProxyObject(int data, sptr &transObject, int operation, int &rep, + int &withdrawRes) = 0; + virtual int TransStubObject(int data, sptr &transObject, int &rep, int &stubRep) = 0; + virtual int TransOversizedPkt(const std::string &dataStr, std::string &repStr) = 0; + virtual int ProxyTransRawData(int lengths) = 0; + virtual int StubTransRawData(int length) = 0; +#ifndef CONFIG_STANDARD_SYSTEM + virtual int GetChildId(uint64_t &rep) = 0; +#endif + virtual int FlushAsyncCommands(int count, int length) = 0; + virtual sptr GetRemoteObject(int type) = 0; + virtual int GetRemoteDecTimes() = 0; + virtual void ClearRemoteDecTimes() = 0; + +private: + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_RPC, "IDBinderTestService" }; +}; + +class DBinderTestServiceStub : public IRemoteStub { +public: + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + int ReverseIntDelayAsync(int data, int &rep) override; + static pid_t GetLastCallingPid(); + static uid_t GetLastCallingUid(); + +private: + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_RPC, "DBinderTestStub" }; + static pid_t g_lastCallingPid; + static pid_t g_lastCallinguid; + sptr recvProxy_; + + int OnReverseInt(MessageParcel &data, MessageParcel &reply); + int OnReverseIntDelay(MessageParcel &data, MessageParcel &reply); + int OnPingService(MessageParcel &data, MessageParcel &reply); + int OnDelay(MessageParcel &data, MessageParcel &reply); + int OnReceivedObject(MessageParcel &data, MessageParcel &reply); + int OnReceivedStubObject(MessageParcel &data, MessageParcel &reply); + int OnReceivedOversizedPkt(MessageParcel &data, MessageParcel &reply); + int OnReceivedRawData(MessageParcel &data, MessageParcel &reply); +#ifndef CONFIG_STANDARD_SYSTEM + int OnGetChildId(MessageParcel &data, MessageParcel &reply); +#endif + int OnSentRawData(MessageParcel &data, MessageParcel &reply); + int OnReceivedGetStubObject(MessageParcel &data, MessageParcel &reply); + int OnReceivedGetDecTimes(MessageParcel &data, MessageParcel &reply); + int OnReceivedClearDecTimes(MessageParcel &data, MessageParcel &reply); +}; + + +class DBinderTestServiceProxy : public IRemoteProxy { +public: + explicit DBinderTestServiceProxy(const sptr &impl); + ~DBinderTestServiceProxy() = default; + int ReverseInt(int data, int &rep) override; + int ReverseIntNullReply(int data, int &rep); + int ReverseIntVoidData(int data, int &rep); + int ReverseIntDelay(int data, int &rep) override; + int Delay(int data, int &rep) override; + int ReverseIntDelayAsync(int data, int &rep) override; + int PingService(std::u16string &serviceName) override; + int TransProxyObject(int data, sptr &transObject, int operation, int &rep, + int &withdrawRes) override; + int TransStubObject(int data, sptr &transObject, int &rep, int &stubRep) override; + int TransOversizedPkt(const std::string &dataStr, std::string &repStr) override; + int ProxyTransRawData(int length) override; + int StubTransRawData(int length) override; +#ifndef CONFIG_STANDARD_SYSTEM + int GetChildId(uint64_t &rep) override; +#endif + sptr GetRemoteObject(int type) override; + int GetRemoteDecTimes() override; + void ClearRemoteDecTimes() override; + int FlushAsyncCommands(int count, int length) override; + +private: + static inline BrokerDelegator delegator_; + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_RPC, "DBinderTestProxy" }; +}; + + +class DBinderTestDeathRecipient : public IRemoteObject::DeathRecipient { +public: + virtual void OnRemoteDied(const wptr &remote); + DBinderTestDeathRecipient(); + virtual ~DBinderTestDeathRecipient(); + static bool GotDeathRecipient(); + static void ClearDeathRecipient(); + static bool g_gotDeathRecipient; + +private: + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_RPC, "DBinderTestDeathRecipient" }; +}; +} // namespace OHOS +#endif // OHOS_DBINDER_TEST_SERVICE_SKELETON_H diff --git a/services/dbinder/test/distributedtest/src/dbinder_distributed_test.cpp b/services/dbinder/test/distributedtest/src/dbinder_distributed_test.cpp new file mode 100755 index 00000000..9e692fa5 --- /dev/null +++ b/services/dbinder/test/distributedtest/src/dbinder_distributed_test.cpp @@ -0,0 +1,1460 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dbinder_service.h" +#include "dbinder_service_test_helper.h" +#include "dbinder_test_service_skeleton.h" +#include "ipc_skeleton.h" +#include "ipc_object_proxy.h" +#include "ipc_types.h" +#include "if_system_ability_manager.h" +#include "string_ex.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "distributed_major.h" +#include "log_tags.h" +#include "dbinder_test_service.h" + +using namespace OHOS; +using namespace testing::ext; +using namespace OHOS::DistributeSystemTest; +using namespace OHOS::HiviewDFX; + +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "DbinderTest" }; +#define DBINDER_LOGF(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGW(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Warn(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGD(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Debug(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +class DbinderTest : public DistributeTest { +public: + static const int UNIT = 1024; + /* The threshold of packet size is 64 * 1024, including header. + * The following definitions are used to test legal and illegal packets. + */ + static const int LEGAL_SIZE_S = 3 * 1024; + static const int LEGAL_SIZE_M = 16 * 1024; + static const int LEGAL_SIZE_L = 63 * 1024; + static const int ILLEGAL_SIZE = 2 * 1024 * 1024; + static const int REPEAT_TIMES = 1000; + static const int REPEAT_RAW_DATA_TIMES = 100; + static const int MULTIPLEX_TIMES = 10; + static sptr manager_; + static char serverId_[DEVICEID_LENGTH + 1]; + // Test transferring big data with different sizes + const int rawData10K = 10 * 1024; + const int rawData100K = 100 * 1024; + const int rawData1M = 1024 * 1024; + const int rawData10M = 10 * 1024 * 1024; + const int rawData100M = 100 * 1024 * 1024; + + DbinderTest() = default; + ~DbinderTest() = default; + static void SetUpTestCase(); + static void TearDownTestCase(); + virtual void SetUp(); + virtual void TearDown() {}; + std::string IpToDeviceId(const std::string &localIp); + bool GetRemoteDeviceId(); +}; + +sptr DbinderTest::manager_ = nullptr; +char DbinderTest::serverId_[DEVICEID_LENGTH + 1]; + +void DbinderTest::SetUpTestCase() +{ + DBINDER_LOGI("enter SetUpTestCase"); + StartDBinderServiceTestService(); +} + +void DbinderTest::TearDownTestCase() +{ + DBINDER_LOGI("enter TearDownTestCase"); + StopDBinderServiceTestService(); +} + +void DbinderTest::SetUp() +{ + bool ret = GetRemoteDeviceId(); + ASSERT_TRUE(ret); + + sptr dBinderService = DBinderService::GetInstance(); + ASSERT_TRUE(dBinderService != nullptr); + + manager_ = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(manager_ != nullptr); +} + +bool DbinderTest::GetRemoteDeviceId() +{ + std::string msg = "Ask Device ID"; + int ret = SendMessage(AGENT_NO::ONE, msg, strlen(msg.c_str()), [&](const std::string &retId, int retLen) -> bool { + if (memcpy_s(serverId_, DEVICEID_LENGTH, retId.c_str(), DEVICEID_LENGTH) != 0 || retLen != DEVICEID_LENGTH) { + DBINDER_LOGE("fail to copy string"); + return false; + } + serverId_[DEVICEID_LENGTH] = '\0'; + return true; + }); + + return ret > 0; +} + +/* + * @tc.name: DbinderRemoteCall001 + * @tc.desc: Verify local client can acquire registered system ability + * and invoke remote function on remote server. + * @tc.type: FUNC + * @tc.require: SR000CS1C1/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall001, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_001); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to invoke remote function. + * @tc.expected: step2.Remote call succeeds and returns 0. + */ + int reply = 0; + int result = testService->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} +/* + * @tc.name: DbinderRemoteCall002 + * @tc.desc: Verify local client cannot acquire unregistered system ability + * @tc.type: FUNC + * @tc.require: SR000CS1C1/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall002, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_002); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get an unregistered System Ability from remote server. + * @tc.expected: step1.Failed to get the SA and return nullptr. + */ + sptr object = manager_->GetSystemAbility(RPC_UNREGISTERED_TEST_SERVICE, serverId_); + ASSERT_TRUE(object == nullptr); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall003 + * @tc.desc: Verify the limit to the size of data sent to remote server + * @tc.type: FUNC + * @tc.require: SR000CS1C1/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall003, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_003); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to invoke remote function with legal and illegal data respectively. + * @tc.expected: step2.Succeed in transferring legal data but fail to transfer illegal data. + */ + std::string reply; + std::string emptyData; + testService->TransOversizedPkt(emptyData, reply); + ASSERT_TRUE(emptyData == reply); + + std::string legalDataS(LEGAL_SIZE_S, 'a'); + int64_t startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + testService->TransOversizedPkt(legalDataS, reply); + ASSERT_TRUE(legalDataS == reply); + } + int64_t finishTime = GetCurrentTime(); + float speed = GetSpeed(finishTime - startTime, LEGAL_SIZE_S, MULTIPLEX_TIMES); + printf("Transfer 3k data with speed of %.2fk/s.\n", speed); + + std::string legalDataM(LEGAL_SIZE_M, 'a'); + startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + testService->TransOversizedPkt(legalDataM, reply); + ASSERT_TRUE(legalDataM == reply); + } + finishTime = GetCurrentTime(); + speed = GetSpeed(finishTime - startTime, LEGAL_SIZE_M, MULTIPLEX_TIMES); + printf("Transfer 16k data with speed of %.2fk/s.\n", speed); + + std::string legalDataL(LEGAL_SIZE_L, 'a'); + startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + testService->TransOversizedPkt(legalDataL, reply); + ASSERT_TRUE(legalDataL == reply); + } + finishTime = GetCurrentTime(); + speed = GetSpeed(finishTime - startTime, LEGAL_SIZE_L, MULTIPLEX_TIMES); + printf("Transfer 63k data with speed of %.2fk/s.\n", speed); + + std::string illegalData(ILLEGAL_SIZE, 'a'); + testService->TransOversizedPkt(illegalData, reply); + ASSERT_TRUE(illegalData != reply); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall004 + * @tc.desc: Verify the communication with remote server is stable + * @tc.type: PERF + * @tc.require: SR000CS1C1/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall004, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_004); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to call remote function repeatedly. + * @tc.expected: step2.All remote calls succeed and return 0. + */ + for (int i = 0; i < REPEAT_TIMES; i++) { + int reply = 0; + int result = testService->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + } + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall005 + * @tc.desc: Test the delay of remote call with remote server + * @tc.type: PERF + * @tc.require: SR000CS1C1/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall005, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_005); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to call remote function, and calculate the time consumption. + * @tc.expected: step2.Remote call succeeds and the time delay is close to 15ms. + */ + int64_t startTime = GetCurrentTime(); + int reply = 0; + int result = testService->ReverseInt(2019, reply); + int64_t finishTime = GetCurrentTime(); + EXPECT_GE(finishTime - startTime, 0L); + printf("Remote call costs %" PRId64"ms\n", (finishTime - startTime)); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall006 + * @tc.desc: Verify the communications with remote device can be multiplexed + * @tc.type: FUNC + * @tc.require: SR000CS1C1/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall006, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_006); + DBINDER_LOGI(""); + + vector> objects; + vector> testServices; + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + /* + * @tc.steps: step1.Get a proxy from remote server and stores it. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + objects.push_back(manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_)); + testServices.push_back(iface_cast(objects[i])); + + /* + * @tc.steps: step2.Use the proxy object to invoke remote function. + * @tc.expected: step2.Remote call succeeds and returns 0. + */ + int reply = 0; + int result = testServices[i]->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + } + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall007 + * @tc.desc: Verify local client can transfer a local object to remote device. + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall007, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_007); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a local binder object and a proxy pointing to remote stub. + * @tc.expected: step1.Get both objects successfully. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + sptr remoteObject = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(remoteObject != nullptr); + + sptr remoteTestService = iface_cast(remoteObject); + ASSERT_TRUE(remoteTestService != nullptr); + + /* + * @tc.steps: step2.Transfer the binder object to remote device. + * @tc.expected: step2.Remote device receives the object and use it to communicate with server. + */ + int reply = 0; + int withdrawRes = 0; + int result = + remoteTestService->TransProxyObject(2019, object, OHOS::DBinderTestServiceProxy::NOT_SAVE, reply, withdrawRes); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + EXPECT_EQ(withdrawRes, 0); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall008 + * @tc.desc: Verify local client can transfer two different local objects to remote device. + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall008, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_008); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a local binder object and a proxy pointing to remote stub. + * @tc.expected: step1.Get both objects successfully. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + sptr object2 = manager_->GetSystemAbility(RPC_TEST_SERVICE); + ASSERT_TRUE(object2 != nullptr); + sptr remoteObject = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(remoteObject != nullptr); + + sptr remoteTestService = iface_cast(remoteObject); + ASSERT_TRUE(remoteTestService != nullptr); + + /* + * @tc.steps: step2.Transfer two binder objects to remote device. + * @tc.expected: step2.Remote device receives the objects and use them to communicate with server. + */ + int reply = 0; + int withdrawRes = 0; + int result = + remoteTestService->TransProxyObject(2019, object, OHOS::DBinderTestServiceProxy::NOT_SAVE, reply, withdrawRes); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + EXPECT_EQ(withdrawRes, 0); + + result = + remoteTestService->TransProxyObject(2019, object2, OHOS::DBinderTestServiceProxy::NOT_SAVE, reply, withdrawRes); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + EXPECT_EQ(withdrawRes, 0); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall009 + * @tc.desc: Verify local client is transmitting the same proxy every time to server. + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall009, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_009); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a local binder object and a proxy pointing to remote stub. + * @tc.expected: step1.Get both objects successfully. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + sptr remoteObject = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(remoteObject != nullptr); + + sptr remoteTestService = iface_cast(remoteObject); + ASSERT_TRUE(remoteTestService != nullptr); + + /* + * @tc.steps: step2.Transfer the binder object to remote device twice. + * @tc.expected: step2.Remote device receives same object in two transmissions. + */ + int reply = 0; + int withdrawRes = 0; + int result = remoteTestService->TransProxyObject(2019, object, DBinderTestServiceProxy::SAVE, reply, withdrawRes); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + EXPECT_EQ(withdrawRes, 0); + + result = remoteTestService->TransProxyObject(2019, object, DBinderTestServiceProxy::WITHDRAW, reply, withdrawRes); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + EXPECT_EQ(withdrawRes, 0); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall011 + * @tc.desc: Verify transferring objects between remote devices is stable + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall011, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_011); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a local binder object and a proxy pointing to remote stub. + * @tc.expected: step1.Get both objects successfully. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + sptr remoteObject = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(remoteObject != nullptr); + + sptr remoteTestService = iface_cast(remoteObject); + ASSERT_TRUE(remoteTestService != nullptr); + + /* + * @tc.steps: step2.Transfer the binder object to remote device repeatedly. + * @tc.expected: step2.Remote device receives the object and use it to communicate with server. + */ + for (int i = 0; i < REPEAT_TIMES; i++) { + int reply = 0; + int withdrawRes = 0; + int result = + remoteTestService->TransProxyObject(2019, object, DBinderTestServiceProxy::NOT_SAVE, reply, withdrawRes); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + } + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall012 + * @tc.desc: Test the delay of transferring an object between remote devices + * @tc.type: PERF + * @tc.require: SR000CS1C8/SR000CS1CA/SR000CUFFU + */ +HWTEST_F(DbinderTest, DbinderRemoteCall012, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_012); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a local binder object and a proxy pointing to remote stub. + * @tc.expected: step1.Get both objects successfully. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + sptr remoteObject = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(remoteObject != nullptr); + + sptr remoteTestService = iface_cast(remoteObject); + ASSERT_TRUE(remoteTestService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to transfer object, and calculate the time consumption. + * @tc.expected: step2.Remote call succeeds and the time delay is close to 50ms. + */ + int64_t startTime = GetCurrentTime(); + int reply = 0; + int withdrawRes = 0; + int result = + remoteTestService->TransProxyObject(2019, object, DBinderTestServiceProxy::NOT_SAVE, reply, withdrawRes); + int64_t finishTime = GetCurrentTime(); + EXPECT_GE(finishTime - startTime, 0L); + printf("Transferring an object costs %" PRId64 "ms\n", (finishTime - startTime)); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall014 + * @tc.desc: Verify adding and removing death recipient successfully + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA + */ +HWTEST_F(DbinderTest, DbinderRemoteCall014, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_DEATH_RECIPIENT_001); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Add death recipient. + * @tc.expected: step2.Register death notification successfully. + */ + sptr deathRecipient(new DBinderTestDeathRecipient()); + bool result = object->AddDeathRecipient(deathRecipient); + EXPECT_EQ(result, true); + + /* + * @tc.steps: step3.Remove death recipient + * @tc.expected: step3.Unregister death notification successfully. + */ + result = object->RemoveDeathRecipient(deathRecipient); + EXPECT_EQ(result, true); + + /* + * @tc.steps: step4.Use the proxy object to invoke remote function. + * @tc.expected: step4.Remote call succeeds and returns 0. + */ + int reply = 0; + int res = testService->ReverseInt(2019, reply); + EXPECT_EQ(res, 0); + EXPECT_EQ(reply, 9102); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall015 + * @tc.desc: Verify adding and removing death recipient successfully + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA + */ +HWTEST_F(DbinderTest, DbinderRemoteCall015, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_DEATH_RECIPIENT_002); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + sptr deathRecipient; + bool result = true; + int reply = 0, res = 0; + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + /* + * @tc.steps: step2.Add death recipient. + * @tc.expected: step2.Register death notification successfully. + */ + deathRecipient = new DBinderTestDeathRecipient(); + result = object->AddDeathRecipient(deathRecipient); + EXPECT_EQ(result, true); + + /* + * @tc.steps: step3.Remove death recipient + * @tc.expected: step3.Unregister death notification successfully. + */ + result = object->RemoveDeathRecipient(deathRecipient); + EXPECT_EQ(result, true); + + /* + * @tc.steps: step4.Use the proxy object to invoke remote function. + * @tc.expected: step4.Remote call succeeds and returns 0. + */ + res = testService->ReverseInt(2019, reply); + EXPECT_EQ(res, 0); + EXPECT_EQ(reply, 9102); + } + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall016 + * @tc.desc: Verify adding and removing death recipient successfully + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA + */ +HWTEST_F(DbinderTest, DbinderRemoteCall016, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_DEATH_RECIPIENT_003); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Add two death recipients. + * @tc.expected: step2.Register two death notifications successfully. + */ + sptr deathRecipient(new DBinderTestDeathRecipient()); + bool result = object->AddDeathRecipient(deathRecipient); + EXPECT_EQ(result, true); + + sptr deathRecipientRepeat(new DBinderTestDeathRecipient()); + result = object->AddDeathRecipient(deathRecipientRepeat); + EXPECT_EQ(result, true); + + /* + * @tc.steps: step3.Remove two death recipients. + * @tc.expected: step3.Return false when unregisterring 1st death notification because there is another one left. + * Return true when unregisterring 2nd death notification because all clean. + */ + result = object->RemoveDeathRecipient(deathRecipient); + EXPECT_EQ(result, false); + + result = object->RemoveDeathRecipient(deathRecipientRepeat); + EXPECT_EQ(result, true); + + /* + * @tc.steps: step4.Use the proxy object to invoke remote function. + * @tc.expected: step4.Remote call succeeds and returns 0. + */ + int reply = 0; + int res = testService->ReverseInt(2019, reply); + EXPECT_EQ(res, 0); + EXPECT_EQ(reply, 9102); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall017 + * @tc.desc: Verify receiving death notification when remote device dies + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA + */ +HWTEST_F(DbinderTest, DbinderRemoteCall017, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_DEATH_RECIPIENT_004); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Add death recipient. + * @tc.expected: step2.Register death notification successfully. + */ + sptr deathRecipient(new DBinderTestDeathRecipient()); + bool result = object->AddDeathRecipient(deathRecipient); + ASSERT_TRUE(result == true); + + /* + * @tc.steps: step3.Stop remote service. Wait 10s, then check death notification. + * @tc.expected: step3.Stop it successfully, and receive death notification. + */ + std::string command = "KILL"; + std::string cmdArgs = "server"; + std::string expectValue = "0"; + bool ret = RunCmdOnAgent(AGENT_NO::ONE, command, cmdArgs, expectValue); + EXPECT_EQ(ret, true); + EXPECT_EQ(GetReturnVal(), 0); + + // wait for killing remote service + sleep(10); + result = DBinderTestDeathRecipient::GotDeathRecipient(); + EXPECT_EQ(result, true); + DBinderTestDeathRecipient::ClearDeathRecipient(); + printf("Succ! Recv death notification!\n"); + + /* + * @tc.steps: step4.Remove death recipient + * @tc.expected: step4.Fail to remove death recipient + * because when receiving death notification, it remove death recipient automatically. + */ + result = object->RemoveDeathRecipient(deathRecipient); + EXPECT_EQ(result, false); + + /* + * @tc.steps: step5.Restart remote service and wait 10s. + * @tc.expected: step5.Restart it successfully. + */ + std::string restartCommand = "RESTART"; + ret = RunCmdOnAgent(AGENT_NO::ONE, restartCommand, cmdArgs, expectValue); + EXPECT_EQ(ret, true); + EXPECT_EQ(GetReturnVal(), 0); + + // wait for restarting server + sleep(10); + + /* + * @tc.steps: step6.Get a proxy (called testService2) from remote server. + * @tc.expected: step6.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object2 = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object2 != nullptr); + + sptr testService2 = iface_cast(object2); + ASSERT_TRUE(testService2 != nullptr); + + /* + * @tc.steps: step7.Use the proxy object to invoke remote function. + * @tc.expected: step7.Remote call succeeds and returns 0. + */ + int reply = 0; + int res = testService2->ReverseInt(2019, reply); + EXPECT_EQ(res, 0); + EXPECT_EQ(reply, 9102); + + object = nullptr; + testService = nullptr; + object2 = nullptr; + testService2 = nullptr; + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall018 + * @tc.desc: Verify transferring raw data + * @tc.type: FUNC + * @tc.require: AR000ER7PF + */ +HWTEST_F(DbinderTest, DbinderRemoteCall018, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_RAW_DATA_001); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to transfer raw data. + * @tc.expected: step2.Remote call succeed and return the size of raw data. + */ + // ProxyTransRawData cannot transfer data less than 2. + int result = testService->ProxyTransRawData(rawData100M); + EXPECT_EQ(result, 0); + result = testService->ProxyTransRawData(rawData100M); + EXPECT_EQ(result, 0); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall019 + * @tc.desc: Test the speed of transferring raw data by proxy + * @tc.type: PERF + * @tc.require: SR000D48A5 + */ +HWTEST_F(DbinderTest, DbinderRemoteCall019, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_RAW_DATA_002); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to transfer raw data with different size. + * @tc.expected: step2.Remote calls succeed and return the size of raw data. + */ + int result; + int64_t startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + result = testService->ProxyTransRawData(rawData10K); + EXPECT_EQ(result, 0); + } + int64_t finishTime = GetCurrentTime(); + float speed = GetSpeed(finishTime - startTime, rawData10K, MULTIPLEX_TIMES); + printf("Transfer 10K raw data with speed of %.2fk/s.\n", speed); + + startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + result = testService->ProxyTransRawData(rawData100K); + EXPECT_EQ(result, 0); + } + finishTime = GetCurrentTime(); + speed = GetSpeed(finishTime - startTime, rawData100K, MULTIPLEX_TIMES); + printf("Transfer 100K raw data with speed of %.2fk/s.\n", speed); + + startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + result = testService->ProxyTransRawData(rawData1M); + EXPECT_EQ(result, 0); + } + finishTime = GetCurrentTime(); + speed = GetSpeed(finishTime - startTime, rawData1M, MULTIPLEX_TIMES); + printf("Transfer 1M raw data with speed of %.2fk/s.\n", speed); + + startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + result = testService->ProxyTransRawData(rawData10M); + EXPECT_EQ(result, 0); + } + finishTime = GetCurrentTime(); + speed = GetSpeed(finishTime - startTime, rawData10M, MULTIPLEX_TIMES); + printf("Transfer 10M raw data with speed of %.2fk/s.\n", speed); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall020 + * @tc.desc: Verify it is stable to transfer raw data + * @tc.type: FUNC + * @tc.require: SR000D48A5 + */ +HWTEST_F(DbinderTest, DbinderRemoteCall020, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_RAW_DATA_003); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to transfer raw data with different size. + * @tc.expected: step2.Remote calls succeed and return the size of raw data. + */ + int result; + for (int i = 0; i < REPEAT_RAW_DATA_TIMES; i++) { + result = testService->ProxyTransRawData(rawData10M); + EXPECT_EQ(result, 0); + } + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall021 + * @tc.desc: Verify reply can carry big raw data + * @tc.type: FUNC + * @tc.require: AR000DAPPO + */ +HWTEST_F(DbinderTest, DbinderRemoteCall021, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_RAW_DATA_004); + DBINDER_LOGI(""); + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to ask stub to transfer raw data. + * @tc.expected: step2.Remote call succeed and return 0. + */ + // StubTransRawData cannot ask data less than 2. + int result = testService->StubTransRawData(rawData10M); + EXPECT_EQ(result, 0); + result = testService->StubTransRawData(rawData100M); + EXPECT_EQ(result, 0); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + + +/* + * @tc.name: DbinderRemoteCall022 + * @tc.desc: Test the speed of transferring raw data by stub + * @tc.type: PERF + * @tc.require: AR000DAPPO + */ +HWTEST_F(DbinderTest, DbinderRemoteCall022, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_RAW_DATA_005); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to transfer raw data with different size. + * @tc.expected: step2.Remote calls succeed and return the size of raw data. + */ + int result; + int64_t startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + result = testService->StubTransRawData(rawData10K); + EXPECT_EQ(result, 0); + } + int64_t finishTime = GetCurrentTime(); + float speed = GetSpeed(finishTime - startTime, rawData10K, MULTIPLEX_TIMES); + printf("Receive 10K raw data with speed of %.2fk/s.\n", speed); + + startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + result = testService->StubTransRawData(rawData100K); + EXPECT_EQ(result, 0); + } + finishTime = GetCurrentTime(); + speed = GetSpeed(finishTime - startTime, rawData100K, MULTIPLEX_TIMES); + printf("Receive 100K raw data with speed of %.2fk/s.\n", speed); + + startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + result = testService->StubTransRawData(rawData1M); + EXPECT_EQ(result, 0); + } + finishTime = GetCurrentTime(); + speed = GetSpeed(finishTime - startTime, rawData1M, MULTIPLEX_TIMES); + printf("Receive 1M raw data with speed of %.2fk/s.\n", speed); + + startTime = GetCurrentTime(); + for (int i = 0; i < MULTIPLEX_TIMES; i++) { + result = testService->StubTransRawData(rawData10M); + EXPECT_EQ(result, 0); + } + finishTime = GetCurrentTime(); + speed = GetSpeed(finishTime - startTime, rawData10M, MULTIPLEX_TIMES); + printf("Receive 10M raw data with speed of %.2fk/s.\n", speed); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall023 + * @tc.desc: Verify it is stable to transfer raw data by stub + * @tc.type: FUNC + * @tc.require: AR000DAPPO + */ +HWTEST_F(DbinderTest, DbinderRemoteCall023, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_RAW_DATA_006); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to transfer raw data with different size. + * @tc.expected: step2.Remote calls succeed and return the size of raw data. + */ + int result; + for (int i = 0; i < REPEAT_RAW_DATA_TIMES; i++) { + result = testService->StubTransRawData(rawData10M); + EXPECT_EQ(result, 0); + } + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +#ifndef CONFIG_STANDARD_SYSTEM +/* + * @tc.name: DbinderRemoteCall024 + * @tc.desc: trace test + * @tc.type: FUNC + * @tc.require: SR000CPN5H AR000CPN5I AR000CPN5J + */ +HWTEST_F(DbinderTest, DbinderRemoteCall024, TestSize.Level3) +{ + DBINDER_LOGI(""); + SetCurrentTestCase(DBINDER_TEST_TRACE_001); + HiTraceId traceId = HiTrace::Begin("rpc hitrace", 0); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to transfer trace id. + * @tc.expected: step2.Remote calls succeed and trace id equal local trace id. + */ + uint64_t childId = 0; + int result = testService->GetChildId(childId); + EXPECT_EQ(result, 0); + EXPECT_EQ(childId, traceId.GetChainId()); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} +#endif + +/* + * @tc.name: DbinderRemoteCall025 + * @tc.desc: Test trans stub object + * @tc.type: PERF + * @tc.require: SR000CQSAB AR000DAPPM + */ +HWTEST_F(DbinderTest, DbinderRemoteCall025, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_TRANS_STUB_001); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a local binder object and a proxy pointing to remote stub. + * @tc.expected: step1.Get both objects successfully. + */ + sptr object = new DBinderTestService(); + ASSERT_TRUE(object != nullptr); + sptr remoteObject = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(remoteObject != nullptr); + + sptr remoteTestService = iface_cast(remoteObject); + ASSERT_TRUE(remoteTestService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to transfer stub object + * @tc.expected: step2.Remote call succeeds. + */ + int reply = 0; + int stubReply = 0; + int result = remoteTestService->TransStubObject(2019, object, reply, stubReply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + EXPECT_EQ(stubReply, 2019); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall026 + * @tc.desc: Verify it is stable to transfer raw data by stub + * @tc.type: FUNC + * @tc.require: AR000DHOVU SR000DHOVT + */ +HWTEST_F(DbinderTest, DbinderRemoteCall026, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_FLUSH_COMMAND_001); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a local binder object and a proxy pointing to remote stub. + * @tc.expected: step1.Get both objects successfully. + */ + sptr object = new DBinderTestService(); + ASSERT_TRUE(object != nullptr); + sptr remoteObject = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(remoteObject != nullptr); + + sptr remoteTestService = iface_cast(remoteObject); + ASSERT_TRUE(remoteTestService != nullptr); + + /* + * @tc.steps: step2.Use the proxy object to flush commands + * @tc.expected: step2.Remote call succeeds. + */ + int result = remoteTestService->FlushAsyncCommands(MULTIPLEX_TIMES, rawData10K); + EXPECT_EQ(result, 0); + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall027 + * @tc.desc: Death notice for anonymous objects + * @tc.type: FUNC + * @tc.require: SR000DP5BC + */ +HWTEST_F(DbinderTest, DbinderRemoteCall027, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_DEATH_RECIPIENT_007); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Get two anonymous objects. + * @tc.expected: step2.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr proxy1 = testService->GetRemoteObject(IDBinderTestService::FIRST_OBJECT); + ASSERT_TRUE(proxy1 != nullptr); + + sptr proxy2 = testService->GetRemoteObject(IDBinderTestService::SECOND_OBJECT); + ASSERT_TRUE(proxy2 != nullptr); + + sptr remoteTestService1 = iface_cast(proxy1); + ASSERT_TRUE(remoteTestService1 != nullptr); + + sptr remoteTestService2 = iface_cast(proxy2); + ASSERT_TRUE(remoteTestService2 != nullptr); + + /* + * @tc.steps: step3.Use the proxy object to invoke remote function. + * @tc.expected: step3.Remote call succeeds and returns 0. + */ + int reply; + int result = remoteTestService1->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + result = remoteTestService2->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + /* + * @tc.steps: step4.Add death recipient. + * @tc.expected: step4.Register death notification successfully. + */ + sptr deathRecipient1(new DBinderTestDeathRecipient()); + bool ret = proxy1->AddDeathRecipient(deathRecipient1); + ASSERT_TRUE(ret == true); + + sptr deathRecipient2(new DBinderTestDeathRecipient()); + ret = proxy2->AddDeathRecipient(deathRecipient2); + ASSERT_TRUE(ret == true); + + /* + * @tc.steps: step5.Stop remote service. Wait 10s, then check death notification. + * @tc.expected: step5.Stop it successfully, and receive death notification. + */ + std::string command = "KILL"; + std::string cmdArgs = "server"; + std::string expectValue = "0"; + ret = RunCmdOnAgent(AGENT_NO::ONE, command, cmdArgs, expectValue); + EXPECT_EQ(ret, true); + EXPECT_EQ(GetReturnVal(), 0); + + // wait for killing remote service + sleep(10); + EXPECT_EQ(DBinderTestDeathRecipient::GotDeathRecipient(), true); + EXPECT_EQ(DBinderTestDeathRecipient::GotDeathRecipient(), true); + DBinderTestDeathRecipient::ClearDeathRecipient(); + printf("Succ! Recv death notification!\n"); + + /* + * @tc.steps: step6.Remove death recipient + * @tc.expected: step6.Fail to remove death recipient + * because when receiving death notification, it remove death recipient automatically. + */ + ret = proxy1->RemoveDeathRecipient(deathRecipient1); + EXPECT_EQ(ret, false); + + ret = proxy2->RemoveDeathRecipient(deathRecipient2); + EXPECT_EQ(ret, false); + + /* + * @tc.steps: step7.Restart remote service and wait 10s. + * @tc.expected: step7.Restart it successfully. + */ + std::string restartCommand = "RESTART"; + ret = RunCmdOnAgent(AGENT_NO::ONE, restartCommand, cmdArgs, expectValue); + EXPECT_EQ(ret, true); + EXPECT_EQ(GetReturnVal(), 0); + + // wait for restarting server + sleep(10); + + /* + * @tc.steps: step8.Get a proxy (called testService2) from remote server. + * @tc.expected: step8.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object2 = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object2 != nullptr); + + sptr testService2 = iface_cast(object2); + ASSERT_TRUE(testService2 != nullptr); + + /* + * @tc.steps: step9.Use the proxy object to invoke remote function. + * @tc.expected: step9.Remote call succeeds and returns 0. + */ + result = testService2->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + object = nullptr; + testService = nullptr; + object2 = nullptr; + testService2 = nullptr; + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall028 + * @tc.desc: Death notice for anonymous objects + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA + */ +HWTEST_F(DbinderTest, DbinderRemoteCall028, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_015); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + /* + * @tc.steps: step2.Get two anonymous objects. + * @tc.expected: step2.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr proxy1 = testService->GetRemoteObject(IDBinderTestService::FIRST_OBJECT); + ASSERT_TRUE(proxy1 != nullptr); + + sptr proxy2 = testService->GetRemoteObject(IDBinderTestService::FIRST_OBJECT); + ASSERT_TRUE(proxy2 != nullptr); + + sptr remoteTestService1 = iface_cast(proxy1); + ASSERT_TRUE(remoteTestService1 != nullptr); + + sptr remoteTestService2 = iface_cast(proxy2); + ASSERT_TRUE(remoteTestService2 != nullptr); + + /* + * @tc.steps: step3.Use the proxy object to invoke remote function. + * @tc.expected: step3.Remote call succeeds and returns 0. + */ + int reply; + int result = remoteTestService1->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + result = remoteTestService2->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + testService->ClearRemoteDecTimes(); + + proxy1 = nullptr; + remoteTestService1 = nullptr; + EXPECT_EQ(testService->GetRemoteDecTimes(), 1); + + proxy2 = nullptr; + remoteTestService2 = nullptr; + EXPECT_EQ(testService->GetRemoteDecTimes(), 2); + + object = nullptr; + testService = nullptr; + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +/* + * @tc.name: DbinderRemoteCall029 + * @tc.desc: Death notice for anonymous objects + * @tc.type: FUNC + * @tc.require: SR000CS1C8/SR000CS1CA + */ +HWTEST_F(DbinderTest, DbinderRemoteCall029, TestSize.Level3) +{ + SetCurrentTestCase(DBINDER_TEST_REMOTE_CALL_016); + DBINDER_LOGI(""); + + /* + * @tc.steps: step1.Get a proxy (called testService) from remote server. + * @tc.expected: step1.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr object = manager_->GetSystemAbility(RPC_TEST_SERVICE, serverId_); + ASSERT_TRUE(object != NULL); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != NULL); + + /* + * @tc.steps: step2.Get two anonymous objects. + * @tc.expected: step2.Get the proxy successfully, and the proxy points to remote stub. + */ + sptr proxy1 = testService->GetRemoteObject(IDBinderTestService::SECOND_OBJECT); + ASSERT_TRUE(proxy1 != nullptr); + + sptr proxy2 = testService->GetRemoteObject(IDBinderTestService::SECOND_OBJECT); + ASSERT_TRUE(proxy2 != nullptr); + ASSERT_TRUE(proxy2 == proxy1); + + sptr remoteTestService1 = iface_cast(proxy1); + ASSERT_TRUE(remoteTestService1 != nullptr); + + sptr remoteTestService2 = iface_cast(proxy2); + ASSERT_TRUE(remoteTestService2 != nullptr); + + /* + * @tc.steps: step3.Use the proxy object to invoke remote function. + * @tc.expected: step3.Remote call succeeds and returns 0. + */ + int reply; + int result = remoteTestService1->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + result = remoteTestService2->ReverseInt(2019, reply); + EXPECT_EQ(result, 0); + EXPECT_EQ(reply, 9102); + + testService->ClearRemoteDecTimes(); + + proxy1 = nullptr; + proxy2 = nullptr; + remoteTestService1 = nullptr; + remoteTestService2 = nullptr; + sleep(1); + EXPECT_EQ(testService->GetRemoteDecTimes(), 1); + + object = nullptr; + testService = nullptr; + + SetCurrentTestCase(DBINDER_TEST_INIT); +} + +int main(int argc, char *argv[]) +{ + g_pDistributetestEnv = new DistributeTestEnvironment("major.desc"); + testing::AddGlobalTestEnvironment(g_pDistributetestEnv); + testing::GTEST_FLAG(output) = "xml:./"; + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/services/dbinder/test/distributedtest/src/dbinder_service_test_helper.cpp b/services/dbinder/test/distributedtest/src/dbinder_service_test_helper.cpp new file mode 100755 index 00000000..ed8e4b9c --- /dev/null +++ b/services/dbinder/test/distributedtest/src/dbinder_service_test_helper.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_service_test_helper.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ipc_types.h" +#include "hilog/log.h" +#include "log_tags.h" + +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "DbinderTestHelper" }; +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +pid_t GetPidByName(std::string taskName) +{ + DIR *dir = nullptr; + struct dirent *ptr = nullptr; + FILE *fp = nullptr; + char filepath[PATH_LENGTH]; + char curTaskName[PATH_LENGTH]; + char buf[BUF_SIZE]; + pid_t pid = INVALID_PID; + + dir = opendir("/proc"); + if (dir == nullptr) { + return pid; + } + while ((ptr = readdir(dir)) != nullptr) { + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) + continue; + if (DT_DIR != ptr->d_type) { + continue; + } + + if (sprintf_s(filepath, sizeof(filepath), "/proc/%s/status", ptr->d_name) <= EOK) { + DBINDER_LOGI("sprintf_s fail"); + closedir(dir); + return INVALID_PID; + } + + fp = fopen(filepath, "r"); + if (fp != nullptr) { + if (fgets(buf, BUF_SIZE - 1, fp) == nullptr) { + fclose(fp); + continue; + } + if (sscanf_s(buf, "%*s %s", curTaskName, sizeof(curTaskName)) <= EOK) { + DBINDER_LOGI("sscanf fail"); + } + + if (!strcmp(taskName.c_str(), curTaskName)) { + if (sscanf_s(ptr->d_name, "%d", &pid) <= EOK) { + DBINDER_LOGI("sscanf fail"); + } + } + fclose(fp); + } + } + closedir(dir); + return pid; +} + +int GetChildPids(std::vector &childPids) +{ + pid_t current = getpid(); + DBINDER_LOGI("current pid %{public}d", current); + const std::string TASK_PATH = "/proc/" + std::to_string(current) + "/task"; + DIR *dir = nullptr; + struct dirent *ptr = nullptr; + + dir = opendir(TASK_PATH.c_str()); + if (dir != nullptr) { + while ((ptr = readdir(dir)) != nullptr) { + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) { + continue; + } + if (DT_DIR != ptr->d_type) { + continue; + } + + pid_t child = std::stoi(ptr->d_name); + if (child == current) { + continue; + } + childPids.push_back(child); + DBINDER_LOGI("child pid %{public}d", child); + } + closedir(dir); + } + + return ERR_NONE; +} + +pid_t StartExecutable(std::string name, std::string args) +{ + const char *ldLibraryPath = getenv("LD_LIBRARY_PATH"); + if (ldLibraryPath != nullptr) { + unsetenv("LD_LIBRARY_PATH"); + } + pid_t pid = GetPidByName(name); + if (pid != INVALID_PID) { + DBINDER_LOGI("test.service is already started, do nothing"); + return pid; + } + + std::string cmd1 = "chmod +x /data/test/" + name; + int res = system(cmd1.c_str()); + DBINDER_LOGI("%{public}s res = %d, errno = %{public}d %{public}s", cmd1.c_str(), res, errno, strerror(errno)); + + std::string cmd2 = "/data/test/" + name + " " + args + "&"; + res = system(cmd2.c_str()); + DBINDER_LOGI("%{public}s res = %{public}d", cmd2.c_str(), res); + + if (ldLibraryPath != nullptr) { + setenv("LD_LIBRARY_PATH", ldLibraryPath, 1); + } + res = 0; + while (pid == INVALID_PID && res < 10) { // 10:try-time to wait for exe start + pid = GetPidByName(name); + DBINDER_LOGI("StartExecutable pid = %{public}d && name = %{public}s", pid, name.c_str()); + usleep(100 * 1000); // 100:time-length 1000:time-unit + res++; + } + + DBINDER_LOGI("start %{public}s done", name.c_str()); + return GetPidByName(name); +} + +void StopExecutable(pid_t pid) +{ + kill(pid, SIGKILL); +} + +void StopExecutable(std::string name) +{ + pid_t pid = GetPidByName(name); + DBINDER_LOGI("StopExecutable %{public}s pid = %{public}d, prepare to kill it", name.c_str(), pid); + + if (pid != INVALID_PID) { + DBINDER_LOGI("%{public}s pid = %{public}d, kill it", name.c_str(), pid); + kill(pid, SIGKILL); + } +} + +int StartDBinderServiceSARegistry() +{ + pid_t registryPid = GetPidByName(SYSTEM_ABILITY_MANAGER_NAME); + if (registryPid != -1) { + DBINDER_LOGI("SYSTEM_ABILITY_MANAGER_NAME Already Started pid=%{public}d", registryPid); + return registryPid; + } + StartExecutable(SYSTEM_ABILITY_MANAGER_NAME); + usleep(200 * 1000); // 100:200-length 1000:time-unit + DBINDER_LOGI("Start SYSTEM_ABILITY_MANAGER_NAME done"); + return ERR_NONE; +} + +void StopDBinderServiceSARegistry() +{ + StopExecutable(SYSTEM_ABILITY_MANAGER_NAME); +} + +void StartDBinderServiceTestService() +{ + pid_t pid = StartExecutable(DBINDER_TEST_SERVICE_NAME); + DBINDER_LOGE("DBINDER_TEST_SERVICE_NAME pid : %{public}d", pid); + + pid = StartExecutable(DBINDER_TEST_SERVICE_NAME_SECOND); + DBINDER_LOGE("DBINDER_TEST_SERVICE_NAME_SECOND pid : %{public}d", pid); +} + +void StopDBinderServiceTestService() +{ + StopExecutable(DBINDER_TEST_SERVICE_NAME); + DBINDER_LOGE("Stop DBINDER_TEST_SERVICE_NAME"); + + StopExecutable(DBINDER_TEST_SERVICE_NAME_SECOND); + DBINDER_LOGE("Stop DBINDER_TEST_SERVICE_NAME_SECOND"); +} + +int SetCurrentTestCase(int caseNum) +{ + if (caseNum > DBINDER_TEST_START && caseNum < DBINDER_TEST_END) { + printf("SetCurrentTestCase to : %d\n", caseNum); + return g_currentTestCase = caseNum; + } + printf("SetCurrentTestCase to : %d\n", DBINDER_TEST_INIT); + return DBINDER_TEST_INIT; +} + +int GetCurrentTestCase(void) +{ + if (g_currentTestCase > DBINDER_TEST_START && g_currentTestCase < DBINDER_TEST_END) { + printf("GetCurrentTestCase is : %d\n", g_currentTestCase); + return g_currentTestCase; + } + printf("GetCurrentTestCase is : %d\n", DBINDER_TEST_INIT); + return DBINDER_TEST_INIT; +} + +int64_t GetCurrentTime() +{ + struct timeval timeInterval = {}; + gettimeofday(&timeInterval, nullptr); + return timeInterval.tv_sec * SECOND_TO_MS + timeInterval.tv_usec / SECOND_TO_MS; +} + +float GetSpeed(int64_t timeInterval, int size, int times) +{ + if (timeInterval == 0) { + return 0; + } + float dataSize { times * size }; + float costTime { timeInterval }; + float speed = dataSize / costTime; + return speed * SECOND_TO_MS / KB_TO_B; +} diff --git a/services/dbinder/test/distributedtest/src/dbinder_test_agent.cpp b/services/dbinder/test/distributedtest/src/dbinder_test_agent.cpp new file mode 100755 index 00000000..eb95f237 --- /dev/null +++ b/services/dbinder/test/distributedtest/src/dbinder_test_agent.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 +#include +#include "hilog/log.h" +#include "dbinder_test_service.h" +#include "ipc_skeleton.h" +#include "distributed_agent.h" +#include "dbinder_service_test_helper.h" +#include "log_tags.h" +#include "softbus_bus_center.h" + +using namespace testing; +using namespace OHOS; +using namespace OHOS::DistributeSystemTest; +using namespace OHOS::HiviewDFX; + +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "DbinderTestAgent" }; +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +class DbinderTestAgent : public DistributedAgent { +public: + DbinderTestAgent(); + ~DbinderTestAgent(); + virtual bool SetUp(); + virtual bool TearDown(); + virtual int OnProcessMsg(const std::string &strMsg, int len, std::string &strReturnValue, int returnBufLen); + virtual int OnProcessCmd(const std::string &strCommand, int cmdLen, const std::string &strArgs, int argsLen, + const std::string &strExpectValue, int expectValueLen); + +private: + std::string localUdid; + void KillService() const; + void RestartService() const; +}; + +DbinderTestAgent::DbinderTestAgent() +{ + std::string pkgName = "dbinderService"; + NodeBasicInfo nodeBasicInfo; + if (GetLocalNodeDeviceInfo(pkgName.c_str(), &nodeBasicInfo) != 0) { + DBINDER_LOGE("Get local node device info failed"); + return; + } + std::string networkId(nodeBasicInfo.networkId); + localUdid = networkId; +} + +DbinderTestAgent::~DbinderTestAgent() {} + +bool DbinderTestAgent::SetUp() +{ + DBINDER_LOGI("enter SetUp"); + StartDBinderServiceTestService(); + return true; +} + +bool DbinderTestAgent::TearDown() +{ + DBINDER_LOGI("enter TearDown"); + KillService(); + return true; +} + +// from test framework +int DbinderTestAgent::OnProcessMsg(const std::string &strMsg, int len, std::string &strReturnValue, int returnValueLen) +{ + std::string msg = "Ask Device ID"; + if (strncmp(msg.c_str(), strMsg.c_str(), len) == 0) { + strReturnValue = localUdid; + returnValueLen = strlen(localUdid.c_str()); + return returnValueLen; + } else { + return DistributedAgent::OnProcessMsg(strMsg, len, strReturnValue, returnValueLen); + } +} + +// from test framework +int DbinderTestAgent::OnProcessCmd(const std::string &strCommand, int cmdLen, const std::string &strArgs, int argsLen, + const std::string &strExpectValue, int expectValueLen) +{ + DBINDER_LOGI("enter OnProcessCmd"); + if (strCommand == "KILL") { + DBINDER_LOGI("strCommand = %{public}s, strArgs = %{public}s", strCommand.c_str(), strArgs.c_str()); + KillService(); + } else if (strCommand == "RESTART") { + DBINDER_LOGI("strCommand = %{public}s, strArgs = %{public}s", strCommand.c_str(), strArgs.c_str()); + RestartService(); + } else { + return DistributedAgent::OnProcessCmd(strCommand, cmdLen, strArgs, argsLen, strExpectValue, expectValueLen); + } + + return 0; +} + +void DbinderTestAgent::KillService() const +{ + DBINDER_LOGI("enter KillService"); + StopDBinderServiceTestService(); +} + +void DbinderTestAgent::RestartService() const +{ + DBINDER_LOGI("enter RestartService"); + StartDBinderServiceTestService(); +} + +int main() +{ + // Test agent main function + DbinderTestAgent obj; + if (obj.SetUp()) { + obj.Start("agent.desc"); + obj.Join(); + } else { + DBINDER_LOGE("Init environment failed."); + } + if (obj.TearDown()) { + return 0; + } else { + DBINDER_LOGE("Clear environment failed."); + return -1; + } +} diff --git a/services/dbinder/test/distributedtest/src/dbinder_test_server_main.cpp b/services/dbinder/test/distributedtest/src/dbinder_test_server_main.cpp new file mode 100755 index 00000000..da905d47 --- /dev/null +++ b/services/dbinder/test/distributedtest/src/dbinder_test_server_main.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_test_service.h" +#include "ipc_skeleton.h" +#include "hilog/log.h" +#include "log_tags.h" + +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LG_LABEL = { LOG_CORE, LOG_ID_RPC, "DBinderTestService" }; + +int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) +{ + DBinderTestService::Instantiate(); + + HiLog::Info(LG_LABEL, "DBinderTestService-main call StartThreadPool"); + + while (1) {}; +} diff --git a/services/dbinder/test/distributedtest/src/dbinder_test_service.cpp b/services/dbinder/test/distributedtest/src/dbinder_test_service.cpp new file mode 100755 index 00000000..6153356e --- /dev/null +++ b/services/dbinder/test/distributedtest/src/dbinder_test_service.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_test_service.h" +#include +#include +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "log_tags.h" + +static std::string g_dbinderTestServerName = "dbinderTestServer"; + +namespace OHOS { +using namespace OHOS::HiviewDFX; +int DBinderTestService::destructTimes_ = 0; +std::mutex DBinderTestService::destructTimesMutex_; + +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "DbinderTest" }; +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +#define DBINDER_LOGI(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +static int Reverse(int x) +{ + int result = 0; + while (x != 0) { + result = result * 10 + x % 10; + x = x / 10; + } + return result; +} + +DBinderTestService::~DBinderTestService() +{ + DBINDER_LOGI("DBinderTestService finish"); + std::lock_guard lockGuard(destructTimesMutex_); + + destructTimes_++; +} + +int DBinderTestService::Instantiate() +{ + DBINDER_LOGI("enter %{public}s", __func__); + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (saMgr == nullptr) { + DBINDER_LOGE("%{public}s:fail to instantiate", __func__); + return -ENODEV; + } + + ISystemAbilityManager::SAExtraProp saExtra; + saExtra.isDistributed = true; +#ifdef DBINDER_TEST_SECOND + int result = saMgr->AddSystemAbility(RPC_TEST_SERVICE2, new DBinderTestService(), saExtra); +#else + int result = saMgr->AddSystemAbility(RPC_TEST_SERVICE, new DBinderTestService(), saExtra); +#endif + DBINDER_LOGE("%{public}s: add TestService result=%{public}d", __func__, result); + + return result; +} + +int DBinderTestService::ReverseInt(int data, int &rep) +{ + DBINDER_LOGI("enter %{public}s", __func__); + rep = Reverse(data); + DBINDER_LOGI("%{public}s:read from client data = %{public}d", __func__, data); + return ERR_NONE; +} + +int DBinderTestService::ReverseIntDelay(int data, int &rep) +{ + DBINDER_LOGI("enter %{public}s", __func__); + rep = Reverse(data); + DBINDER_LOGI("%{public}s:read from client data = %{public}d", __func__, data); + return ERR_NONE; +} + +int DBinderTestService::Delay(int data, int &rep) +{ + DBINDER_LOGI("enter %{public}s", __func__); + rep = data; + int i = 1; + while (i <= data) { + sleep(1); + DBINDER_LOGI("sleep loop : %{public}d", i); + i++; + } + DBINDER_LOGE("%{public}s:read from client data = %{public}d", __func__, data); + return ERR_NONE; +} + +int DBinderTestService::PingService(std::u16string &serviceName) +{ + std::u16string localServiceName = GetDescriptor(); + if (localServiceName.compare(serviceName) != 0) { + DBINDER_LOGE("ServiceName is not equal"); + return -1; + } + return ERR_NONE; +} + +int DBinderTestService::TransProxyObject(int data, sptr &transObject, int operation, int &rep, + int &withdrawRes) +{ + DBINDER_LOGI("enter %{public}s", __func__); + return 0; +} + +int DBinderTestService::TransStubObject(int data, sptr &transObject, int &rep, int &stubRep) +{ + DBINDER_LOGI("enter %{public}s", __func__); + return 0; +} + +int DBinderTestService::TransOversizedPkt(const std::string &dataStr, std::string &repStr) +{ + DBINDER_LOGI("enter %{public}s", __func__); + return 0; +} + +int DBinderTestService::ProxyTransRawData(int length) +{ + DBINDER_LOGI("enter %{public}s", __func__); + return 0; +} + +int DBinderTestService::StubTransRawData(int length) +{ + DBINDER_LOGI("enter %{public}s", __func__); + return 0; +} + +#ifndef CONFIG_STANDARD_SYSTEM +int DBinderTestService::GetChildId(uint64_t &rep) +{ + DBINDER_LOGI("enter %{public}s", __func__); + return 0; +} +#endif + +int DBinderTestService::FlushAsyncCommands(int count, int length) +{ + DBINDER_LOGI("enter %{public}s", __func__); + return 0; +} + +sptr DBinderTestService::GetRemoteObject(int type) +{ + DBINDER_LOGI("DBinderTestService GetRemoteObject"); + if (type == IDBinderTestService::FIRST_OBJECT) { + return new DBinderTestService(); + } + + if (object_ == nullptr) { + object_ = new DBinderTestService(); + return object_; + } else { + sptr node = object_; + object_ = nullptr; + return node; + } +} + +int DBinderTestService::GetRemoteDecTimes() +{ + std::lock_guard lockGuard(destructTimesMutex_); + + DBINDER_LOGI("DBinderTestService GetDestructTimes"); + return destructTimes_; +} + +void DBinderTestService::ClearRemoteDecTimes() +{ + std::lock_guard lockGuard(destructTimesMutex_); + + DBINDER_LOGI("DBinderTestService ClearRemoteDecTimes"); + destructTimes_ = 0; +} +} // namespace OHOS diff --git a/services/dbinder/test/distributedtest/src/dbinder_test_service_skeleton.cpp b/services/dbinder/test/distributedtest/src/dbinder_test_service_skeleton.cpp new file mode 100755 index 00000000..116f4e70 --- /dev/null +++ b/services/dbinder/test/distributedtest/src/dbinder_test_service_skeleton.cpp @@ -0,0 +1,752 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "dbinder_test_service_skeleton.h" +#include +#include "iremote_proxy.h" +#include "ipc_skeleton.h" +#include "ipc_object_proxy.h" + +namespace OHOS { +using namespace OHOS::HiviewDFX; + +#ifndef TITLE +#define TITLE __PRETTY_FUNCTION__ +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "DBinderTestServiceProxy" }; +#define DBINDER_LOGE(fmt, args...) \ + (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) + +// set wait time for raw data +static constexpr int RAW_DATA_TIMEOUT = 300; + +DBinderTestServiceProxy::DBinderTestServiceProxy(const sptr &impl) + : IRemoteProxy(impl) +{} + +int DBinderTestServiceProxy::ReverseInt(int data, int &rep) +{ + DBINDER_LOGE("data = %{public}d", data); + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(data)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + error = Remote()->SendRequest(REVERSEINT, dataParcel, replyParcel, option); + + rep = replyParcel.ReadInt32(); + DBINDER_LOGE("rep = %{public}d, error = %{public}d", rep, error); + return error; +} + +#ifndef CONFIG_STANDARD_SYSTEM +int DBinderTestServiceProxy::GetChildId(uint64_t &rep) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + error = Remote()->SendRequest(TRANS_TRACE_ID, dataParcel, replyParcel, option); + + rep = replyParcel.ReadUint64(); + DBINDER_LOGE("rep = %{public}" PRIu64 ", error = %{public}d", rep, error); + return error; +} +#endif + +int DBinderTestServiceProxy::TransProxyObject(int data, sptr &transObject, int operation, int &rep, + int &withdrawRes) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(data) || !dataParcel.WriteInt32(operation) || + !dataParcel.WriteRemoteObject(transObject)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + error = Remote()->SendRequest(TRANS_OBJECT, dataParcel, replyParcel, option); + + rep = replyParcel.ReadInt32(); + withdrawRes = replyParcel.ReadInt32(); + return error; +} + +int DBinderTestServiceProxy::TransStubObject(int data, sptr &transObject, int &rep, int &stubRep) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(data) || !dataParcel.WriteRemoteObject(transObject)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + error = Remote()->SendRequest(TRANS_STUB_OBJECT, dataParcel, replyParcel, option); + if (error != ERR_NONE) { + DBINDER_LOGE("fail to send stub object"); + return ERR_INVALID_STATE; + } + + rep = replyParcel.ReadInt32(); + + sptr proxy = replyParcel.ReadRemoteObject(); + if (proxy == nullptr) { + DBINDER_LOGE("fail to get remote stub object"); + return ERR_INVALID_STATE; + } + + MessageParcel dataStubParcel, replyStubParcel; + if (!dataStubParcel.WriteInt32(rep)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + error = proxy->SendRequest(REVERSEINT, dataStubParcel, replyStubParcel, option); + if (error != ERR_NONE) { + DBINDER_LOGE("fail to send data info"); + return ERR_INVALID_STATE; + } + + stubRep = replyStubParcel.ReadInt32(); + return error; +} + +sptr DBinderTestServiceProxy::GetRemoteObject(int type) +{ + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(type)) { + DBINDER_LOGE("fail to write parcel"); + return nullptr; + } + + int error = Remote()->SendRequest(GET_REMOTE_STUB_OBJECT, dataParcel, replyParcel, option); + if (error != ERR_NONE) { + DBINDER_LOGE("fail to send data info"); + return nullptr; + } + + sptr proxy = replyParcel.ReadRemoteObject(); + if (proxy == nullptr) { + DBINDER_LOGE("fail to get remote stub object"); + return nullptr; + } + return proxy; +} + +int DBinderTestServiceProxy::GetRemoteDecTimes() +{ + MessageOption option; + MessageParcel dataParcel, replyParcel; + + int error = Remote()->SendRequest(GET_REMOTE_DES_TIMES, dataParcel, replyParcel, option); + if (error != ERR_NONE) { + DBINDER_LOGE("fail to send data info"); + return 0; + } + + return replyParcel.ReadInt32(); +} + +void DBinderTestServiceProxy::ClearRemoteDecTimes() +{ + MessageOption option; + MessageParcel dataParcel, replyParcel; + + int error = Remote()->SendRequest(CLEAR_REMOTE_DES_TIMES, dataParcel, replyParcel, option); + if (error != ERR_NONE) { + DBINDER_LOGE("fail to send data info"); + } +} + +int DBinderTestServiceProxy::TransOversizedPkt(const std::string &dataStr, std::string &repStr) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteString(dataStr)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + error = Remote()->SendRequest(TRANS_OVERSIZED_PKT, dataParcel, replyParcel, option); + + repStr = replyParcel.ReadString(); + return error; +} + +int DBinderTestServiceProxy::ProxyTransRawData(int length) +{ + MessageParcel dataParcel, replyParcel; + + MessageOption option; + option.SetWaitTime(RAW_DATA_TIMEOUT); + int waitTime = option.GetWaitTime(); + DBINDER_LOGE("data length = %{public}d, wait time = %{public}d", length, waitTime); + + if (length <= 1) { + DBINDER_LOGE("length should > 1, length is %{public}d", length); + return ERR_INVALID_STATE; + } + unsigned char *buffer = new (std::nothrow) unsigned char[length]; + if (buffer == nullptr) { + DBINDER_LOGE("new buffer failed of length = %{public}d", length); + return ERR_INVALID_STATE; + } + buffer[0] = 'a'; + buffer[length - 1] = 'z'; + if (!dataParcel.WriteInt32(length) || !dataParcel.WriteRawData(buffer, length) || !dataParcel.WriteInt32(length)) { + DBINDER_LOGE("fail to write parcel"); + delete[] buffer; + return ERR_INVALID_STATE; + } + delete[] buffer; + int ret = Remote()->SendRequest(TRANS_RAW_DATA, dataParcel, replyParcel, option); + if (ret != ERR_NONE) { + DBINDER_LOGE("fail to send request, ret = %{public}d", ret); + return ret; + } + if (length != replyParcel.ReadInt32()) { + DBINDER_LOGE("reply wrong length"); + ret += ERR_TRANSACTION_FAILED; + } + return ret; +} + +int DBinderTestServiceProxy::StubTransRawData(int length) +{ + MessageParcel dataParcel, replyParcel; + + MessageOption option; + option.SetWaitTime(RAW_DATA_TIMEOUT); + int waitTime = option.GetWaitTime(); + DBINDER_LOGE("data length = %{public}d, wait time = %{public}d", length, waitTime); + + if (length <= 1) { + DBINDER_LOGE("length should > 1, length is %{public}d", length); + return ERR_INVALID_STATE; + } + + if (!dataParcel.WriteInt32(length)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + int ret = Remote()->SendRequest(RECEIVE_RAW_DATA, dataParcel, replyParcel, option); + if (ret != ERR_NONE) { + DBINDER_LOGE("fail to send request, ret = %{public}d", ret); + return ret; + } + + if (replyParcel.ReadInt32() != length) { + DBINDER_LOGE("reply false data"); + return ERR_INVALID_DATA; + } + + const char *buffer = nullptr; + if ((buffer = reinterpret_cast(replyParcel.ReadRawData(length))) == nullptr) { + DBINDER_LOGE("fail to read raw data, length = %{public}d", length); + return ERR_INVALID_DATA; + } + if (buffer[0] != 'a' || buffer[length - 1] != 'z') { + DBINDER_LOGE("received raw data is wrong, length = %{public}d", length); + return ERR_INVALID_DATA; + } + + if (replyParcel.ReadInt32() != length) { + DBINDER_LOGE("fail to read length after raw data, length = %{public}d", length); + return ERR_INVALID_DATA; + } + + return ERR_NONE; +} + +int DBinderTestServiceProxy::FlushAsyncCommands(int count, int length) +{ + int ret; + MessageOption option = { MessageOption::TF_ASYNC }; + MessageParcel dataParcel, replyParcel; + std::string dataStr(length, 'a'); + if (!dataParcel.WriteString(dataStr)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + for (int i = 0; i < count; i++) { + ret = Remote()->SendRequest(TRANS_OVERSIZED_PKT, dataParcel, replyParcel, option); + if (ret != ERR_NONE) { + DBINDER_LOGE("fail to send request when count = %{public}d ret = %{public}d", i, ret); + return ret; + } + } + ret = IPCSkeleton::FlushCommands(this->AsObject()); + return ret; +} + +int DBinderTestServiceProxy::ReverseIntNullReply(int data, int &rep) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(data)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + error = Remote()->SendRequest(REVERSEINT, dataParcel, replyParcel, option); + + rep = replyParcel.ReadInt32(); + return error; +} + +int DBinderTestServiceProxy::ReverseIntVoidData(int data, int &rep) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + // do not write data to parcel; + error = Remote()->SendRequest(REVERSEINT, dataParcel, replyParcel, option); + + rep = replyParcel.ReadInt32(); + return error; +} + +int DBinderTestServiceProxy::ReverseIntDelay(int data, int &rep) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(data)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + error = Remote()->SendRequest(REVERSEINTDELAY, dataParcel, replyParcel, option); + + rep = replyParcel.ReadInt32(); + return error; +} + +int DBinderTestServiceProxy::Delay(int data, int &rep) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(data)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + error = Remote()->SendRequest(ONLY_DELAY, dataParcel, replyParcel, option); + + rep = replyParcel.ReadInt32(); + return error; +} + +int DBinderTestServiceProxy::ReverseIntDelayAsync(int data, int &rep) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(data) || + // 2:for data update check, only in test case + !replyParcel.WriteInt32(data * 2)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + error = Remote()->SendRequest(REVERSEINTDELAY, dataParcel, replyParcel, option); + + rep = replyParcel.ReadInt32(); + return error; +} + +int DBinderTestServiceProxy::PingService(std::u16string &serviceName) +{ + int error; + MessageOption option; + MessageParcel dataParcel, replyParcel; + DBINDER_LOGE("TestServiceProxy:PingService"); + if (!dataParcel.WriteString16(serviceName.data())) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + error = Remote()->SendRequest(REVERSEINT, dataParcel, replyParcel, option); + replyParcel.ReadInt32(); + return error; +} + +pid_t DBinderTestServiceStub::g_lastCallingPid = 0; +pid_t DBinderTestServiceStub::g_lastCallinguid = 0; + +pid_t DBinderTestServiceStub::GetLastCallingPid() +{ + return g_lastCallingPid; +} + +uid_t DBinderTestServiceStub::GetLastCallingUid() +{ + return g_lastCallinguid; +} + +int DBinderTestServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + DBINDER_LOGE("TestServiceStub::OnReceived, cmd = %{public}d", code); + g_lastCallingPid = IPCSkeleton::GetCallingPid(); + g_lastCallinguid = IPCSkeleton::GetCallingUid(); + switch (code) { + case REVERSEINT: { + return OnReverseInt(data, reply); + } + case REVERSEINTDELAY: { + return OnReverseIntDelay(data, reply); + } + case PING_SERVICE: { + return OnPingService(data, reply); + } + case ONLY_DELAY: { + return OnDelay(data, reply); + } + case TRANS_OBJECT: { + return OnReceivedObject(data, reply); + } + case TRANS_STUB_OBJECT: { + return OnReceivedStubObject(data, reply); + } + case TRANS_OVERSIZED_PKT: { + return OnReceivedOversizedPkt(data, reply); + } + case TRANS_RAW_DATA: { + return OnReceivedRawData(data, reply); + } + case RECEIVE_RAW_DATA: { + return OnSentRawData(data, reply); + } +#ifndef CONFIG_STANDARD_SYSTEM + case TRANS_TRACE_ID: { + return OnGetChildId(data, reply); + } +#endif + case GET_REMOTE_STUB_OBJECT: { + return OnReceivedGetStubObject(data, reply); + } + case GET_REMOTE_DES_TIMES: { + return OnReceivedGetDecTimes(data, reply); + } + case CLEAR_REMOTE_DES_TIMES: { + return OnReceivedClearDecTimes(data, reply); + } + default: { + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + } +} + +int DBinderTestServiceStub::ReverseIntDelayAsync(int data, int &rep) +{ + HiLog::Error(LABEL, "%{public}s: not valid operate", __func__); + return 0; +} + +int DBinderTestServiceStub::OnReverseInt(MessageParcel &data, MessageParcel &reply) +{ + int result; + int32_t reqData = data.ReadInt32(); + int ret = ReverseInt(reqData, result); + HiLog::Info(LABEL, "ReverseInt result = %{public}d", result); + if (!reply.WriteInt32(result)) { + DBINDER_LOGE("fail to write parcel"); + ret = ERR_INVALID_STATE; + } + + return ret; +} + +#ifndef CONFIG_STANDARD_SYSTEM +int DBinderTestServiceStub::OnGetChildId(MessageParcel &data, MessageParcel &reply) +{ + uint64_t reqData = HiTrace::GetId().GetChainId(); + if (!reply.WriteUint64(reqData)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + DBINDER_LOGE("before reset uid = %{public}d, callerId = %{public}s, localId = %{public}s, islocal = %{public}d", + IPCSkeleton::GetCallingUid(), IPCSkeleton::GetCallingDeviceID().c_str(), + IPCSkeleton::GetLocalDeviceID().c_str(), IPCSkeleton::IsLocalCalling()); + std::string token = IPCSkeleton::ResetCallingIdentity(); + + DBINDER_LOGE("before set uid = %{public}d, callerId = %{public}s, localId = %{public}s, islocal = %{public}d", + IPCSkeleton::GetCallingUid(), IPCSkeleton::GetCallingDeviceID().c_str(), + IPCSkeleton::GetLocalDeviceID().c_str(), IPCSkeleton::IsLocalCalling()); + if (!IPCSkeleton::SetCallingIdentity(token)) { + DBINDER_LOGE("Set Calling Identity fail"); + } + + DBINDER_LOGE("after set uid = %{public}d, callerId = %{public}s, localId = %{public}s, islocal = %{public}d", + IPCSkeleton::GetCallingUid(), IPCSkeleton::GetCallingDeviceID().c_str(), + IPCSkeleton::GetLocalDeviceID().c_str(), IPCSkeleton::IsLocalCalling()); + return ERR_NONE; +} +#endif + +int DBinderTestServiceStub::OnReverseIntDelay(MessageParcel &data, MessageParcel &reply) +{ + int result; + int32_t reqData = data.ReadInt32(); + int ret = ReverseIntDelay(reqData, result); + if (!reply.WriteInt32(result)) { + DBINDER_LOGE("fail to write parcel"); + ret = ERR_INVALID_STATE; + } + + return ret; +} + +int DBinderTestServiceStub::OnPingService(MessageParcel &data, MessageParcel &reply) +{ + std::u16string serviceName = data.ReadString16(); + int ret = PingService(serviceName); + HiLog::Info(LABEL, "%s:PingService: ret=%d", __func__, ret); + if (!reply.WriteInt32(ret)) { + DBINDER_LOGE("fail to write parcel"); + ret = ERR_INVALID_STATE; + } + + return ret; +} + +int DBinderTestServiceStub::OnDelay(MessageParcel &data, MessageParcel &reply) +{ + int result; + int32_t reqData = data.ReadInt32(); + int ret = Delay(reqData, result); + if (!reply.WriteInt32(result)) { + DBINDER_LOGE("fail to write parcel"); + ret = ERR_INVALID_STATE; + } + + return ret; +} + +int DBinderTestServiceStub::OnReceivedObject(MessageParcel &data, MessageParcel &reply) +{ + int32_t reqData = data.ReadInt32(); + int32_t operation = data.ReadInt32(); + sptr proxy = data.ReadRemoteObject(); + if (proxy == nullptr) { + DBINDER_LOGE("null proxy"); + return ERR_INVALID_STATE; + } + + // use the received proxy to communicate + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(reqData)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + HiLog::Info(LABEL, "%s:TRANSOBJECT: reqData=%d", __func__, reqData); + int ret = proxy->SendRequest(REVERSEINT, dataParcel, replyParcel, option); + int reqResult = replyParcel.ReadInt32(); + HiLog::Info(LABEL, "%s:TRANSOBJECT: result=%d", __func__, reqResult); + + if (!reply.WriteInt32(reqResult)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + if (operation == SAVE) { + recvProxy_ = proxy; + } + + // received proxy is different from that of last time + if ((operation == WITHDRAW) && (recvProxy_ != proxy)) { + if (!reply.WriteInt32(1)) { + DBINDER_LOGE("fail to write parcel"); + ret = ERR_INVALID_STATE; + } + return ret; + } + + if (!reply.WriteInt32(0)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + return ret; +} + +int DBinderTestServiceStub::OnReceivedStubObject(MessageParcel &data, MessageParcel &reply) +{ + int32_t reqData = data.ReadInt32(); + sptr proxy = data.ReadRemoteObject(); + if (proxy == nullptr) { + DBINDER_LOGE("fail to get proxy"); + return ERR_INVALID_STATE; + } + + MessageOption option; + MessageParcel dataParcel, replyParcel; + if (!dataParcel.WriteInt32(reqData)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + int error = proxy->SendRequest(REVERSEINT, dataParcel, replyParcel, option); + if (error != ERR_NONE) { + DBINDER_LOGE("fail to send data info"); + return ERR_INVALID_STATE; + } + int reqResult = replyParcel.ReadInt32(); + if (!reply.WriteInt32(reqResult)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + if (!reply.WriteRemoteObject(this)) { + DBINDER_LOGE("fail to write parcel stub"); + return ERR_INVALID_STATE; + } + + return error; +} + +int DBinderTestServiceStub::OnReceivedGetStubObject(MessageParcel &data, MessageParcel &reply) +{ + if (!reply.WriteRemoteObject(GetRemoteObject(data.ReadInt32()))) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + return ERR_NONE; +} + +int DBinderTestServiceStub::OnReceivedGetDecTimes(MessageParcel &data, MessageParcel &reply) +{ + if (!reply.WriteInt32(GetRemoteDecTimes())) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + return ERR_NONE; +} + +int DBinderTestServiceStub::OnReceivedClearDecTimes(MessageParcel &data, MessageParcel &reply) +{ + DBINDER_LOGE("OnReceivedClearDecTimes"); + + ClearRemoteDecTimes(); + return ERR_NONE; +} + +int DBinderTestServiceStub::OnReceivedOversizedPkt(MessageParcel &data, MessageParcel &reply) +{ + std::string reqStr = data.ReadString(); + std::string resultStr = reqStr; + if (!reply.WriteString(resultStr)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + return ERR_NONE; +} + +int DBinderTestServiceStub::OnReceivedRawData(MessageParcel &data, MessageParcel &reply) +{ + int length = data.ReadInt32(); + if (length <= 1) { + DBINDER_LOGE("length should > 1, length is %{public}d", length); + if (!reply.WriteInt32(length)) { + DBINDER_LOGE("fail to write parcel"); + } + return ERR_INVALID_DATA; + } + const char *buffer = nullptr; + if ((buffer = reinterpret_cast(data.ReadRawData(length))) == nullptr) { + if (!reply.WriteInt32(0)) { + DBINDER_LOGE("fail to write parcel"); + } + DBINDER_LOGE("read raw data failed, length = %{public}d", length); + return ERR_INVALID_DATA; + } + if (buffer[0] != 'a' || buffer[length - 1] != 'z') { + if (!reply.WriteInt32(0)) { + DBINDER_LOGE("fail to write parcel"); + } + DBINDER_LOGE("buffer error, length = %{public}d", length); + return ERR_INVALID_DATA; + } + if (data.ReadInt32() != length) { + if (!reply.WriteInt32(0)) { + DBINDER_LOGE("fail to write parcel"); + } + DBINDER_LOGE("read raw data after failed, length = %{public}d", length); + return ERR_INVALID_DATA; + } + if (!reply.WriteInt32(length)) { + DBINDER_LOGE("fail to write parcel"); + return ERR_INVALID_STATE; + } + + return ERR_NONE; +} + +int DBinderTestServiceStub::OnSentRawData(MessageParcel &data, MessageParcel &reply) +{ + int length = data.ReadInt32(); + if (length <= 1) { + DBINDER_LOGE("length should > 1, length is %{public}d", length); + if (!reply.WriteInt32(length)) { + DBINDER_LOGE("fail to write parcel"); + } + return ERR_INVALID_DATA; + } + + unsigned char *buffer = new (std::nothrow) unsigned char[length]; + if (buffer == nullptr) { + DBINDER_LOGE("new buffer failed of length = %{public}d", length); + return ERR_INVALID_STATE; + } + buffer[0] = 'a'; + buffer[length - 1] = 'z'; + if (!reply.WriteInt32(length) || !reply.WriteRawData(buffer, length) || !reply.WriteInt32(length)) { + DBINDER_LOGE("fail to write parcel"); + delete[] buffer; + return ERR_INVALID_STATE; + } + delete[] buffer; + return ERR_NONE; +} + +bool DBinderTestDeathRecipient::g_gotDeathRecipient = false; +bool DBinderTestDeathRecipient::GotDeathRecipient() +{ + return g_gotDeathRecipient; +} + +void DBinderTestDeathRecipient::ClearDeathRecipient() +{ + g_gotDeathRecipient = false; +} + +void DBinderTestDeathRecipient::OnRemoteDied(const wptr &remote) +{ + g_gotDeathRecipient = true; + printf("Succ! Remote Died!\n"); + DBINDER_LOGE("recv death notification"); +} + +DBinderTestDeathRecipient::DBinderTestDeathRecipient() {} + +DBinderTestDeathRecipient::~DBinderTestDeathRecipient() {} +} // namespace OHOS diff --git a/services/dbinder/test/test_dbinder.py b/services/dbinder/test/test_dbinder.py new file mode 100755 index 00000000..8fd3dc69 --- /dev/null +++ b/services/dbinder/test/test_dbinder.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding=utf-8 + +# +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. +# + +import sys +import os +sys.path.insert(0, os.environ.get('PYTEST_PYTESTPATH')) +import unittest +from distributed import * + +class DbinderTest(unittest.TestCase): + def setUp(self): + print('setUp') + self.result_path = get_result_dir(__file__) + self.suits_dir = os.path.abspath(os.path.dirname(__file__)) + self.manager = DeviceManager() + self.major = self.manager.PHONE1 + self.agent_list = [self.manager.PHONE2] + + def test_dbinder(self): + major_target_name = "DbinderTest" + agent_target_name = "DbinderTestAgent" + + distribute = Distribute(self.suits_dir, self.major, self.agent_list) + + for agent in self.agent_list: + if not distribute.exec_agent(agent, agent_target_name): + create_empty_result_file(self.result_path, major_target_name) + return + + distribute.exec_major(self.major, major_target_name) + + source_path = "%s/%s.xml" % (self.major.test_path, major_target_name) + distribute.pull_result(self.major, source_path, self.result_path) + + def tearDown(self): + print('tearDown') + + +if __name__ == '__main__': + unittest.main() diff --git a/test/resource/ipc/ohos_test.xml b/test/resource/ipc/ohos_test.xml new file mode 100755 index 00000000..b52fa508 --- /dev/null +++ b/test/resource/ipc/ohos_test.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/test/resource/services/ohos_test.xml b/test/resource/services/ohos_test.xml new file mode 100755 index 00000000..47806f0a --- /dev/null +++ b/test/resource/services/ohos_test.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/utils/include/log_tags.h b/utils/include/log_tags.h new file mode 100755 index 00000000..ac44d124 --- /dev/null +++ b/utils/include/log_tags.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_COMMUNICATION_LOG_TAGS_H +#define OHOS_COMMUNICATION_LOG_TAGS_H + +namespace OHOS { +const unsigned int LOG_ID_COMMUNICATION = 0xD001500; + +const unsigned int LOG_ID_IPC = LOG_ID_COMMUNICATION | 0x10; + +const unsigned int LOG_ID_RPC = LOG_ID_COMMUNICATION | 0x18; + +const unsigned int LOG_ID_DISC = LOG_ID_COMMUNICATION | 0x20; + +const unsigned int LOG_ID_DNET = LOG_ID_COMMUNICATION | 0x30; + +const unsigned int LOG_ID_SMARTNET = LOG_ID_COMMUNICATION | 0x40; + +const unsigned int LOG_ID_BLUETOOTH = LOG_ID_COMMUNICATION | 0x50; + +const unsigned int LOG_ID_WIFI = LOG_ID_COMMUNICATION | 0x60; +const unsigned int LOG_ID_WIFI_HOTSPOT = LOG_ID_WIFI | 0x01; +const unsigned int LOG_ID_WIFI_ENHANCER = LOG_ID_WIFI | 0x02; + +const unsigned int LOG_ID_NFC = LOG_ID_COMMUNICATION | 0x70; + +const unsigned int LOG_ID_NSTACK = LOG_ID_COMMUNICATION | 0x80; + +const unsigned int LOG_ID_RADIO = LOG_ID_COMMUNICATION | 0x90; + +const unsigned int LOG_ID_REMOTE_P2P = LOG_ID_COMMUNICATION | 0xA0; + +const unsigned int LOG_ID_NET_MANAGER = LOG_ID_COMMUNICATION | 0xB0; +} // namespace OHOS +#endif // OHOS_COMMUNICATION_LOG_TAGS_H