• 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_INFO, "~HdcDaemonUnity cid:%u sid:%u", taskInfo->channelId, taskInfo->sessionId);
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 
CheckbundlePath(const string & bundleName,string & mountPath)76 bool HdcDaemonUnity::CheckbundlePath(const string &bundleName, string &mountPath)
77 {
78     if (access(DEBUG_BUNDLE_PATH.c_str(), F_OK) != 0 || !Base::CheckBundleName(bundleName)) {
79         WRITE_LOG(LOG_FATAL, "debug path %s not found", DEBUG_BUNDLE_PATH.c_str());
80         LogMsg(MSG_FAIL, "[E003001] Invalid bundle name: %s", bundleName.c_str());
81         return false;
82     }
83     string targetPath = "";
84     targetPath += DEBUG_BUNDLE_PATH;
85     targetPath += bundleName;
86     if ((access(targetPath.c_str(), F_OK) != 0)) {
87         WRITE_LOG(LOG_FATAL, "bundle mount path %s not found", targetPath.c_str());
88         LogMsg(MSG_FAIL, "[E003001] Invalid bundle name: %s", bundleName.c_str());
89         return false;
90     }
91     mountPath = targetPath;
92     return true;
93 }
94 
ExecuteOptionShell(const string & shellCommand,const string & bundleName)95 int HdcDaemonUnity::ExecuteOptionShell(const string &shellCommand, const string &bundleName)
96 {
97     string mountPath = "";
98     if (!CheckbundlePath(bundleName, mountPath)) {
99         return -1;
100     }
101     return ExecuteShell(shellCommand, mountPath);
102 }
103 
ExecuteShell(const string & shellCommand,string optionPath)104 int HdcDaemonUnity::ExecuteShell(const string &shellCommand, string optionPath)
105 {
106     do {
107         AsyncCmd::CmdResultCallback funcResultOutput;
108         funcResultOutput = [this](bool finish, int64_t exitStatus, const string result) -> bool {
109             return this->AsyncCmdOut(finish, exitStatus, result);
110         };
111         if (!asyncCommand.Initial(loopTask, funcResultOutput)) {
112             break;
113         }
114         asyncCommand.ExecuteCommand(shellCommand, optionPath);
115         ++refCount;
116         return RET_SUCCESS;
117     } while (false);
118 
119     TaskFinish();
120     WRITE_LOG(LOG_DEBUG, "Shell failed finish");
121     return -1;
122 }
123 
ExecuteShellExtend(const uint8_t * payload,const int payloadSize)124 int HdcDaemonUnity::ExecuteShellExtend(const uint8_t *payload, const int payloadSize)
125 {
126     string bundleName = "";
127     string command = "";
128     string errMsg = "";
129     TlvBuf tlvbuf(const_cast<uint8_t *>(payload), payloadSize, Base::REGISTERD_TAG_SET);
130     tlvbuf.Display();
131     if (tlvbuf.ContainInvalidTag()) {
132         LogMsg(MSG_FAIL, "[E003004] Device does not support this shell option");
133         return -1;
134     } else {
135         if (!tlvbuf.FindTlv(TAG_SHELL_BUNDLE, bundleName)) {
136             WRITE_LOG(LOG_FATAL, "ExecuteShellExtend bundleName is empty");
137         }
138         if (!tlvbuf.FindTlv(TAG_SHELL_CMD, command)) {
139             WRITE_LOG(LOG_FATAL, "ExecuteShellExtend command is empty");
140         }
141     }
142     WRITE_LOG(LOG_DEBUG, "ExecuteShellExtend command: %s, bundleName: %s", command.c_str(), bundleName.c_str());
143     return ExecuteOptionShell(command, bundleName);
144 }
145 
FindMountDeviceByPath(const char * toQuery,char * dev)146 bool HdcDaemonUnity::FindMountDeviceByPath(const char *toQuery, char *dev)
147 {
148     int ret = false;
149     int len = BUF_SIZE_DEFAULT2;
150     char buf[BUF_SIZE_DEFAULT2];
151 
152     FILE *fp = fopen("/proc/mounts", "r");
153     if (fp == nullptr) {
154         WRITE_LOG(LOG_FATAL, "fopen /proc/mounts error:%d", errno);
155         return false;
156     }
157 
158     while (fgets(buf, len, fp) != nullptr) {
159         char dir[BUF_SIZE_SMALL] = "";
160         int freq;
161         int passnno;
162         int res = 0;
163         // clang-format off
164         res = sscanf_s(buf, "%255s %255s %*s %*s %d %d\n", dev, BUF_SIZE_SMALL - 1,
165                        dir, BUF_SIZE_SMALL - 1, &freq, &passnno);
166         // clang-format on
167         dev[BUF_SIZE_SMALL - 1] = '\0';
168         dir[BUF_SIZE_SMALL - 1] = '\0';
169         if (res == 4 && (strcmp(toQuery, dir) == 0)) {  // 4 : The correct number of parameters
170             WRITE_LOG(LOG_DEBUG, "FindMountDeviceByPath dev:%s dir:%s", dev, dir);
171             ret = true;
172             break;
173         }
174     }
175     int rc = fclose(fp);
176     if (rc != 0) {
177         WRITE_LOG(LOG_WARN, "fclose rc:%d error:%d", rc, errno);
178     }
179     if (!ret) {
180         WRITE_LOG(LOG_FATAL, "FindMountDeviceByPath not found %s", toQuery);
181     }
182     return ret;
183 }
184 
RemountPartition(const char * dir)185 bool HdcDaemonUnity::RemountPartition(const char *dir)
186 {
187     int fd;
188     int off = 0;
189     char dev[BUF_SIZE_SMALL] = "";
190 
191     if (!FindMountDeviceByPath(dir, dev) || strlen(dev) < 4) {  // 4 : file count
192         WRITE_LOG(LOG_FATAL, "FindMountDeviceByPath failed %s", dir);
193         return false;
194     }
195 
196     if ((fd = open(dev, O_RDONLY | O_CLOEXEC)) < 0) {
197         WRITE_LOG(LOG_FATAL, "Open device:%s failed,error:%d", dev, errno);
198         return false;
199     }
200     ioctl(fd, BLKROSET, &off);
201     Base::CloseFd(fd);
202 
203     if (mount(dev, dir, "none", MS_REMOUNT, nullptr) < 0) {
204         WRITE_LOG(LOG_FATAL, "Mount device failed dev:%s dir:%s error:%d", dev, dir, errno);
205         return false;
206     }
207     return true;
208 }
209 
CallRemount()210 bool HdcDaemonUnity::CallRemount()
211 {
212     int pipefd[2];
213     pid_t pid;
214     int exitStatus;
215 
216     if (pipe(pipefd) == -1) {
217         WRITE_LOG(LOG_FATAL, "Failed to create pipe: %s", strerror(errno));
218         return false;
219     }
220     pid = fork();
221     if (pid < 0) {
222         close(pipefd[0]);
223         close(pipefd[1]);
224         WRITE_LOG(LOG_FATAL, "Failed to fork: %s", strerror(errno));
225         return false;
226     }
227     if (pid == 0) {
228         close(pipefd[0]);
229         signal(SIGCHLD, SIG_DFL);
230         exitStatus = system("remount");
231         write(pipefd[1], &exitStatus, sizeof(int));
232         close(pipefd[1]);
233         _exit(0);
234     } else {
235         close(pipefd[1]);
236         read(pipefd[0], &exitStatus, sizeof(int));
237         close(pipefd[0]);
238         waitpid(pid, nullptr, 0);
239         if (exitStatus == -1) {
240             WRITE_LOG(LOG_FATAL, "Failed to execute /bin/remount: %s", strerror(errno));
241             return false;
242         } else if (WIFEXITED(exitStatus) && WEXITSTATUS(exitStatus) != 0) {
243             WRITE_LOG(LOG_FATAL, "Remount failed with exit code: %d", WEXITSTATUS(exitStatus));
244             return false;
245         }
246     }
247 
248     return true;
249 }
250 
RemountDevice()251 bool HdcDaemonUnity::RemountDevice()
252 {
253     string debugMode;
254     SystemDepend::GetDevItem("const.debuggable", debugMode);
255     if (debugMode != "1") {
256         LogMsg(MSG_FAIL, "[E007100] Operate need running under debug mode");
257         return false;
258     }
259 
260     if (getuid() != 0) {
261         LogMsg(MSG_FAIL, "Operate need running as root");
262         return false;
263     }
264     struct stat info;
265     if (!lstat("/vendor", &info) && (info.st_mode & S_IFMT) == S_IFDIR) {
266         if (!RemountPartition("/vendor")) {
267             WRITE_LOG(LOG_FATAL, "Mount failed /vendor (via mount)");
268         }
269     }
270     if (!lstat("/system", &info) && (info.st_mode & S_IFMT) == S_IFDIR) {
271         if (!RemountPartition("/")) {
272             WRITE_LOG(LOG_FATAL, "Mount failed /system (via mount)");
273         }
274     }
275     if (CallRemount()) {
276         LogMsg(MSG_OK, "Mount finish");
277         return true;
278     } else {
279         LogMsg(MSG_FAIL, "Mount failed");
280         return false;
281     }
282 }
283 
RebootDevice(const string & cmd)284 bool HdcDaemonUnity::RebootDevice(const string &cmd)
285 {
286     sync();
287     return SystemDepend::RebootDevice(cmd);
288 }
289 
SetDeviceRunMode(const char * cmd)290 bool HdcDaemonUnity::SetDeviceRunMode(const char *cmd)
291 {
292     WRITE_LOG(LOG_INFO, "Set run mode:%s", cmd);
293     string tmp(cmd);
294     char *ptr = tmp.data();
295     char *token = nullptr;
296 
297 #ifdef HDC_EMULATOR
298     LogMsg(MSG_FAIL, "[E001300]Not support tmode for Emulator");
299     return true;
300 #endif
301 
302     // hdc tmode usb, do nothing
303     if (strcmp(CMDSTR_TMODE_USB.c_str(), cmd) == 0) {
304         LogMsg(MSG_FAIL, "[E001000]For USB debugging, please set it on the device's Settings UI");
305         return true;
306     }
307     // not usb and not tcp
308     if (strncmp("port", cmd, strlen("port")) != 0) {
309         LogMsg(MSG_FAIL, "[E001001]Unknown command");
310         return false;
311     }
312 
313     // bypass port
314     token = strtok_r(ptr, " ", &ptr);
315     // get next token
316     token = strtok_r(ptr, " ", &ptr);
317     // hdc tmode port
318     if (token == nullptr) {
319         LogMsg(MSG_OK, "Set device run mode successful.");
320         SystemDepend::SetDevItem("persist.hdc.mode", "tcp");
321         SystemDepend::SetDevItem("persist.hdc.mode.tcp", "enable");
322     } else {
323         /*
324         * hdc tmode port xxxxxx
325         * hdc tmode port close
326         */
327         if (strcmp(token, "close") == 0) {
328             SystemDepend::SetDevItem("persist.hdc.port", "0");
329             SystemDepend::SetDevItem("persist.hdc.mode.tcp", "disable");
330         } else {
331             string tmp(token);
332             if (tmp.find_first_not_of("0123456789") != string::npos) {
333                 LogMsg(MSG_FAIL, "[E001100]Invalid port");
334                 return false;
335             }
336             LogMsg(MSG_OK, "Set device run mode successful.");
337             SystemDepend::SetDevItem("persist.hdc.mode", "tcp");
338             SystemDepend::SetDevItem("persist.hdc.port", token);
339             SystemDepend::SetDevItem("persist.hdc.mode.tcp", "enable");
340         }
341     }
342     return true;
343 }
344 
GetHiLog(const char * cmd)345 inline bool HdcDaemonUnity::GetHiLog(const char *cmd)
346 {
347     string cmdDo = "hilog";
348     if (cmd && !strcmp(const_cast<char *>(cmd), "h")) {
349         cmdDo += " -h";
350     }
351     ExecuteShell(cmdDo.c_str());
352     return true;
353 }
354 
ListJdwpProcess(void * daemonIn)355 inline bool HdcDaemonUnity::ListJdwpProcess(void *daemonIn)
356 {
357     HdcDaemon *daemon = (HdcDaemon *)daemonIn;
358     string result = ((HdcJdwp *)daemon->clsJdwp)->GetProcessList();
359     if (!result.size()) {
360         result = EMPTY_ECHO;
361     } else {
362         result.erase(result.end() - 1);  // remove tail \n
363     }
364     LogMsg(MSG_OK, result.c_str());
365     return true;
366 }
367 
TrackJdwpProcess(void * daemonIn,const string & param)368 inline bool HdcDaemonUnity::TrackJdwpProcess(void *daemonIn, const string& param)
369 {
370     HdcDaemon *daemon = static_cast<HdcDaemon *>(daemonIn);
371     taskInfo->debugRelease = 1;
372     if (param == "p") {
373         taskInfo->debugRelease = 0;
374     } else if (param == "a") {
375         // allApp with display debug or release
376         constexpr uint8_t allAppWithDr = 3;
377         taskInfo->debugRelease = allAppWithDr;
378     }
379     if (!((static_cast<HdcJdwp *>(daemon->clsJdwp))->CreateJdwpTracker(taskInfo))) {
380         string result = MESSAGE_FAIL;
381         LogMsg(MSG_OK, result.c_str());
382         return false;
383     }
384     return true;
385 }
386 
RemoveJdwpTracker()387 inline void HdcDaemonUnity::RemoveJdwpTracker()
388 {
389     HdcDaemon *daemon = static_cast<HdcDaemon *>(taskInfo->ownerSessionClass);
390     (static_cast<HdcJdwp *>(daemon->clsJdwp))->RemoveJdwpTracker(taskInfo);
391 }
392 
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)393 bool HdcDaemonUnity::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
394 {
395     bool ret = true;
396     HdcDaemon *daemon = (HdcDaemon *)taskInfo->ownerSessionClass;
397     // Both are not executed, do not need to be detected 'childReady'
398     string strPayload = string(reinterpret_cast<char *>(payload), payloadSize);
399     WRITE_LOG(LOG_INFO, "Unity CommandDispatch command:%d cid:%u sid:%u", command, taskInfo->channelId,
400         taskInfo->sessionId);
401     switch (command) {
402         case CMD_UNITY_EXECUTE: {
403             ExecuteShell(const_cast<char *>(strPayload.c_str()));
404             break;
405         }
406         case CMD_UNITY_EXECUTE_EX: {
407             if (ExecuteShellExtend(payload, payloadSize) != 0) {
408                 ret = false;
409             }
410             break;
411         }
412         case CMD_UNITY_REMOUNT: {
413             ret = false;
414             RemountDevice();
415             break;
416         }
417         case CMD_UNITY_REBOOT: {
418             ret = false;
419             RebootDevice(strPayload);
420             break;
421         }
422         case CMD_UNITY_RUNMODE: {
423             ret = false;
424             SetDeviceRunMode(strPayload.c_str());
425             break;
426         }
427         case CMD_UNITY_HILOG: {
428             GetHiLog(strPayload.c_str());
429             break;
430         }
431         case CMD_UNITY_ROOTRUN: {
432             ret = false;
433             string debugMode;
434             // hdcd restart in old pid
435             bool restart = true;
436             SystemDepend::GetDevItem("const.debuggable", debugMode);
437             if (debugMode == "1") {
438                 if (payloadSize != 0 && !strcmp(strPayload.c_str(), "r")) {
439                     SystemDepend::SetDevItem("persist.hdc.root", "0");
440                 } else {
441                     // hdcd restart in new pid
442                     restart = false;
443                     SystemDepend::SetDevItem("persist.hdc.root", "1");
444                 }
445             } else {
446                 LogMsg(MSG_FAIL, "Cannot set root run mode in undebuggable version.");
447                 return false;
448             }
449             daemon->PostStopInstanceMessage(restart);
450             break;
451         }
452         case CMD_UNITY_BUGREPORT_INIT: {
453             currentDataCommand = CMD_UNITY_BUGREPORT_DATA;
454             ExecuteShell("hidumper");
455             break;
456         }
457         case CMD_JDWP_LIST: {
458             ret = false;
459             ListJdwpProcess(daemon);
460             break;
461         }
462         case CMD_JDWP_TRACK: {
463             if (!TrackJdwpProcess(daemon, strPayload)) {
464                 ret = false;
465             }
466             break;
467         }
468         default:
469             break;
470     }
471     WRITE_LOG(LOG_INFO, "Unity CommandDispatch command:%d finish cid:%u sid:%u", command, taskInfo->channelId,
472         taskInfo->sessionId);
473     return ret;
474 };
475 }  // namespace Hdc
476