• 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 #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