1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 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 "dfx_signalhandler_exception.h" 17 18#include <stdio.h> 19#include <sys/syscall.h> 20#include <sys/socket.h> 21#include <sys/time.h> 22#include <sys/un.h> 23#include <unistd.h> 24 25#include "dfx_define.h" 26#include "dfx_exception.h" 27#include "dfx_socket_request.h" 28#include "errno.h" 29#include "string.h" 30 31#ifndef DFX_SIGNAL_LIBC 32#include "dfx_log.h" 33#else 34#include "musl_log.h" 35#endif 36 37#ifdef LOG_DOMAIN 38#undef LOG_DOMAIN 39#define LOG_DOMAIN 0xD002D11 40#endif 41 42#ifdef LOG_TAG 43#undef LOG_TAG 44#define LOG_TAG "DfxSignalHandlerException" 45#endif 46 47static const int TIME_OUT = 2; /* seconds */ 48static const char FAULTLOGGERD_SOCKET_NAME[] = "/dev/unix/socket/faultloggerd.server"; 49 50static int ConnectSocket(const char* path, const int timeout) 51{ 52 int fd = -1; 53 if ((fd = syscall(SYS_socket, AF_LOCAL, SOCK_STREAM, 0)) < 0) { 54 DFXLOGE("Failed to create a socket, errno(%{public}d).", errno); 55 return -1; 56 } 57 58 do { 59 if (timeout > 0) { 60 struct timeval timev = { 61 timeout, 62 0 63 }; 64 void* pTimev = &timev; 65 if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_setsockopt, fd, SOL_SOCKET, SO_RCVTIMEO, 66 (const void*)(pTimev), sizeof(timev))) != 0) { 67 DFXLOGE("setsockopt SO_RCVTIMEO error, errno(%{public}d).", errno); 68 syscall(SYS_close, fd); 69 fd = -1; 70 break; 71 } 72 } 73 struct sockaddr_un server; 74 (void)memset(&server, 0, sizeof(server)); 75 server.sun_family = AF_LOCAL; 76 (void)strncpy(server.sun_path, path, sizeof(server.sun_path) - 1); 77 int len = sizeof(server.sun_family) + strlen(server.sun_path); 78 int connected = OHOS_TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)(&server), len)); 79 if (connected < 0) { 80 DFXLOGE("Failed to connect to faultloggerd socket, errno = %{public}d.", errno); 81 syscall(SYS_close, fd); 82 fd = -1; 83 break; 84 } 85 } while (false); 86 return fd; 87} 88 89static bool CheckReadResp(int fd) 90{ 91 char controlBuffer[MAX_FUNC_NAME_LEN] = {0}; 92 ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, controlBuffer, sizeof(controlBuffer) - 1)); 93 if (nread != (ssize_t)(strlen(FAULTLOGGER_DAEMON_RESP))) { 94 DFXLOGE("Failed to read expected length, nread: %{public}zd, errno(%{public}d).", nread, errno); 95 return false; 96 } 97 return true; 98} 99 100int ReportException(struct CrashDumpException exception) 101{ 102 struct FaultLoggerdRequest request; 103 (void)memset(&request, 0, sizeof(struct FaultLoggerdRequest)); 104 request.clientType = (int32_t)REPORT_EXCEPTION_CLIENT; 105 request.pid = exception.pid; 106 request.uid = (uint32_t)(exception.uid); 107 int ret = -1; 108 int fd = ConnectSocket(FAULTLOGGERD_SOCKET_NAME, TIME_OUT); // connect timeout 109 if (fd == -1) { 110 DFXLOGE("Failed to connect socket."); 111 return ret; 112 } 113 do { 114 if (OHOS_TEMP_FAILURE_RETRY(write(fd, &request, sizeof(request))) != (long)sizeof(request)) { 115 DFXLOGE("Failed to write request message to socket, errno(%{public}d).", errno); 116 break; 117 } 118 119 if (!CheckReadResp(fd)) { 120 DFXLOGE("Failed to receive socket responces."); 121 break; 122 } 123 124 if (OHOS_TEMP_FAILURE_RETRY(write(fd, &exception, 125 sizeof(exception))) != (long)sizeof(exception)) { 126 DFXLOGE("Failed to write exception message to socket, errno(%{public}d).", errno); 127 break; 128 } 129 130 ret = 0; 131 } while (false); 132 syscall(SYS_close, fd); 133 return ret; 134} 135