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