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