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 <unistd.h> 17#include <stdlib.h> 18#include <stdio.h> 19#include <sys/wait.h> 20 21#include "hilog/log.h" 22#include "appspawn_utils.h" 23#include "securec.h" 24#include "parameter.h" 25 26#include "hnp_api.h" 27 28#ifdef __cplusplus 29extern "C" { 30#endif 31 32#define HNPAPI_LOG(fmt, ...) \ 33 HILOG_INFO(LOG_CORE, "[%{public}s:%{public}d]" fmt, (__FILE_NAME__), (__LINE__), ##__VA_ARGS__) 34#define MAX_ARGV_NUM 256 35#define MAX_ENV_NUM (128 + 2) 36#define IS_OPTION_SET(x, option) ((x) & (1 << (option))) 37#define BUFFER_SIZE 1024 38#define CMD_API_TEXT_LEN 50 39#define PARAM_BUFFER_SIZE 10 40 41/* 数字索引 */ 42enum { 43 HNP_INDEX_0 = 0, 44 HNP_INDEX_1, 45 HNP_INDEX_2, 46 HNP_INDEX_3, 47 HNP_INDEX_4, 48 HNP_INDEX_5, 49 HNP_INDEX_6, 50 HNP_INDEX_7 51}; 52 53static int HnpCmdApiReturnGet(int readFd, int *ret) 54{ 55 char buffer[BUFFER_SIZE] = {0}; 56 ssize_t bytesRead; 57 int bufferEnd = 0; // 跟踪缓冲区中有效数据的末尾 58 const char *prefix = "native manager process exit. ret="; 59 60 // 循环读取子进程的输出,直到结束 61 while ((bytesRead = read(readFd, buffer + bufferEnd, BUFFER_SIZE - bufferEnd - 1)) > 0) { 62 // 更新有效数据的末尾 63 bufferEnd += bytesRead; 64 65 // 如果缓冲区中的数据超过或等于50个字节,移动数据以保留最后50个字节 66 if (bufferEnd >= CMD_API_TEXT_LEN) { 67 if (memmove_s(buffer, BUFFER_SIZE, buffer + bufferEnd - CMD_API_TEXT_LEN, CMD_API_TEXT_LEN) != EOK) { 68 HNPAPI_LOG("\r\n [HNP API] mem move unsuccess!\r\n"); 69 return HNP_API_ERRNO_MEMMOVE_FAILED; 70 } 71 bufferEnd = CMD_API_TEXT_LEN; 72 } 73 74 buffer[bufferEnd] = '\0'; 75 } 76 77 if (bytesRead == -1) { 78 HNPAPI_LOG("\r\n [HNP API] read stream unsuccess!\r\n"); 79 return HNP_API_ERRNO_PIPE_READ_FAILED; 80 } 81 82 char *retStr = strstr(buffer, prefix); 83 84 if (retStr != NULL) { 85 // 获取后续的数字字符串 86 retStr += strlen(prefix); 87 *ret = atoi(retStr); 88 89 return 0; 90 } 91 92 HNPAPI_LOG("\r\n [HNP API] get return unsuccess!, buffer is:%{public}s\r\n", buffer); 93 return HNP_API_ERRNO_RETURN_VALUE_GET_FAILED; 94} 95 96static int StartHnpProcess(char *const argv[], char *const apcEnv[]) 97{ 98 int fd[2]; 99 pid_t pid; 100 int exitVal = -1; 101 int ret; 102 int status; 103 104 if (pipe(fd) < 0) { 105 HNPAPI_LOG("\r\n [HNP API] pipe fd unsuccess!\r\n"); 106 return HNP_API_ERRNO_PIPE_CREATED_FAILED; 107 } 108 109 pid = vfork(); 110 if (pid < 0) { 111 HNPAPI_LOG("\r\n [HNP API] fork unsuccess!\r\n"); 112 return HNP_API_ERRNO_FORK_FAILED; 113 } else if (pid == 0) { 114 close(fd[0]); 115 // 将子进程的stdout重定向到管道的写端 116 dup2(fd[1], STDOUT_FILENO); 117 close(fd[1]); 118 119 ret = execve("/system/bin/hnp", argv, apcEnv); 120 if (ret < 0) { 121 HNPAPI_LOG("\r\n [HNP API] execve unsuccess!\r\n"); 122 _exit(-1); 123 } 124 _exit(0); 125 } 126 127 HNPAPI_LOG("\r\n [HNP API] this is fork father! chid=%{public}d\r\n", pid); 128 close(fd[1]); 129 if (waitpid(pid, &status, 0) == -1) { 130 close(fd[0]); 131 HNPAPI_LOG("\r\n [HNP API] wait pid unsuccess!\r\n"); 132 return HNP_API_WAIT_PID_FAILED; 133 } 134 ret = HnpCmdApiReturnGet(fd[0], &exitVal); 135 close(fd[0]); 136 if (ret != 0) { 137 HNPAPI_LOG("\r\n [HNP API] get api return value unsuccess!\r\n"); 138 return ret; 139 } 140 HNPAPI_LOG("\r\n [HNP API] Child process exited with exitval=%{public}d\r\n", exitVal); 141 142 return exitVal; 143} 144 145static bool IsHnpInstallEnable() 146{ 147 char buffer[PARAM_BUFFER_SIZE] = {0}; 148 int ret = GetParameter("const.startup.hnp.install.enable", "false", buffer, PARAM_BUFFER_SIZE); 149 if (ret <= 0) { 150 HNPAPI_LOG("\r\n [HNP API] get hnp install enable param unsuccess! ret =%{public}d\r\n", ret); 151 return false; 152 } 153 154 if (strcmp(buffer, "true") == 0) { 155 return true; 156 } 157 158 return false; 159} 160 161int NativeInstallHnp(const char *userId, const char *hnpRootPath, const HapInfo *hapInfo, int installOptions) 162{ 163 char *argv[MAX_ARGV_NUM] = {0}; 164 char *apcEnv[MAX_ENV_NUM] = {0}; 165 int index = 0; 166 167 if (!IsDeveloperModeOpen()) { 168 HNPAPI_LOG("\r\n [HNP API] native package install not in developer mode"); 169 return HNP_API_NOT_IN_DEVELOPER_MODE; 170 } 171 172 if ((userId == NULL) || (hnpRootPath == NULL) || (hapInfo == NULL)) { 173 return HNP_API_ERRNO_PARAM_INVALID; 174 } 175 176 if (!IsHnpInstallEnable()) { 177 return HNP_API_ERRNO_HNP_INSTALL_DISABLED; 178 } 179 180 HNPAPI_LOG("\r\n [HNP API] native package install! userId=%{public}s, hap path=%{public}s, sys abi=%{public}s, " 181 "hnp root path=%{public}s, package name=%{public}s install options=%{public}d\r\n", userId, hapInfo->hapPath, 182 hapInfo->abi, hnpRootPath, hapInfo->packageName, installOptions); 183 184 argv[index++] = "hnp"; 185 argv[index++] = "install"; 186 argv[index++] = "-u"; 187 argv[index++] = (char *)userId; 188 argv[index++] = "-i"; 189 argv[index++] = (char *)hnpRootPath; 190 argv[index++] = "-p"; 191 argv[index++] = (char *)hapInfo->packageName; 192 argv[index++] = "-s"; 193 argv[index++] = (char *)hapInfo->hapPath; 194 argv[index++] = "-a"; 195 argv[index++] = (char *)hapInfo->abi; 196 197 if (installOptions >= 0 && IS_OPTION_SET((unsigned int)installOptions, OPTION_INDEX_FORCE)) { 198 argv[index++] = "-f"; 199 } 200 201 return StartHnpProcess(argv, apcEnv); 202} 203 204int NativeUnInstallHnp(const char *userId, const char *packageName) 205{ 206 char *argv[MAX_ARGV_NUM] = {0}; 207 char *apcEnv[MAX_ENV_NUM] = {0}; 208 int index = 0; 209 210 if (!IsDeveloperModeOpen()) { 211 HNPAPI_LOG("\r\n [HNP API] native package uninstall not in developer mode"); 212 return HNP_API_NOT_IN_DEVELOPER_MODE; 213 } 214 215 if ((userId == NULL) || (packageName == NULL)) { 216 return HNP_API_ERRNO_PARAM_INVALID; 217 } 218 219 HNPAPI_LOG("\r\n [HNP API] native package uninstall! userId=%{public}s, package name=%{public}s\r\n", userId, 220 packageName); 221 222 argv[index++] = "hnp"; 223 argv[index++] = "uninstall"; 224 argv[index++] = "-u"; 225 argv[index++] = (char *)userId; 226 argv[index++] = "-p"; 227 argv[index++] = (char *)packageName; 228 229 return StartHnpProcess(argv, apcEnv); 230} 231 232#ifdef __cplusplus 233} 234#endif