* Copyright (C) 2023 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.
*/
#define private public
#define protected public
#include "full_ime_info_manager.h"
#include "settings_data_utils.h"
#include "user_session_manager.h"
#include "task_manager.h"
#undef private
#include <unistd.h>
#include <csignal>
#include <cstdint>
#include <sstream>
#include <string>
#include <vector>
#include "accesstoken_kit.h"
#include "datashare_helper.h"
#include "display_info.h"
#include "display_manager_lite.h"
#include "global.h"
#include "if_system_ability_manager.h"
#include "input_method_controller.h"
#include "iservice_registry.h"
#include "nativetoken_kit.h"
#include "os_account_manager.h"
#include "scope_utils.h"
#include "system_ability.h"
#include "system_ability_definition.h"
#include "tdd_util.h"
#include "token_setproc.h"
namespace OHOS {
namespace MiscServices {
using namespace OHOS::Security::AccessToken;
using namespace OHOS::AccountSA;
using namespace Rosen;
constexpr int32_t INVALID_USER_ID = -1;
constexpr int32_t MAIN_USER_ID = 100;
constexpr const uint16_t EACH_LINE_LENGTH = 500;
constexpr int32_t PERMISSION_NUM = 7;
constexpr int32_t FIRST_PARAM_INDEX = 0;
constexpr int32_t SECOND_PARAM_INDEX = 1;
constexpr int32_t THIRD_PARAM_INDEX = 2;
constexpr int32_t FOURTH_PARAM_INDEX = 3;
constexpr int32_t FIFTH_PARAM_INDEX = 4;
constexpr int32_t SIXTH_PARAM_INDEX = 5;
constexpr int32_t SEVENTH_PARAM_INDEX = 6;
static constexpr int32_t MAX_TIMEOUT_WAIT_FOCUS = 2000;
constexpr int32_t WAIT_CLICK_COMPLETE = 100;
uint64_t TddUtil::selfTokenID_ = 0;
int32_t TddUtil::userID_ = INVALID_USER_ID;
std::string TddUtil::currentBundleNameMock_;
sptr<Window> TddUtil::WindowManager::window_ = nullptr;
int32_t TddUtil::WindowManager::currentWindowId_ = 0;
uint64_t TddUtil::WindowManager::windowTokenId_ = 0;
std::shared_ptr<BlockData<bool>> FocusChangedListenerTestImpl::isFocused_ =
std::make_shared<BlockData<bool>>(MAX_TIMEOUT_WAIT_FOCUS, false);
std::shared_ptr<BlockData<bool>> FocusChangedListenerTestImpl::unFocused_ =
std::make_shared<BlockData<bool>>(MAX_TIMEOUT_WAIT_FOCUS, false);
static constexpr const char *ENABLE_IME = "settings.inputmethod.enable_ime";
void FocusChangedListenerTestImpl::OnFocused(const sptr<Rosen::FocusChangeInfo> &focusChangeInfo)
{
IMSA_HILOGI("get onFocus information from window manager.");
if (focusChangeInfo->windowId_ == TddUtil::WindowManager::currentWindowId_) {
getFocus_ = true;
isFocused_->SetValue(getFocus_);
unFocused_->Clear(false);
}
}
void FocusChangedListenerTestImpl::OnUnfocused(const sptr<Rosen::FocusChangeInfo> &focusChangeInfo)
{
IMSA_HILOGI("get unfocus information from window manager.");
if (focusChangeInfo->windowId_ == TddUtil::WindowManager::currentWindowId_) {
getFocus_ = false;
isFocused_->Clear(false);
bool unFocus = !getFocus_;
unFocused_->SetValue(unFocus);
}
}
int32_t TddUtil::GetCurrentUserId()
{
if (userID_ != INVALID_USER_ID) {
return userID_;
}
int32_t userId = -1;
auto ret = OsAccountManager::GetForegroundOsAccountLocalId(userId);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetForegroundOsAccountLocalId failed");
return MAIN_USER_ID;
}
return userId;
}
void TddUtil::StorageSelfTokenID()
{
selfTokenID_ = GetSelfTokenID();
}
uint64_t TddUtil::AllocTestTokenID(
bool isSystemApp, const std::string &bundleName, const std::vector<std::string> &premission)
{
IMSA_HILOGI("bundleName: %{public}s", bundleName.c_str());
HapInfoParams infoParams = { .userID = GetCurrentUserId(),
.bundleName = bundleName,
.instIndex = 0,
.appIDDesc = bundleName,
.isSystemApp = isSystemApp };
std::vector<PermissionStateFull> permStateList;
for (const auto &prem : premission) {
PermissionStateFull permissionState = { .permissionName = prem,
.isGeneral = true,
.resDeviceID = { "local" },
.grantStatus = { PermissionState::PERMISSION_GRANTED },
.grantFlags = { 1 } };
permStateList.push_back(permissionState);
}
HapPolicyParams policyParams = {
.apl = APL_NORMAL, .domain = bundleName, .permList = {}, .permStateList = permStateList
};
if (premission.empty()) {
policyParams = { .apl = APL_NORMAL, .domain = bundleName, .permList = {}, .permStateList = {} };
}
auto tokenInfo = AccessTokenKit::AllocHapToken(infoParams, policyParams);
return tokenInfo.tokenIDEx;
}
uint64_t TddUtil::GetTestTokenID(const std::string &bundleName)
{
HapInfoParams infoParams = { .userID = GetCurrentUserId(), .bundleName = bundleName,
.instIndex = 0, .appIDDesc = "ohos.inputmethod_test.demo"
};
return AccessTokenKit::GetHapTokenID(infoParams.userID, infoParams.bundleName, infoParams.instIndex);
}
void TddUtil::DeleteTestTokenID(uint64_t tokenId)
{
AccessTokenKit::DeleteToken(tokenId);
}
void TddUtil::SetTestTokenID(uint64_t tokenId)
{
auto ret = SetSelfTokenID(tokenId);
IMSA_HILOGI("SetSelfTokenID ret: %{public}d", ret);
}
void TddUtil::RestoreSelfTokenID()
{
auto ret = SetSelfTokenID(selfTokenID_);
IMSA_HILOGI("SetSelfTokenID ret = %{public}d", ret);
}
uint64_t TddUtil::GetCurrentTokenID()
{
return GetSelfTokenID();
}
int32_t TddUtil::GetUid(const std::string &bundleName)
{
auto bundleMgr = GetBundleMgr();
if (bundleMgr == nullptr) {
IMSA_HILOGE("bundleMgr nullptr");
return -1;
}
auto uid = bundleMgr->GetUidByBundleName(bundleName, GetCurrentUserId());
if (uid == -1) {
IMSA_HILOGE("failed to get information and the parameters may be wrong.");
return -1;
}
IMSA_HILOGI("bundleName: %{public}s, uid: %{public}d", bundleName.c_str(), uid);
return uid;
}
void TddUtil::SetSelfUid(int32_t uid)
{
setuid(uid);
IMSA_HILOGI("set uid to: %{public}d", uid);
}
bool TddUtil::ExecuteCmd(const std::string &cmd, std::string &result)
{
char buff[EACH_LINE_LENGTH] = { 0x00 };
std::stringstream output;
FILE *ptr = popen(cmd.c_str(), "r");
if (ptr != nullptr) {
IMSA_HILOGI("Execute cmd: %{public}s", cmd.c_str());
while (fgets(buff, sizeof(buff), ptr) != nullptr) {
output << buff;
}
pclose(ptr);
ptr = nullptr;
} else {
return false;
}
result = output.str();
return true;
}
pid_t TddUtil::GetImsaPid()
{
auto currentToken = GetSelfTokenID();
GrantNativePermission();
auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
SystemProcessInfo info;
int32_t ret = saMgr->GetSystemProcessInfo(INPUT_METHOD_SYSTEM_ABILITY_ID, info);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to get sa info, ret: %{public}d", ret);
return -1;
}
SetSelfTokenID(currentToken);
return info.pid;
}
bool TddUtil::KillImsaProcess()
{
pid_t pid = GetImsaPid();
if (pid == -1) {
IMSA_HILOGE("failed to get pid");
return false;
}
auto ret = kill(pid, SIGTERM);
if (ret != 0) {
IMSA_HILOGE("Kill failed, ret: %{public}d", ret);
return false;
}
IMSA_HILOGI("Kill [%{public}d] success", pid);
return true;
}
sptr<OHOS::AppExecFwk::IBundleMgr> TddUtil::GetBundleMgr()
{
sptr<ISystemAbilityManager> systemAbilityManager =
SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (systemAbilityManager == nullptr) {
IMSA_HILOGE("systemAbilityManager is nullptr");
return nullptr;
}
sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
if (remoteObject == nullptr) {
IMSA_HILOGE("remoteObject is nullptr");
return nullptr;
}
return iface_cast<AppExecFwk::IBundleMgr>(remoteObject);
}
int TddUtil::GetUserIdByBundleName(const std::string &bundleName, const int currentUserId)
{
auto bundleMgr = TddUtil::GetBundleMgr();
if (bundleMgr == nullptr) {
IMSA_HILOGE("Get bundleMgr failed.");
return -1;
}
auto uid = bundleMgr->GetUidByBundleName(bundleName, currentUserId);
if (uid == -1) {
IMSA_HILOGE("failed to get information and the parameters may be wrong.");
return -1;
}
return uid / 200000;
}
void TddUtil::GrantNativePermission()
{
const char **perms = new const char *[PERMISSION_NUM];
perms[FIRST_PARAM_INDEX] = "ohos.permission.MANAGE_SECURE_SETTINGS";
perms[SECOND_PARAM_INDEX] = "ohos.permission.CONNECT_IME_ABILITY";
perms[THIRD_PARAM_INDEX] = "ohos.permission.MANAGE_SETTINGS";
perms[FOURTH_PARAM_INDEX] = "ohos.permission.INJECT_INPUT_EVENT";
perms[FIFTH_PARAM_INDEX] = "ohos.permission.GET_BUNDLE_INFO_PRIVILEGED";
perms[SIXTH_PARAM_INDEX] = "ohos.permission.GET_RUNNING_INFO";
perms[SEVENTH_PARAM_INDEX] = "ohos.permission.MANAGE_LOCAL_ACCOUNTS";
TokenInfoParams infoInstance = {
.dcapsNum = 0,
.permsNum = PERMISSION_NUM,
.aclsNum = 0,
.dcaps = nullptr,
.perms = perms,
.acls = nullptr,
.processName = "imf_test",
.aplStr = "system_core",
};
uint64_t tokenId = GetAccessTokenId(&infoInstance);
int res = SetSelfTokenID(tokenId);
if (res == 0) {
IMSA_HILOGI("SetSelfTokenID success!");
} else {
IMSA_HILOGE("SetSelfTokenID fail!");
}
AccessTokenKit::ReloadNativeTokenInfo();
delete[] perms;
}
void TddUtil::PushEnableImeValue(const std::string &key, const std::string &value)
{
IMSA_HILOGI("key: %{public}s, value: %{public}s", key.c_str(), value.c_str());
auto helper = SettingsDataUtils::GetInstance().CreateDataShareHelper(SETTING_URI_PROXY);
if (helper == nullptr) {
IMSA_HILOGE("helper is nullptr.");
return;
}
DataShare::DataShareValueObject keyObj(key);
DataShare::DataShareValueObject valueObj(value);
DataShare::DataShareValuesBucket bucket;
bucket.Put(SETTING_COLUMN_KEYWORD, keyObj);
bucket.Put(SETTING_COLUMN_VALUE, valueObj);
DataShare::DataSharePredicates predicates;
predicates.EqualTo(SETTING_COLUMN_KEYWORD, key);
Uri uri(SettingsDataUtils::GetInstance().GenerateTargetUri(SETTING_URI_PROXY, key));
if (helper->Update(uri, predicates, bucket) <= 0) {
int index = helper->Insert(uri, bucket);
IMSA_HILOGI("no data exists, insert ret index: %{public}d", index);
} else {
IMSA_HILOGI("data exits");
}
bool ret = SettingsDataUtils::GetInstance().ReleaseDataShareHelper(helper);
IMSA_HILOGI("ReleaseDataShareHelper isSuccess: %{public}d", ret);
}
void TddUtil::DeleteGlobalTable(const std::string &key)
{
IMSA_HILOGI("key: %{public}s", key.c_str());
std::string uriProxy = SETTING_URI_PROXY;
DeleteTable(key, uriProxy);
}
void TddUtil::DeleteUserTable(int32_t userId, const std::string &key)
{
IMSA_HILOGI("userId:%{public}d, key:%{public}s", userId, key.c_str());
std::string uriProxy = SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true";
DeleteTable(key, uriProxy);
}
void TddUtil::DeleteTable(const std::string &key, const std::string &uriProxy)
{
auto helper = SettingsDataUtils::GetInstance().CreateDataShareHelper(uriProxy);
if (helper == nullptr) {
IMSA_HILOGE("helper is nullptr.");
return;
}
DataShare::DataSharePredicates predicates;
predicates.EqualTo(SETTING_COLUMN_KEYWORD, key);
Uri uri(SettingsDataUtils::GetInstance().GenerateTargetUri(uriProxy, key));
auto result = helper->DeleteEx(uri, predicates);
IMSA_HILOGI("Delete ret: [%{public}d, %{public}d]", result.first, result.second);
bool ret = SettingsDataUtils::GetInstance().ReleaseDataShareHelper(helper);
IMSA_HILOGI("ReleaseDataShareHelper isSuccess: %{public}d", ret);
}
void TddUtil::SetGlobalTable(const std::string &key, const std::string &content)
{
std::string uriProxy = SETTING_URI_PROXY;
SetTable(key, uriProxy, content);
}
void TddUtil::SetUserTable(int32_t userId, const std::string &key, const std::string &content)
{
std::string uriProxy = SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true";
SetTable(key, uriProxy, content);
}
void TddUtil::SetTable(const std::string &key, const std::string &uriProxy, const std::string &content)
{
SettingsDataUtils::GetInstance().SetStringValue(uriProxy, key, content);
}
std::string TddUtil::GetTable(const std::string &key, const std::string &uriProxy)
{
std::string content;
auto ret = SettingsDataUtils::GetInstance().GetStringValue(uriProxy, key, content);
IMSA_HILOGI("%{public}s/%{public}s ret:%{public}d.", key.c_str(), uriProxy.c_str(), ret);
return content;
}
std::string TddUtil::GetGlobalTable(const std::string &key)
{
std::string uriProxy = SETTING_URI_PROXY;
return GetTable(key, uriProxy);
}
std::string TddUtil::GetUserTable(int32_t userId, const std::string &key)
{
std::string uriProxy = SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true";
return GetTable(key, uriProxy);
}
int32_t TddUtil::GetEnableData(std::string &value)
{
auto ret = SettingsDataUtils::GetInstance().GetStringValue(SETTING_URI_PROXY, ENABLE_IME, value);
if (ret == ErrorCode::NO_ERROR) {
IMSA_HILOGI("success, value: %{public}s", value.c_str());
}
IMSA_HILOGI("GetStringValue ret: %{public}d", ret);
return ret;
}
void TddUtil::InitWindow(bool isShow)
{
WindowManager::RegisterFocusChangeListener();
WindowManager::CreateWindow();
if (!isShow) {
return;
}
WindowManager::ShowWindow();
bool isFocused = FocusChangedListenerTestImpl::isFocused_->GetValue();
IMSA_HILOGI("getFocus end, isFocused = %{public}d", isFocused);
}
void TddUtil::DestroyWindow()
{
WindowManager::HideWindow();
WindowManager::DestroyWindow();
}
bool TddUtil::GetFocused()
{
WindowManager::ShowWindow();
bool isFocused = FocusChangedListenerTestImpl::isFocused_->GetValue();
IMSA_HILOGI("getFocus end, isFocused = %{public}d", isFocused);
return isFocused;
}
bool TddUtil::GetUnfocused()
{
WindowManager::HideWindow();
bool unFocused = FocusChangedListenerTestImpl::unFocused_->GetValue();
IMSA_HILOGI("unFocused end, unFocused = %{public}d", unFocused);
return unFocused;
}
void TddUtil::InitCurrentImePermissionInfo()
{
auto userId = GetCurrentUserId();
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
UserSessionManager::GetInstance().AddUserSession(userId);
}
session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("session is nullptr.");
return;
}
std::shared_ptr<Property> property = nullptr;
InputMethodController::GetInstance()->GetDefaultInputMethod(property);
if (property == nullptr) {
IMSA_HILOGI("default ime is nullptr.");
return;
}
currentBundleNameMock_ = property->name;
sptr<AAFwk::IAbilityConnection> connection = nullptr;
bool isFirstStart = false;
session->InitRealImeData(connection, isFirstStart, { property->name, property->id });
}
void TddUtil::EnabledAllIme()
{
auto imc = InputMethodController::GetInstance();
if (imc == nullptr) {
return;
}
std::vector<Property> props;
imc->ListInputMethod(false, props);
for (const auto &prop : props) {
imc->EnableIme(prop.name, prop.id, EnabledStatus::BASIC_MODE);
}
}
void TddUtil::DisabledAllIme()
{
auto imc = InputMethodController::GetInstance();
if (imc == nullptr) {
return;
}
std::vector<Property> props;
imc->ListInputMethod(true, props);
for (const auto &prop : props) {
imc->EnableIme(prop.name, prop.id, EnabledStatus::DISABLED);
}
}
void TddUtil::StartApp(const std::string &bundleName)
{
std::string cmd = std::string("aa start ability -a EntryAbility -b") + " " + bundleName;
std::string result;
auto ret = ExecuteCmd(cmd, result);
IMSA_HILOGI("ExecuteCmd ret = %{public}d", ret);
sleep(WAIT_APP_START_COMPLETE);
}
void TddUtil::StopApp(const std::string &bundleName)
{
static std::string cmd = std::string("aa force-stop") + " " + bundleName;
std::string result;
auto ret = ExecuteCmd(cmd, result);
IMSA_HILOGI("ExecuteCmd ret = %{public}d", ret);
}
void TddUtil::ClickApp()
{
auto displayInfo = Rosen::DisplayManagerLite::GetInstance().GetDefaultDisplay();
if (displayInfo == nullptr) {
return;
}
int32_t Height = displayInfo->GetHeight() / 2;
int32_t Width = displayInfo->GetWidth() / 2;
std::string cmd = "uinput";
cmd.append(" ")
.append("-T")
.append(" ")
.append("-d")
.append(" ")
.append(std::to_string(Width))
.append(" ")
.append(std::to_string(Height))
.append(" ")
.append("-u")
.append(" ")
.append(std::to_string(Width))
.append(" ")
.append(std::to_string(Height));
std::string result;
auto ret = TddUtil::ExecuteCmd(cmd, result);
IMSA_HILOGI("ExecuteCmd ret = %{public}d", ret);
usleep(WAIT_CLICK_COMPLETE);
}
bool TddUtil::WaitTaskEmpty()
{
return BlockRetry(WAIT_TASK_EMPTY_INTERVAL, WAIT_TASK_EMPTY_TIMES, []() {
return TaskManager::GetInstance().curTask_ == nullptr && TaskManager::GetInstance().amsTasks_.empty() &&
TaskManager::GetInstance().imaTasks_.empty() && TaskManager::GetInstance().imsaTasks_.empty() &&
TaskManager::GetInstance().innerTasks_.empty();
});
}
void TddUtil::WindowManager::CreateWindow()
{
if (windowTokenId_ == 0) {
windowTokenId_ = AllocTestTokenID(true, "TestWindow", { "ohos.permission.SYSTEM_FLOAT_WINDOW" });
}
TokenScope scope(windowTokenId_);
std::string windowName = "inputmethod_test_window";
sptr<WindowOption> winOption = new OHOS::Rosen::WindowOption();
winOption->SetWindowType(WindowType::WINDOW_TYPE_FLOAT);
winOption->SetFocusable(true);
std::shared_ptr<AbilityRuntime::Context> context = nullptr;
WMError wmError = WMError::WM_OK;
window_ = Window::Create(windowName, winOption, context, wmError);
if (window_ == nullptr) {
IMSA_HILOGE("failed to create window, ret: %{public}d", wmError);
return;
}
IMSA_HILOGI("Create window ret:%{public}d", wmError);
currentWindowId_ = window_->GetWindowId();
}
void TddUtil::WindowManager::ShowWindow()
{
if (window_ == nullptr) {
IMSA_HILOGE("window is not exist.");
return;
}
TokenScope scope(windowTokenId_);
auto ret = window_->Show();
IMSA_HILOGI("Show window end, ret = %{public}d", ret);
}
void TddUtil::WindowManager::HideWindow()
{
if (window_ == nullptr) {
IMSA_HILOGE("window is not exist.");
return;
}
TokenScope scope(windowTokenId_);
auto ret = window_->Hide();
IMSA_HILOGI("Hide window end, ret = %{public}d", ret);
}
void TddUtil::WindowManager::DestroyWindow()
{
if (window_ == nullptr) {
IMSA_HILOGE("window_ nullptr");
return;
}
TokenScope scope(windowTokenId_);
auto wmError = window_->Destroy();
IMSA_HILOGI("Destroy window ret: %{public}d", wmError);
}
void TddUtil::WindowManager::RegisterFocusChangeListener()
{
auto listener = new (std::nothrow) FocusChangedListenerTestImpl();
WMError ret = Rosen::WindowManager::GetInstance().RegisterFocusChangedListener(listener);
IMSA_HILOGI("register focus changed listener ret: %{public}d", ret);
}
}
}