• 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 "daemon_unity.h"
16 #include <sys/mount.h>
17 
18 namespace Hdc {
HdcDaemonUnity(HTaskInfo hTaskInfo)19 HdcDaemonUnity::HdcDaemonUnity(HTaskInfo hTaskInfo)
20     : HdcTaskBase(hTaskInfo)
21 {
22     currentDataCommand = CMD_KERNEL_ECHO_RAW;  // Default output to shelldata
23 }
24 
~HdcDaemonUnity()25 HdcDaemonUnity::~HdcDaemonUnity()
26 {
27     WRITE_LOG(LOG_DEBUG, "~HdcDaemonUnity channelId:%u", taskInfo->channelId);
28 }
29 
StopTask()30 void HdcDaemonUnity::StopTask()
31 {
32     // Remove jpid tracker when stopping task
33     RemoveJdwpTracker();
34     asyncCommand.DoRelease();
35 }
36 
ReadyForRelease()37 bool HdcDaemonUnity::ReadyForRelease()
38 {
39     if (!HdcTaskBase::ReadyForRelease() || !asyncCommand.ReadyForRelease()) {
40         WRITE_LOG(LOG_DEBUG, "not ready for release channelId:%u", taskInfo->channelId);
41         return false;
42     }
43     return true;
44 }
45 
AsyncCmdOut(bool finish,int64_t exitStatus,const string result)46 bool HdcDaemonUnity::AsyncCmdOut(bool finish, int64_t exitStatus, const string result)
47 {
48 #ifdef UNIT_TEST
49     Base::WriteBinFile((UT_TMP_PATH + "/execute.result").c_str(), (uint8_t *)result.c_str(), result.size(),
50                        countUt++ == 0);
51 #endif
52     bool ret = false;
53     bool wantFinish = false;
54     do {
55         if (finish) {
56             wantFinish = true;
57             ret = true;
58             --refCount;
59             break;
60         }
61         if (!SendToAnother(currentDataCommand, reinterpret_cast<uint8_t *>(const_cast<char *>(result.c_str())),
62             result.size())) {
63             break;
64         }
65         ret = true;
66     } while (false);
67     if (wantFinish) {
68         TaskFinish();
69     }
70     return ret;
71 }
72 
ExecuteShell(const char * shellCommand)73 int HdcDaemonUnity::ExecuteShell(const char *shellCommand)
74 {
75     do {
76         AsyncCmd::CmdResultCallback funcResultOutput;
77         funcResultOutput = std::bind(&HdcDaemonUnity::AsyncCmdOut, this, std::placeholders::_1, std::placeholders::_2,
78                                      std::placeholders::_3);
79         if (!asyncCommand.Initial(loopTask, funcResultOutput)) {
80             break;
81         }
82         asyncCommand.ExecuteCommand(shellCommand);
83         ++refCount;
84         return RET_SUCCESS;
85     } while (false);
86 
87     TaskFinish();
88     WRITE_LOG(LOG_DEBUG, "Shell failed finish");
89     return -1;
90 }
91 
FindMountDeviceByPath(const char * toQuery,char * dev)92 bool HdcDaemonUnity::FindMountDeviceByPath(const char *toQuery, char *dev)
93 {
94     int fd;
95     int res;
96     char *token = nullptr;
97     const char delims[] = "\n";
98     char buf[BUF_SIZE_DEFAULT2];
99 
100     fd = open("/proc/mounts", O_RDONLY | O_CLOEXEC);
101     if (fd < 0) {
102         return false;
103     }
104     read(fd, buf, sizeof(buf) - 1);
105     Base::CloseFd(fd);
106     buf[sizeof(buf) - 1] = '\0';
107     token = strtok(buf, delims);
108 
109     while (token) {
110         char dir[BUF_SIZE_SMALL] = "";
111         int freq;
112         int passnno;
113         // clang-format off
114         res = sscanf_s(token, "%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             return true;
121         }
122         token = strtok(nullptr, delims);
123     }
124     return false;
125 }
126 
RemountPartition(const char * dir)127 bool HdcDaemonUnity::RemountPartition(const char *dir)
128 {
129     int fd;
130     int off = 0;
131     char dev[BUF_SIZE_SMALL] = "";
132 
133     if (!FindMountDeviceByPath(dir, dev) || strlen(dev) < 4) {  // 4 : file count
134         WRITE_LOG(LOG_DEBUG, "FindMountDeviceByPath failed");
135         return false;
136     }
137 
138     if ((fd = open(dev, O_RDONLY | O_CLOEXEC)) < 0) {
139         WRITE_LOG(LOG_DEBUG, "Open device:%s failed, error:%d", dev, errno);
140         return false;
141     }
142     ioctl(fd, BLKROSET, &off);
143     Base::CloseFd(fd);
144 
145     if (mount(dev, dir, "none", MS_REMOUNT, nullptr) < 0) {
146         WRITE_LOG(LOG_DEBUG, "Mount device failed");
147         return false;
148     }
149     return true;
150 }
151 
RemountDevice()152 bool HdcDaemonUnity::RemountDevice()
153 {
154     if (getuid() != 0) {
155         LogMsg(MSG_FAIL, "Operate need running as root");
156         return false;
157     }
158     struct stat info;
159     if (!lstat("/vendor", &info) && (info.st_mode & S_IFMT) == S_IFDIR) {
160         // has vendor
161         if (!RemountPartition("/vendor")) {
162             LogMsg(MSG_FAIL, "Mount failed");
163             return false;
164         }
165     }
166     if (!lstat("/data", &info) && (info.st_mode & S_IFMT) == S_IFDIR) {
167         if (!RemountPartition("/data")) {
168             return false;
169         }
170     }
171     LogMsg(MSG_OK, "Mount finish");
172     return true;
173 }
174 
RebootDevice(const string & cmd)175 bool HdcDaemonUnity::RebootDevice(const string &cmd)
176 {
177     sync();
178     return SystemDepend::RebootDevice(cmd);
179 }
180 
SetDeviceRunMode(void * daemonIn,const char * cmd)181 bool HdcDaemonUnity::SetDeviceRunMode(void *daemonIn, const char *cmd)
182 {
183     HdcDaemon *daemon = (HdcDaemon *)daemonIn;
184     WRITE_LOG(LOG_DEBUG, "Set run mode:%s", cmd);
185     if (!strcmp(CMDSTR_TMODE_USB.c_str(), cmd)) {
186         SystemDepend::SetDevItem("persist.hdc.mode", CMDSTR_TMODE_USB.c_str());
187     } else if (!strncmp("port", cmd, strlen("port"))) {
188         SystemDepend::SetDevItem("persist.hdc.mode", CMDSTR_TMODE_TCP.c_str());
189         if (!strncmp("port ", cmd, strlen("port "))) {
190             const char *port = cmd + 5;
191             SystemDepend::SetDevItem("persist.hdc.port", port);
192         }
193     } else {
194         LogMsg(MSG_FAIL, "Unknown command");
195         return false;
196     }
197     // shutdown
198     daemon->PostStopInstanceMessage(true);
199     LogMsg(MSG_OK, "Set device run mode successful.");
200     return true;
201 }
202 
GetHiLog(const char * cmd)203 inline bool HdcDaemonUnity::GetHiLog(const char *cmd)
204 {
205     string cmdDo = "hilog";
206     if (cmd && !strcmp(const_cast<char *>(cmd), "h")) {
207         cmdDo += " -h";
208     }
209     ExecuteShell(cmdDo.c_str());
210     return true;
211 }
212 
ListJdwpProcess(void * daemonIn)213 inline bool HdcDaemonUnity::ListJdwpProcess(void *daemonIn)
214 {
215     HdcDaemon *daemon = (HdcDaemon *)daemonIn;
216     string result = ((HdcJdwp *)daemon->clsJdwp)->GetProcessList();
217     if (!result.size()) {
218         result = EMPTY_ECHO;
219     } else {
220         result.erase(result.end() - 1);  // remove tail \n
221     }
222     LogMsg(MSG_OK, result.c_str());
223     return true;
224 }
225 
TrackJdwpProcess(void * daemonIn,const string & param)226 inline bool HdcDaemonUnity::TrackJdwpProcess(void *daemonIn, const string& param)
227 {
228     HdcDaemon *daemon = static_cast<HdcDaemon *>(daemonIn);
229     taskInfo->debugRelease = 1;
230     if (param == "p") {
231         taskInfo->debugRelease = 0;
232     }
233     if (!((static_cast<HdcJdwp *>(daemon->clsJdwp))->CreateJdwpTracker(taskInfo))) {
234         string result = MESSAGE_FAIL;
235         LogMsg(MSG_OK, result.c_str());
236         return false;
237     }
238     return true;
239 }
240 
RemoveJdwpTracker()241 inline void HdcDaemonUnity::RemoveJdwpTracker()
242 {
243     HdcDaemon *daemon = static_cast<HdcDaemon *>(taskInfo->ownerSessionClass);
244     (static_cast<HdcJdwp *>(daemon->clsJdwp))->RemoveJdwpTracker(taskInfo);
245 }
246 
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)247 bool HdcDaemonUnity::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
248 {
249     bool ret = true;
250     HdcDaemon *daemon = (HdcDaemon *)taskInfo->ownerSessionClass;
251     // Both are not executed, do not need to be detected 'childReady'
252     string strPayload = string(reinterpret_cast<char *>(payload), payloadSize);
253 #ifdef HDC_DEBUG
254     WRITE_LOG(LOG_DEBUG, "CommandDispatch command:%d", command);
255 #endif // HDC_DEBUG
256     switch (command) {
257         case CMD_UNITY_EXECUTE: {
258             ExecuteShell(const_cast<char *>(strPayload.c_str()));
259             break;
260         }
261         case CMD_UNITY_REMOUNT: {
262             ret = false;
263             RemountDevice();
264             break;
265         }
266         case CMD_UNITY_REBOOT: {
267             ret = false;
268             RebootDevice(strPayload);
269             break;
270         }
271         case CMD_UNITY_RUNMODE: {
272             ret = false;
273             SetDeviceRunMode(daemon, strPayload.c_str());
274             break;
275         }
276         case CMD_UNITY_HILOG: {
277             GetHiLog(strPayload.c_str());
278             break;
279         }
280         case CMD_UNITY_ROOTRUN: {
281             ret = false;
282 #ifndef HDC_BUILD_VARIANT_USER
283             string debugMode;
284             // hdcd restart in old pid
285             bool restart = true;
286             SystemDepend::GetDevItem("const.debuggable", debugMode);
287             if (debugMode == "1") {
288                 if (payloadSize != 0 && !strcmp(strPayload.c_str(), "r")) {
289                     SystemDepend::SetDevItem("persist.hdc.root", "0");
290                 } else {
291                     // hdcd restart in new pid
292                     restart = false;
293                     SystemDepend::SetDevItem("persist.hdc.root", "1");
294                 }
295             }
296             daemon->PostStopInstanceMessage(restart);
297 #endif
298             break;
299         }
300         case CMD_UNITY_TERMINATE: {
301             daemon->PostStopInstanceMessage(!strcmp(const_cast<char *>(strPayload.c_str()), "1"));
302             break;
303         }
304         case CMD_UNITY_BUGREPORT_INIT: {
305             currentDataCommand = CMD_UNITY_BUGREPORT_DATA;
306             ExecuteShell("hidumper");
307             break;
308         }
309         case CMD_JDWP_LIST: {
310             ret = false;
311             ListJdwpProcess(daemon);
312             break;
313         }
314         case CMD_JDWP_TRACK: {
315             if (!TrackJdwpProcess(daemon, strPayload)) {
316                 ret = false;
317             }
318             break;
319         }
320         default:
321             break;
322     }
323 #ifdef HDC_DEBUG
324     WRITE_LOG(LOG_DEBUG, "CommandDispatch command:%d finish.", command);
325 #endif // HDC_LOCAL_DEBUG
326     return ret;
327 };
328 }  // namespace Hdc
329