1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ffrt_profiler_socker_client.h"
17
18 #include "ffrt_profiler_common.h"
19 #include "ffrt_profiler.h"
20 #include "logging.h"
21
22 namespace {
23 std::atomic<uint64_t> g_flushCount = 0;
24 std::atomic<bool> g_disableHook = false;
25 constexpr uint32_t FILTER_SIZE = (1 << 10);
26 } // namespace
27
28 namespace OHOS::Developtools::Profiler {
FfrtProfilerSocketClient(int pid,FfrtProfiler * profiler,void (* disableHookCallback)())29 FfrtProfilerSocketClient::FfrtProfilerSocketClient(int pid, FfrtProfiler* profiler, void (*disableHookCallback)())
30 : pid_(pid), disableHookCallback_(disableHookCallback), profiler_(profiler)
31 {
32 smbFd_ = 0;
33 eventFd_ = 0;
34 unixSocketClient_ = nullptr;
35 serviceName_ = "FfrtProfilerService";
36 Connect(FFRT_PROFILER_UNIX_SOCKET_FULL_PATH);
37 }
38
~FfrtProfilerSocketClient()39 FfrtProfilerSocketClient::~FfrtProfilerSocketClient()
40 {
41 if (writer_) {
42 writer_->Flush();
43 }
44 unixSocketClient_ = nullptr;
45 writer_ = nullptr;
46 }
47
Connect(const std::string addrname)48 bool FfrtProfilerSocketClient::Connect(const std::string addrname)
49 {
50 if (unixSocketClient_ != nullptr) {
51 return false;
52 }
53 unixSocketClient_ = std::make_shared<UnixSocketClient>();
54 if (!unixSocketClient_->Connect(addrname, *this)) {
55 unixSocketClient_ = nullptr;
56 return false;
57 }
58
59 unixSocketClient_->SendHookConfig(reinterpret_cast<uint8_t *>(&pid_), sizeof(pid_));
60 return true;
61 }
62
ProtocolProc(SocketContext & context,uint32_t pnum,const int8_t * buf,const uint32_t size)63 bool FfrtProfilerSocketClient::ProtocolProc(SocketContext &context, uint32_t pnum, const int8_t *buf,
64 const uint32_t size)
65 {
66 CHECK_TRUE(size == sizeof(FfrtConfig), true, "FfrtProfilerSocketClient config size not match = %u\n", size);
67 FfrtConfig* config = reinterpret_cast<FfrtConfig *>(const_cast<int8_t*>(buf));
68 smbFd_ = context.ReceiveFileDiscriptor();
69 eventFd_ = context.ReceiveFileDiscriptor();
70 PROFILER_LOG_INFO(LOG_CORE, "ffrt profiler client: smbFd: %d, eventFd: %d, shmSize: %d",
71 smbFd_, eventFd_, config->shmSize);
72
73 flushInterval_ = static_cast<uint32_t>(config->flushCount);
74 block_ = config->block;
75 profiler_->SetClockId(config->clock);
76 PROFILER_LOG_INFO(LOG_CORE, "ffrt profiler client: flushInterval: %d, block: %d, clock: %d",
77 flushInterval_, block_, config->clock);
78
79 std::string smbName = "ffrtProfilerSmb_" + std::to_string(pid_);
80 writer_ = std::make_shared<FfrtProfilerWriter>(smbName, config->shmSize, smbFd_, eventFd_, config->block);
81 profiler_->SetEnableFlag(true);
82 return true;
83 }
84
SendFfrtProfilerData(const void * data,size_t size,const void * payload,size_t payloadSize)85 bool FfrtProfilerSocketClient::SendFfrtProfilerData(const void* data, size_t size, const void* payload,
86 size_t payloadSize)
87 {
88 if (writer_ == nullptr || unixSocketClient_ == nullptr || g_disableHook) {
89 return false;
90 } else if (unixSocketClient_->GetClientState() == CLIENT_STAT_THREAD_EXITED) {
91 DisableHook();
92 return false;
93 }
94
95 if (payloadSize > FILTER_SIZE) {
96 PROFILER_LOG_ERROR(LOG_CORE, "payloadSize exceeds the maximum of %d bytes", FILTER_SIZE);
97 return false;
98 }
99 bool ret = writer_->WriteWithPayloadTimeout(
100 data,
101 size,
102 payload,
103 payloadSize,
104 std::bind(&FfrtProfilerSocketClient::PeerIsConnected, this));
105 if (!ret && block_) {
106 DisableHook();
107 return false;
108 }
109 if (++g_flushCount % flushInterval_ == 0) {
110 writer_->Flush();
111 }
112 return true;
113 }
114
Flush()115 void FfrtProfilerSocketClient::Flush()
116 {
117 if (writer_ == nullptr || unixSocketClient_ == nullptr) {
118 return;
119 }
120 writer_->Flush();
121 }
122
DisableHook()123 void FfrtProfilerSocketClient::DisableHook()
124 {
125 bool expected = false;
126 if (g_disableHook.compare_exchange_strong(expected, true, std::memory_order_release, std::memory_order_relaxed)) {
127 PROFILER_LOG_INFO(LOG_CORE, "%s", __func__);
128 if (disableHookCallback_ != nullptr) {
129 disableHookCallback_();
130 }
131 }
132 }
133
PeerIsConnected()134 bool FfrtProfilerSocketClient::PeerIsConnected()
135 {
136 if (unixSocketClient_ == nullptr) {
137 return false;
138 }
139 return !unixSocketClient_->IsConnected();
140 }
141 }