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 #ifdef __MUSL__
18 #include "init_reboot.h"
19 #endif
20
21 namespace Hdc {
HdcDaemonUnity(HTaskInfo hTaskInfo)22 HdcDaemonUnity::HdcDaemonUnity(HTaskInfo hTaskInfo)
23 : HdcTaskBase(hTaskInfo)
24 {
25 currentDataCommand = CMD_KERNEL_ECHO_RAW; // Default output to shelldata
26 }
27
~HdcDaemonUnity()28 HdcDaemonUnity::~HdcDaemonUnity()
29 {
30 WRITE_LOG(LOG_DEBUG, "HdcDaemonUnity::~HdcDaemonUnity finish");
31 }
32
StopTask()33 void HdcDaemonUnity::StopTask()
34 {
35 asyncCommand.DoRelease();
36 };
37
ReadyForRelease()38 bool HdcDaemonUnity::ReadyForRelease()
39 {
40 if (!HdcTaskBase::ReadyForRelease() || !asyncCommand.ReadyForRelease()) {
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, (uint8_t *)result.c_str(), 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 = std::bind(&HdcDaemonUnity::AsyncCmdOut,
76 this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
77 if (!asyncCommand.Initial(loopTask, funcResultOutput,
78 asyncCommand.GetDefaultOption() | asyncCommand.OPTION_READBACK_OUT)) {
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 close(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 close(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, "Opearte 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 #ifndef __MUSL__
178 string propertyVal;
179 if (!cmd.size()) {
180 propertyVal = "reboot";
181 } else {
182 propertyVal = Base::StringFormat("reboot,%s", cmd.c_str());
183 }
184 return Base::SetHdcProperty(rebootProperty.c_str(), propertyVal.c_str());
185 #else
186 string reason;
187 if (cmd == "recovery") {
188 reason = "updater";
189 } else if (cmd == "bootloader") {
190 reason = "NoArgument";
191 } else {
192 reason = cmd;
193 }
194 return DoReboot(reason.c_str());
195 #endif
196 }
197
SetDeviceRunMode(void * daemonIn,const char * cmd)198 bool HdcDaemonUnity::SetDeviceRunMode(void *daemonIn, const char *cmd)
199 {
200 HdcDaemon *daemon = (HdcDaemon *)daemonIn;
201 WRITE_LOG(LOG_DEBUG, "Set run mode:%s", cmd);
202 if (!strcmp(CMDSTR_TMODE_USB.c_str(), cmd)) {
203 Base::SetHdcProperty("persist.hdc.mode", CMDSTR_TMODE_USB.c_str());
204 } else if (!strncmp("port", cmd, strlen("port"))) {
205 Base::SetHdcProperty("persist.hdc.mode", CMDSTR_TMODE_TCP.c_str());
206 if (!strncmp("port ", cmd, strlen("port "))) {
207 const char *port = cmd + 5;
208 Base::SetHdcProperty("persist.hdc.port", port);
209 }
210 } else {
211 LogMsg(MSG_FAIL, "Unknow command");
212 return false;
213 }
214 // shutdown
215 daemon->PostStopInstanceMessage(true);
216 LogMsg(MSG_OK, "Set device run mode successful.");
217 return true;
218 }
219
GetHiLog(const char * cmd)220 inline bool HdcDaemonUnity::GetHiLog(const char *cmd)
221 {
222 string cmdDo = "hilog";
223 if (cmd && !strcmp((char *)cmd, "v")) {
224 cmdDo += " -v long";
225 }
226 ExecuteShell(cmdDo.c_str());
227 return true;
228 }
229
ListJdwpProcess(void * daemonIn)230 inline bool HdcDaemonUnity::ListJdwpProcess(void *daemonIn)
231 {
232 HdcDaemon *daemon = (HdcDaemon *)daemonIn;
233 string result = ((HdcJdwp *)daemon->clsJdwp)->GetProcessList();
234 if (!result.size()) {
235 result = EMPTY_ECHO;
236 } else {
237 result.erase(result.end() - 1); // remove tail \n
238 }
239 LogMsg(MSG_OK, result.c_str());
240 return true;
241 }
242
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)243 bool HdcDaemonUnity::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
244 {
245 bool ret = true;
246 HdcDaemon *daemon = (HdcDaemon *)taskInfo->ownerSessionClass;
247 // Both are not executed, do not need to be detected 'childReady'
248 string strPayload = string((char *)payload, payloadSize);
249 switch (command) {
250 case CMD_UNITY_EXECUTE: {
251 ExecuteShell((char *)strPayload.c_str());
252 break;
253 }
254 case CMD_UNITY_REMOUNT: {
255 ret = false;
256 RemountDevice();
257 break;
258 }
259 case CMD_UNITY_REBOOT: {
260 ret = false;
261 RebootDevice(strPayload);
262 break;
263 }
264 case CMD_UNITY_RUNMODE: {
265 ret = false;
266 SetDeviceRunMode(daemon, strPayload.c_str());
267 break;
268 }
269 case CMD_UNITY_HILOG: {
270 GetHiLog(strPayload.c_str());
271 break;
272 }
273 case CMD_UNITY_ROOTRUN: {
274 ret = false;
275 if (payloadSize != 0 && !strcmp((char *)strPayload.c_str(), "r")) {
276 Base::SetHdcProperty("persist.hdc.root", "0");
277 } else {
278 Base::SetHdcProperty("persist.hdc.root", "1");
279 }
280 daemon->PostStopInstanceMessage(true);
281 break;
282 }
283 case CMD_UNITY_TERMINATE: {
284 daemon->PostStopInstanceMessage(!strcmp((char *)strPayload.c_str(), "1"));
285 break;
286 }
287 case CMD_UNITY_BUGREPORT_INIT: {
288 currentDataCommand = CMD_UNITY_BUGREPORT_DATA;
289 ExecuteShell((char *)CMDSTR_BUGREPORT.c_str());
290 break;
291 }
292 case CMD_UNITY_JPID: {
293 ret = false;
294 ListJdwpProcess(daemon);
295 break;
296 }
297 default:
298 break;
299 }
300 return ret;
301 };
302 } // namespace Hdc
303