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