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