You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
3.9 KiB
137 lines
3.9 KiB
/*
|
|
* Copyright (C) 2023 The Android Open Source Project
|
|
*
|
|
* 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 "./test-app.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
#include "./string-utils.h"
|
|
|
|
namespace shell_as {
|
|
|
|
// Returns a pointer to bytes of the test app APK along with the length in bytes
|
|
// of the APK.
|
|
//
|
|
// This function is defined by the shell-as-test-app-apk-cpp genrule.
|
|
void GetTestApk(uint8_t **apk, size_t *length);
|
|
|
|
namespace {
|
|
|
|
// The staging path for the test app APK.
|
|
const char kTestAppApkStagingPath[] = "/data/local/tmp/shell-as-test-app.apk";
|
|
|
|
// Writes the test app to a staging location and then installs the APK via the
|
|
// 'pm' utility. The app is granted runtime permissions on installation. Returns
|
|
// true if the app is installed successfully.
|
|
bool InstallTestApp() {
|
|
uint8_t *apk = nullptr;
|
|
size_t apk_size = 0;
|
|
GetTestApk(&apk, &apk_size);
|
|
|
|
int staging_file = open(kTestAppApkStagingPath, O_WRONLY | O_CREAT | O_TRUNC,
|
|
S_IRUSR | S_IWUSR);
|
|
if (staging_file == -1) {
|
|
std::cerr << "Unable to open staging APK path." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
size_t bytes_written = write(staging_file, apk, apk_size);
|
|
close(staging_file);
|
|
if (bytes_written != apk_size) {
|
|
std::cerr << "Unable to write entire test app APK." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
const char cmd_template[] = "pm install -g %s > /dev/null 2> /dev/null";
|
|
char system_cmd[sizeof(cmd_template) + sizeof(kTestAppApkStagingPath) + 1] =
|
|
{};
|
|
sprintf(system_cmd, cmd_template, kTestAppApkStagingPath);
|
|
return system(system_cmd) == 0;
|
|
}
|
|
|
|
// Uninstalls the test app if it is installed. This method is a no-op if the app
|
|
// is not installed.
|
|
void UninstallTestApp() {
|
|
system(
|
|
"pm uninstall com.android.google.tools.security.shell_as"
|
|
" > /dev/null 2> /dev/null");
|
|
}
|
|
|
|
// Starts the main activity of the test app. This is necessary as some aspects
|
|
// of the security context can only be inferred from a running process.
|
|
bool StartTestApp() {
|
|
return system(
|
|
"am start-activity "
|
|
"com.android.google.tools.security.shell_as/"
|
|
".MainActivity"
|
|
" > /dev/null 2> /dev/null") == 0;
|
|
}
|
|
|
|
// Obtain the process ID of the test app and returns true if it is running.
|
|
// Returns false otherwise.
|
|
bool GetTestAppProcessId(pid_t *test_app_pid) {
|
|
FILE *pgrep = popen(
|
|
"pgrep -f "
|
|
"com.android.google.tools.security.shell_as",
|
|
"r");
|
|
if (!pgrep) {
|
|
std::cerr << "Unable to execute pgrep." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
char pgrep_output[128];
|
|
memset(pgrep_output, 0, sizeof(pgrep_output));
|
|
int bytes_read = fread(pgrep_output, 1, sizeof(pgrep_output) - 1, pgrep);
|
|
pclose(pgrep);
|
|
if (bytes_read <= 0) {
|
|
// Unable to find the process. This may happen if the app is still starting
|
|
// up.
|
|
return false;
|
|
}
|
|
return StringToUInt32(pgrep_output, (uint32_t *)test_app_pid);
|
|
}
|
|
} // namespace
|
|
|
|
bool SetupAndStartTestApp(pid_t *test_app_pid) {
|
|
UninstallTestApp();
|
|
|
|
if (!InstallTestApp()) {
|
|
std::cerr << "Unable to install test app." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
if (!StartTestApp()) {
|
|
std::cerr << "Unable to start and obtain test app PID." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
if (GetTestAppProcessId(test_app_pid)) {
|
|
return true;
|
|
}
|
|
sleep(1);
|
|
}
|
|
return false;
|
|
}
|
|
} // namespace shell_as
|