• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #include <cstdlib>
16 #include <sys/mount.h>
17 #include <sys/wait.h>
18 
19 #include "daemon_unity.h"
20 
21 namespace Hdc {
HdcDaemonUnity(HTaskInfo hTaskInfo)22 HdcDaemonUnity::HdcDaemonUnity(HTaskInfo hTaskInfo)
23     : HdcTaskBase(hTaskInfo)
24 {
25     currentDataCommand = CMD_KERNEL_ECHO_RAW;  // Default output to shelldata
26 }
27 
~HdcDaemonUnity()28 HdcDaemonUnity::~HdcDaemonUnity()
29 {
30     WRITE_LOG(LOG_DEBUG, "~HdcDaemonUnity channelId:%u", taskInfo->channelId);
31 }
32 
StopTask()33 void HdcDaemonUnity::StopTask()
34 {
35     // Remove jpid tracker when stopping task
36     RemoveJdwpTracker();
37     asyncCommand.DoRelease();
38 }
39 
ReadyForRelease()40 bool HdcDaemonUnity::ReadyForRelease()
41 {
42     if (!HdcTaskBase::ReadyForRelease() || !asyncCommand.ReadyForRelease()) {
43         WRITE_LOG(LOG_DEBUG, "not ready for release channelId:%u", taskInfo->channelId);
44         return false;
45     }
46     return true;
47 }
48 
AsyncCmdOut(bool finish,int64_t exitStatus,const string result)49 bool HdcDaemonUnity::AsyncCmdOut(bool finish, int64_t exitStatus, const string result)
50 {
51 #ifdef UNIT_TEST
52     Base::WriteBinFile((UT_TMP_PATH + "/execute.result").c_str(), (uint8_t *)result.c_str(), result.size(),
53                        countUt++ == 0);
54 #endif
55     bool ret = false;
56     bool wantFinish = false;
57     do {
58         if (finish) {
59             wantFinish = true;
60             ret = true;
61             --refCount;
62             break;
63         }
64         if (!SendToAnother(currentDataCommand, reinterpret_cast<uint8_t *>(const_cast<char *>(result.c_str())),
65             result.size())) {
66             break;
67         }
68         ret = true;
69     } while (false);
70     if (wantFinish) {
71         TaskFinish();
72     }
73     return ret;
74 }
75 
ExecuteShell(const char * shellCommand)76 int HdcDaemonUnity::ExecuteShell(const char *shellCommand)
77 {
78     do {
79         AsyncCmd::CmdResultCallback funcResultOutput;
80         funcResultOutput = [this](bool finish, int64_t exitStatus, const string result) -> bool {
81             return this->AsyncCmdOut(finish, exitStatus, result);
82         };
83         if (!asyncCommand.Initial(loopTask, funcResultOutput)) {
84             break;
85         }
86         asyncCommand.ExecuteCommand(shellCommand);
87         ++refCount;
88         return RET_SUCCESS;
89     } while (false);
90 
91     TaskFinish();
92     WRITE_LOG(LOG_DEBUG, "Shell failed finish");
93     return -1;
94 }
95 
FindMountDeviceByPath(const char * toQuery,char * dev)96 bool HdcDaemonUnity::FindMountDeviceByPath(const char *toQuery, char *dev)
97 {
98     int ret = false;
99     int len = BUF_SIZE_DEFAULT2;
100     char buf[BUF_SIZE_DEFAULT2];
101 
102     FILE *fp = fopen("/proc/mounts", "r");
103     if (fp == nullptr) {
104         WRITE_LOG(LOG_FATAL, "fopen /proc/mounts error:%d", errno);
105         return false;
106     }
107 
108     while (fgets(buf, len, fp) != nullptr) {
109         char dir[BUF_SIZE_SMALL] = "";
110         int freq;
111         int passnno;
112         int res = 0;
113         // clang-format off
114         res = sscanf_s(buf, "%255s %255s %*s %*s %d %d\n", dev, BUF_SIZE_SMALL - 1,
115                        dir, BUF_SIZE_SMALL - 1, &freq, &passnno);
116         // clang-format on
117         dev[BUF_SIZE_SMALL - 1] = '\0';
118         dir[BUF_SIZE_SMALL - 1] = '\0';
119         if (res == 4 && (strcmp(toQuery, dir) == 0)) {  // 4 : The correct number of parameters
120             WRITE_LOG(LOG_DEBUG, "FindMountDeviceByPath dev:%s dir:%s", dev, dir);
121             ret = true;
122             break;
123         }
124     }
125     int rc = fclose(fp);
126     if (rc != 0) {
127         WRITE_LOG(LOG_WARN, "fclose rc:%d error:%d", rc, errno);
128     }
129     if (!ret) {
130         WRITE_LOG(LOG_FATAL, "FindMountDeviceByPath not found %s", toQuery);
131     }
132     return ret;
133 }
134 
RemountPartition(const char * dir)135 bool HdcDaemonUnity::RemountPartition(const char *dir)
136 {
137     int fd;
138     int off = 0;
139     char dev[BUF_SIZE_SMALL] = "";
140 
141     if (!FindMountDeviceByPath(dir, dev) || strlen(dev) < 4) {  // 4 : file count
142         WRITE_LOG(LOG_FATAL, "FindMountDeviceByPath failed %s", dir);
143         return false;
144     }
145 
146     if ((fd = open(dev, O_RDONLY | O_CLOEXEC)) < 0) {
147         WRITE_LOG(LOG_FATAL, "Open device:%s failed,error:%d", dev, errno);
148         return false;
149     }
150     ioctl(fd, BLKROSET, &off);
151     Base::CloseFd(fd);
152 
153     if (mount(dev, dir, "none", MS_REMOUNT, nullptr) < 0) {
154         WRITE_LOG(LOG_FATAL, "Mount device failed dev:%s dir:%s error:%d", dev, dir, errno);
155         return false;
156     }
157     return true;
158 }
159 
CallRemount()160 bool HdcDaemonUnity::CallRemount()
161 {
162     int pipefd[2];
163     pid_t pid;
164     int exitStatus;
165 
166     if (pipe(pipefd) == -1) {
167         WRITE_LOG(LOG_FATAL, "Failed to create pipe: %s", strerror(errno));
168         return false;
169     }
170     pid = fork();
171     if (pid < 0) {
172         WRITE_LOG(LOG_FATAL, "Failed to fork: %s", strerror(errno));
173         return false;
174     }
175     if (pid == 0) {
176         close(pipefd[0]);
177         signal(SIGCHLD, SIG_DFL);
178         exitStatus = system("remount");
179         write(pipefd[1], &exitStatus, sizeof(int));
180         close(pipefd[1]);
181         _exit(0);
182     } else {
183         close(pipefd[1]);
184         read(pipefd[0], &exitStatus, sizeof(int));
185         close(pipefd[0]);
186         waitpid(pid, nullptr, 0);
187         if (exitStatus == -1) {
188             WRITE_LOG(LOG_FATAL, "Failed to execute /bin/remount: %s", strerror(errno));
189             return false;
190         } else if (WIFEXITED(exitStatus) && WEXITSTATUS(exitStatus) != 0) {
191             WRITE_LOG(LOG_FATAL, "Remount failed with exit code: %d", WEXITSTATUS(exitStatus));
192             return false;
193         }
194     }
195 
196     return true;
197 }
198 
RemountDevice()199 bool HdcDaemonUnity::RemountDevice()
200 {
201     if (getuid() != 0) {
202         LogMsg(MSG_FAIL, "Operate need running as root");
203         return false;
204     }
205     struct stat info;
206     if (!lstat("/vendor", &info) && (info.st_mode & S_IFMT) == S_IFDIR) {
207         if (!RemountPartition("/vendor")) {
208             WRITE_LOG(LOG_FATAL, "Mount failed /vendor (via mount)");
209         }
210     }
211     if (!lstat("/system", &info) && (info.st_mode & S_IFMT) == S_IFDIR) {
212         if (!RemountPartition("/")) {
213             WRITE_LOG(LOG_FATAL, "Mount failed /system (via mount)");
214         }
215     }
216 
217     if (CallRemount()) {
218         LogMsg(MSG_OK, "Mount finish");
219         return true;
220     } else {
221         LogMsg(MSG_FAIL, "Mount failed");
222         return false;
223     }
224 }
225 
RebootDevice(const string & cmd)226 bool HdcDaemonUnity::RebootDevice(const string &cmd)
227 {
228     sync();
229     return SystemDepend::RebootDevice(cmd);
230 }
231 
SetDeviceRunMode(const char * cmd)232 bool HdcDaemonUnity::SetDeviceRunMode(const char *cmd)
233 {
234     WRITE_LOG(LOG_INFO, "Set run mode:%s", cmd);
235     string tmp(cmd);
236     char *ptr = tmp.data();
237     char *token = nullptr;
238 
239 #ifdef HDC_EMULATOR
240     LogMsg(MSG_FAIL, "[E001300]Not support tmode for Emulator");
241     return true;
242 #endif
243 
244     // hdc tmode usb, do nothing
245     if (strcmp(CMDSTR_TMODE_USB.c_str(), cmd) == 0) {
246         LogMsg(MSG_FAIL, "[E001000]For USB debugging, please set it on the device's Settings UI");
247         return true;
248     }
249     // not usb and not tcp
250     if (strncmp("port", cmd, strlen("port")) != 0) {
251         LogMsg(MSG_FAIL, "[E001001]Unknown command");
252         return false;
253     }
254 
255     // bypass port
256     token = strtok_r(ptr, " ", &ptr);
257     // get next token
258     token = strtok_r(ptr, " ", &ptr);
259     // hdc tmode port
260     if (token == nullptr) {
261         LogMsg(MSG_OK, "Set device run mode successful.");
262         SystemDepend::SetDevItem("persist.hdc.mode", "tcp");
263         SystemDepend::SetDevItem("persist.hdc.mode.tcp", "enable");
264     } else {
265         /*
266         * hdc tmode port xxxxxx
267         * hdc tmode port close
268         */
269         if (strcmp(token, "close") == 0) {
270             SystemDepend::SetDevItem("persist.hdc.port", "0");
271             SystemDepend::SetDevItem("persist.hdc.mode.tcp", "disable");
272         } else {
273             string tmp(token);
274             if (tmp.find_first_not_of("0123456789") != string::npos) {
275                 LogMsg(MSG_FAIL, "[E001100]Invalid port");
276                 return false;
277             }
278             LogMsg(MSG_OK, "Set device run mode successful.");
279             SystemDepend::SetDevItem("persist.hdc.mode", "tcp");
280             SystemDepend::SetDevItem("persist.hdc.port", token);
281             SystemDepend::SetDevItem("persist.hdc.mode.tcp", "enable");
282         }
283     }
284     return true;
285 }
286 
GetHiLog(const char * cmd)287 inline bool HdcDaemonUnity::GetHiLog(const char *cmd)
288 {
289     string cmdDo = "hilog";
290     if (cmd && !strcmp(const_cast<char *>(cmd), "h")) {
291         cmdDo += " -h";
292     }
293     ExecuteShell(cmdDo.c_str());
294     return true;
295 }
296 
ListJdwpProcess(void * daemonIn)297 inline bool HdcDaemonUnity::ListJdwpProcess(void *daemonIn)
298 {
299     HdcDaemon *daemon = (HdcDaemon *)daemonIn;
300     string result = ((HdcJdwp *)daemon->clsJdwp)->GetProcessList();
301     if (!result.size()) {
302         result = EMPTY_ECHO;
303     } else {
304         result.erase(result.end() - 1);  // remove tail \n
305     }
306     LogMsg(MSG_OK, result.c_str());
307     return true;
308 }
309 
TrackJdwpProcess(void * daemonIn,const string & param)310 inline bool HdcDaemonUnity::TrackJdwpProcess(void *daemonIn, const string& param)
311 {
312     HdcDaemon *daemon = static_cast<HdcDaemon *>(daemonIn);
313     taskInfo->debugRelease = 1;
314     if (param == "p") {
315         taskInfo->debugRelease = 0;
316     } else if (param == "a") {
317         // allApp with display debug or release
318         constexpr uint8_t allAppWithDr = 3;
319         taskInfo->debugRelease = allAppWithDr;
320     }
321     if (!((static_cast<HdcJdwp *>(daemon->clsJdwp))->CreateJdwpTracker(taskInfo))) {
322         string result = MESSAGE_FAIL;
323         LogMsg(MSG_OK, result.c_str());
324         return false;
325     }
326     return true;
327 }
328 
RemoveJdwpTracker()329 inline void HdcDaemonUnity::RemoveJdwpTracker()
330 {
331     HdcDaemon *daemon = static_cast<HdcDaemon *>(taskInfo->ownerSessionClass);
332     (static_cast<HdcJdwp *>(daemon->clsJdwp))->RemoveJdwpTracker(taskInfo);
333 }
334 
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)335 bool HdcDaemonUnity::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
336 {
337     bool ret = true;
338     HdcDaemon *daemon = (HdcDaemon *)taskInfo->ownerSessionClass;
339     // Both are not executed, do not need to be detected 'childReady'
340     string strPayload = string(reinterpret_cast<char *>(payload), payloadSize);
341 #ifdef HDC_DEBUG
342     WRITE_LOG(LOG_DEBUG, "CommandDispatch command:%d", command);
343 #endif // HDC_DEBUG
344     switch (command) {
345         case CMD_UNITY_EXECUTE: {
346             ExecuteShell(const_cast<char *>(strPayload.c_str()));
347             break;
348         }
349         case CMD_UNITY_REMOUNT: {
350             ret = false;
351             RemountDevice();
352             break;
353         }
354         case CMD_UNITY_REBOOT: {
355             ret = false;
356             RebootDevice(strPayload);
357             break;
358         }
359         case CMD_UNITY_RUNMODE: {
360             ret = false;
361             SetDeviceRunMode(strPayload.c_str());
362             break;
363         }
364         case CMD_UNITY_HILOG: {
365             GetHiLog(strPayload.c_str());
366             break;
367         }
368         case CMD_UNITY_ROOTRUN: {
369             ret = false;
370             string debugMode;
371             // hdcd restart in old pid
372             bool restart = true;
373             SystemDepend::GetDevItem("const.debuggable", debugMode);
374             if (debugMode == "1") {
375                 if (payloadSize != 0 && !strcmp(strPayload.c_str(), "r")) {
376                     SystemDepend::SetDevItem("persist.hdc.root", "0");
377                 } else {
378                     // hdcd restart in new pid
379                     restart = false;
380                     SystemDepend::SetDevItem("persist.hdc.root", "1");
381                 }
382             } else {
383                 LogMsg(MSG_FAIL, "Cannot set root run mode in undebuggable version.");
384                 return false;
385             }
386             daemon->PostStopInstanceMessage(restart);
387             break;
388         }
389         case CMD_UNITY_BUGREPORT_INIT: {
390             currentDataCommand = CMD_UNITY_BUGREPORT_DATA;
391             ExecuteShell("hidumper");
392             break;
393         }
394         case CMD_JDWP_LIST: {
395             ret = false;
396             ListJdwpProcess(daemon);
397             break;
398         }
399         case CMD_JDWP_TRACK: {
400             if (!TrackJdwpProcess(daemon, strPayload)) {
401                 ret = false;
402             }
403             break;
404         }
405         default:
406             break;
407     }
408 #ifdef HDC_DEBUG
409     WRITE_LOG(LOG_DEBUG, "CommandDispatch command:%d finish.", command);
410 #endif // HDC_LOCAL_DEBUG
411     return ret;
412 };
413 }  // namespace Hdc
414