* Copyright (C) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "daemon.h"
#include <openssl/sha.h>
#include "daemon_updater.h"
#include "flashd_define.h"
#include "serial_struct.h"
namespace Hdc {
HdcDaemon::HdcDaemon(bool serverOrDaemonIn)
: HdcSessionBase(serverOrDaemonIn)
{
clsTCPServ = nullptr;
clsUSBServ = nullptr;
clsJdwp = nullptr;
authEnable = false;
}
HdcDaemon::~HdcDaemon()
{
WRITE_LOG(LOG_DEBUG, "~HdcDaemon");
}
void HdcDaemon::ClearInstanceResource()
{
TryStopInstance();
Base::TryCloseLoop(&loopMain, "HdcDaemon::~HdcDaemon");
if (clsTCPServ) {
delete (HdcDaemonTCP *)clsTCPServ;
clsTCPServ = nullptr;
}
if (clsUSBServ) {
delete (HdcDaemonUSB *)clsUSBServ;
clsUSBServ = nullptr;
}
if (clsJdwp) {
delete (HdcJdwp *)clsJdwp;
clsJdwp = nullptr;
}
WRITE_LOG(LOG_DEBUG, "~HdcDaemon finish");
}
void HdcDaemon::TryStopInstance()
{
ClearSessions();
if (clsTCPServ) {
WRITE_LOG(LOG_DEBUG, "Stop TCP");
((HdcDaemonTCP *)clsTCPServ)->Stop();
}
if (clsUSBServ) {
WRITE_LOG(LOG_DEBUG, "Stop USB");
((HdcDaemonUSB *)clsUSBServ)->Stop();
}
((HdcJdwp *)clsJdwp)->Stop();
ReMainLoopForInstanceClear();
WRITE_LOG(LOG_DEBUG, "Stop loopmain");
}
void HdcDaemon::InitMod(bool bEnableTCP, bool bEnableUSB)
{
WRITE_LOG(LOG_DEBUG, "HdcDaemon InitMod");
if (bEnableTCP) {
clsTCPServ = new HdcDaemonTCP(false, this);
((HdcDaemonTCP *)clsTCPServ)->Initial();
}
if (bEnableUSB) {
clsUSBServ = new HdcDaemonUSB(false, this);
((HdcDaemonUSB *)clsUSBServ)->Initial();
}
LoopStatus ls(&loopMain, "not support");
clsJdwp = new HdcJdwp(&loopMain, &ls);
((HdcJdwp *)clsJdwp)->Initial();
string secure;
SystemDepend::GetDevItem("ro.hdc.secure", secure);
authEnable = (Base::Trim(secure) == "1");
}
bool HdcDaemon::RedirectToTask(HTaskInfo hTaskInfo, HSession hSession, const uint32_t channelId,
const uint16_t command, uint8_t *payload, const int payloadSize)
{
bool ret = true;
hTaskInfo->ownerSessionClass = this;
WRITE_LOG(LOG_DEBUG, "RedirectToTask command %d", command);
switch (command) {
#ifndef UPDATER_BUILD_VARIANT_USER
case CMD_UNITY_EXECUTE:
ret = TaskCommandDispatch<HdcDaemonUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
break;
case CMD_SHELL_INIT:
case CMD_SHELL_DATA:
ret = TaskCommandDispatch<HdcShell>(hTaskInfo, TYPE_SHELL, command, payload, payloadSize);
break;
case CMD_FILE_CHECK:
case CMD_FILE_DATA:
case CMD_FILE_FINISH:
case CMD_FILE_INIT:
case CMD_FILE_BEGIN:
ret = TaskCommandDispatch<HdcFile>(hTaskInfo, TASK_FILE, command, payload, payloadSize);
break;
#endif
case CMD_UNITY_REBOOT:
case CMD_UNITY_HILOG:
ret = TaskCommandDispatch<HdcDaemonUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
break;
case CMD_UPDATER_UPDATE_INIT:
case CMD_UPDATER_FLASH_INIT:
case CMD_UPDATER_CHECK:
case CMD_UPDATER_BEGIN:
case CMD_UPDATER_DATA:
case CMD_UPDATER_FINISH:
case CMD_UPDATER_ERASE:
case CMD_UPDATER_FORMAT:
case CMD_UPDATER_PROGRESS:
ret = TaskCommandDispatch<DaemonUpdater>(hTaskInfo, TASK_UPDATER, command, payload, payloadSize);
break;
case CMD_UNITY_REMOUNT:
case CMD_UNITY_RUNMODE:
case CMD_UNITY_ROOTRUN:
case CMD_UNITY_BUGREPORT_INIT:
case CMD_JDWP_LIST:
case CMD_JDWP_TRACK:
ret = TaskCommandDispatch<InvalidDaemon>(hTaskInfo, TASK_FAKE, command, payload, payloadSize);
break;
default:
break;
}
return ret;
}
bool HdcDaemon::HandDaemonAuth(HSession hSession, const uint32_t channelId, SessionHandShake &handshake)
{
bool ret = false;
switch (handshake.authType) {
case AUTH_NONE: {
hSession->tokenRSA = Base::GetRandomString(SHA_DIGEST_LENGTH);
handshake.authType = AUTH_TOKEN;
handshake.buf = hSession->tokenRSA;
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE, (uint8_t *)bufString.c_str(), bufString.size());
ret = true;
break;
}
case AUTH_SIGNATURE: {
if (!HdcAuth::AuthVerify((uint8_t *)hSession->tokenRSA.c_str(),
(uint8_t *)handshake.buf.c_str(), handshake.buf.size())) {
handshake.authType = AUTH_TOKEN;
handshake.buf = hSession->tokenRSA;
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE, (uint8_t *)bufString.c_str(),
bufString.size());
break;
}
ret = true;
break;
}
case AUTH_PUBLICKEY: {
ret = HdcAuth::PostUIConfirm(handshake.buf);
WRITE_LOG(LOG_DEBUG, "Auth host OK, postUIConfirm");
break;
}
default:
break;
}
return ret;
}
bool HdcDaemon::DaemonSessionHandshake(HSession hSession, const uint32_t channelId, uint8_t *payload, int payloadSize)
{
string s = string((char *)payload, payloadSize);
SessionHandShake handshake;
string err;
SerialStruct::ParseFromString(handshake, s);
if (handshake.banner != HANDSHAKE_MESSAGE) {
hSession->availTailIndex = 0;
WRITE_LOG(LOG_FATAL, "Recv server-hello failed");
return false;
}
if (handshake.authType == AUTH_NONE) {
uint32_t unOld = hSession->sessionId;
hSession->sessionId = handshake.sessionId;
hSession->connectKey = handshake.connectKey;
AdminSession(OP_UPDATE, unOld, hSession);
if (clsUSBServ != nullptr) {
(reinterpret_cast<HdcDaemonUSB *>(clsUSBServ))->OnNewHandshakeOK(hSession->sessionId);
}
handshake.sessionId = 0;
handshake.connectKey = "";
}
if (authEnable && !HandDaemonAuth(hSession, channelId, handshake)) {
return false;
}
char hostName[BUF_SIZE_MEDIUM] = "";
size_t len = sizeof(hostName);
uv_os_gethostname(hostName, &len);
handshake.authType = AUTH_OK;
handshake.buf = hostName;
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE, (uint8_t *)bufString.c_str(), bufString.size());
hSession->handshakeOK = true;
return true;
}
bool HdcDaemon::FetchCommand(HSession hSession, const uint32_t channelId, const uint16_t command, uint8_t *payload,
int payloadSize)
{
WRITE_LOG(LOG_DEBUG, "FetchCommand command %d", command);
bool ret = true;
if (!hSession->handshakeOK && command != CMD_KERNEL_HANDSHAKE) {
ret = false;
return ret;
}
switch (command) {
case CMD_KERNEL_HANDSHAKE: {
ret = DaemonSessionHandshake(hSession, channelId, payload, payloadSize);
break;
}
case CMD_KERNEL_CHANNEL_CLOSE: {
ClearOwnTasks(hSession, channelId);
if (*payload != 0) {
--(*payload);
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, payload, 1);
}
ret = true;
break;
}
default:
ret = DispatchTaskData(hSession, channelId, command, payload, payloadSize);
break;
}
return ret;
}
bool HdcDaemon::RemoveInstanceTask(const uint8_t op, HTaskInfo hTask)
{
bool ret = true;
switch (hTask->taskType) {
case TYPE_UNITY:
ret = DoTaskRemove<HdcDaemonUnity>(hTask, op);
break;
case TYPE_SHELL:
ret = DoTaskRemove<HdcShell>(hTask, op);
break;
case TASK_FILE:
ret = DoTaskRemove<HdcTransferBase>(hTask, op);
break;
case TASK_FORWARD:
ret = DoTaskRemove<HdcDaemonForward>(hTask, op);
break;
case TASK_APP:
ret = DoTaskRemove<HdcDaemonApp>(hTask, op);
break;
case TASK_UPDATER:
ret = DoTaskRemove<DaemonUpdater>(hTask, op);
break;
default:
ret = false;
break;
}
return ret;
}
bool HdcDaemon::ServerCommand(const uint32_t sessionId, const uint32_t channelId, const uint16_t command,
uint8_t *bufPtr, const int size)
{
return Send(sessionId, channelId, command, (uint8_t *)bufPtr, size) > 0;
}
void HdcDaemon::JdwpNewFileDescriptor(const uint8_t *buf, const int bytesIO)
{
if (bytesIO < 9) {
return;
}
uint32_t pid = *(uint32_t *)(buf + 1);
uint32_t fd = *(uint32_t *)(buf + 5);
((HdcJdwp *)clsJdwp)->SendJdwpNewFD(pid, fd);
};
void HdcDaemon::NotifyInstanceSessionFree(HSession hSession, bool freeOrClear)
{
if (!freeOrClear) {
return;
}
if (clsUSBServ != nullptr) {
auto clsUsbModule = reinterpret_cast<HdcDaemonUSB *>(clsUSBServ);
clsUsbModule->OnSessionFreeFinally(hSession);
}
}
}