1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "service.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <jni.h>
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include <filesystem>
22*795d594fSAndroid Build Coastguard Worker #include <string_view>
23*795d594fSAndroid Build Coastguard Worker
24*795d594fSAndroid Build Coastguard Worker #include "android-base/errors.h"
25*795d594fSAndroid Build Coastguard Worker #include "android-base/file.h"
26*795d594fSAndroid Build Coastguard Worker #include "android-base/properties.h"
27*795d594fSAndroid Build Coastguard Worker #include "android-base/result.h"
28*795d594fSAndroid Build Coastguard Worker #include "class_loader_context.h"
29*795d594fSAndroid Build Coastguard Worker #include "gc/heap.h"
30*795d594fSAndroid Build Coastguard Worker #include "nativehelper/JNIHelp.h"
31*795d594fSAndroid Build Coastguard Worker #include "nativehelper/utils.h"
32*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
33*795d594fSAndroid Build Coastguard Worker #include "tools/tools.h"
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Worker namespace art {
36*795d594fSAndroid Build Coastguard Worker namespace service {
37*795d594fSAndroid Build Coastguard Worker
38*795d594fSAndroid Build Coastguard Worker using ::android::base::Dirname;
39*795d594fSAndroid Build Coastguard Worker using ::android::base::Result;
40*795d594fSAndroid Build Coastguard Worker using ::android::base::SetProperty;
41*795d594fSAndroid Build Coastguard Worker
ValidateAbsoluteNormalPath(const std::string & path_str)42*795d594fSAndroid Build Coastguard Worker Result<void> ValidateAbsoluteNormalPath(const std::string& path_str) {
43*795d594fSAndroid Build Coastguard Worker if (path_str.empty()) {
44*795d594fSAndroid Build Coastguard Worker return Errorf("Path is empty");
45*795d594fSAndroid Build Coastguard Worker }
46*795d594fSAndroid Build Coastguard Worker if (path_str.find('\0') != std::string::npos) {
47*795d594fSAndroid Build Coastguard Worker return Errorf("Path '{}' has invalid character '\\0'", path_str);
48*795d594fSAndroid Build Coastguard Worker }
49*795d594fSAndroid Build Coastguard Worker std::filesystem::path path(path_str);
50*795d594fSAndroid Build Coastguard Worker if (!path.is_absolute()) {
51*795d594fSAndroid Build Coastguard Worker return Errorf("Path '{}' is not an absolute path", path_str);
52*795d594fSAndroid Build Coastguard Worker }
53*795d594fSAndroid Build Coastguard Worker if (path.lexically_normal() != path_str) {
54*795d594fSAndroid Build Coastguard Worker return Errorf("Path '{}' is not in normal form", path_str);
55*795d594fSAndroid Build Coastguard Worker }
56*795d594fSAndroid Build Coastguard Worker return {};
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker
ValidatePathElementSubstring(const std::string & path_element_substring,const std::string & name)59*795d594fSAndroid Build Coastguard Worker Result<void> ValidatePathElementSubstring(const std::string& path_element_substring,
60*795d594fSAndroid Build Coastguard Worker const std::string& name) {
61*795d594fSAndroid Build Coastguard Worker if (path_element_substring.empty()) {
62*795d594fSAndroid Build Coastguard Worker return Errorf("{} is empty", name);
63*795d594fSAndroid Build Coastguard Worker }
64*795d594fSAndroid Build Coastguard Worker if (path_element_substring.find('/') != std::string::npos) {
65*795d594fSAndroid Build Coastguard Worker return Errorf("{} '{}' has invalid character '/'", name, path_element_substring);
66*795d594fSAndroid Build Coastguard Worker }
67*795d594fSAndroid Build Coastguard Worker if (path_element_substring.find('\0') != std::string::npos) {
68*795d594fSAndroid Build Coastguard Worker return Errorf("{} '{}' has invalid character '\\0'", name, path_element_substring);
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker return {};
71*795d594fSAndroid Build Coastguard Worker }
72*795d594fSAndroid Build Coastguard Worker
ValidatePathElement(const std::string & path_element,const std::string & name)73*795d594fSAndroid Build Coastguard Worker Result<void> ValidatePathElement(const std::string& path_element, const std::string& name) {
74*795d594fSAndroid Build Coastguard Worker OR_RETURN(ValidatePathElementSubstring(path_element, name));
75*795d594fSAndroid Build Coastguard Worker if (path_element == "." || path_element == "..") {
76*795d594fSAndroid Build Coastguard Worker return Errorf("Invalid {} '{}'", name, path_element);
77*795d594fSAndroid Build Coastguard Worker }
78*795d594fSAndroid Build Coastguard Worker return {};
79*795d594fSAndroid Build Coastguard Worker }
80*795d594fSAndroid Build Coastguard Worker
ValidateDexPath(const std::string & dex_path)81*795d594fSAndroid Build Coastguard Worker Result<void> ValidateDexPath(const std::string& dex_path) {
82*795d594fSAndroid Build Coastguard Worker OR_RETURN(ValidateAbsoluteNormalPath(dex_path));
83*795d594fSAndroid Build Coastguard Worker return {};
84*795d594fSAndroid Build Coastguard Worker }
85*795d594fSAndroid Build Coastguard Worker
ValidateClassLoaderContext(std::string_view dex_path,const std::string & class_loader_context)86*795d594fSAndroid Build Coastguard Worker android::base::Result<void> ValidateClassLoaderContext(std::string_view dex_path,
87*795d594fSAndroid Build Coastguard Worker const std::string& class_loader_context) {
88*795d594fSAndroid Build Coastguard Worker if (class_loader_context == ClassLoaderContext::kUnsupportedClassLoaderContextEncoding) {
89*795d594fSAndroid Build Coastguard Worker return {};
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker
92*795d594fSAndroid Build Coastguard Worker std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(class_loader_context);
93*795d594fSAndroid Build Coastguard Worker if (context == nullptr) {
94*795d594fSAndroid Build Coastguard Worker return Errorf("Class loader context '{}' is invalid", class_loader_context);
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker
97*795d594fSAndroid Build Coastguard Worker std::vector<std::string> flattened_context = context->FlattenDexPaths();
98*795d594fSAndroid Build Coastguard Worker std::string dex_dir = Dirname(dex_path);
99*795d594fSAndroid Build Coastguard Worker for (const std::string& context_element : flattened_context) {
100*795d594fSAndroid Build Coastguard Worker std::string context_path = std::filesystem::path(dex_dir).append(context_element);
101*795d594fSAndroid Build Coastguard Worker OR_RETURN(ValidateDexPath(context_path));
102*795d594fSAndroid Build Coastguard Worker }
103*795d594fSAndroid Build Coastguard Worker
104*795d594fSAndroid Build Coastguard Worker return {};
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker
GetGarbageCollector()107*795d594fSAndroid Build Coastguard Worker std::string GetGarbageCollector() {
108*795d594fSAndroid Build Coastguard Worker return Runtime::Current()->GetHeap()->GetForegroundCollectorName();
109*795d594fSAndroid Build Coastguard Worker }
110*795d594fSAndroid Build Coastguard Worker
111*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jstring JNICALL
Java_com_android_server_art_ArtJni_validateDexPathNative(JNIEnv * env,jobject,jstring j_dex_path)112*795d594fSAndroid Build Coastguard Worker Java_com_android_server_art_ArtJni_validateDexPathNative(JNIEnv* env, jobject, jstring j_dex_path) {
113*795d594fSAndroid Build Coastguard Worker std::string dex_path(GET_UTF_OR_RETURN(env, j_dex_path));
114*795d594fSAndroid Build Coastguard Worker
115*795d594fSAndroid Build Coastguard Worker if (Result<void> result = ValidateDexPath(dex_path); !result.ok()) {
116*795d594fSAndroid Build Coastguard Worker return CREATE_UTF_OR_RETURN(env, result.error().message()).release();
117*795d594fSAndroid Build Coastguard Worker } else {
118*795d594fSAndroid Build Coastguard Worker return nullptr;
119*795d594fSAndroid Build Coastguard Worker }
120*795d594fSAndroid Build Coastguard Worker }
121*795d594fSAndroid Build Coastguard Worker
122*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jstring JNICALL
Java_com_android_server_art_ArtJni_validateClassLoaderContextNative(JNIEnv * env,jobject,jstring j_dex_path,jstring j_class_loader_context)123*795d594fSAndroid Build Coastguard Worker Java_com_android_server_art_ArtJni_validateClassLoaderContextNative(
124*795d594fSAndroid Build Coastguard Worker JNIEnv* env, jobject, jstring j_dex_path, jstring j_class_loader_context) {
125*795d594fSAndroid Build Coastguard Worker ScopedUtfChars dex_path = GET_UTF_OR_RETURN(env, j_dex_path);
126*795d594fSAndroid Build Coastguard Worker std::string class_loader_context(GET_UTF_OR_RETURN(env, j_class_loader_context));
127*795d594fSAndroid Build Coastguard Worker
128*795d594fSAndroid Build Coastguard Worker if (Result<void> result = ValidateClassLoaderContext(dex_path, class_loader_context);
129*795d594fSAndroid Build Coastguard Worker !result.ok()) {
130*795d594fSAndroid Build Coastguard Worker return CREATE_UTF_OR_RETURN(env, result.error().message()).release();
131*795d594fSAndroid Build Coastguard Worker } else {
132*795d594fSAndroid Build Coastguard Worker return nullptr;
133*795d594fSAndroid Build Coastguard Worker }
134*795d594fSAndroid Build Coastguard Worker }
135*795d594fSAndroid Build Coastguard Worker
136*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jstring JNICALL
Java_com_android_server_art_ArtJni_getGarbageCollectorNative(JNIEnv * env,jobject)137*795d594fSAndroid Build Coastguard Worker Java_com_android_server_art_ArtJni_getGarbageCollectorNative(JNIEnv* env, jobject) {
138*795d594fSAndroid Build Coastguard Worker return CREATE_UTF_OR_RETURN(env, GetGarbageCollector()).release();
139*795d594fSAndroid Build Coastguard Worker }
140*795d594fSAndroid Build Coastguard Worker
Java_com_android_server_art_ArtJni_setPropertyNative(JNIEnv * env,jobject,jstring j_key,jstring j_value)141*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_com_android_server_art_ArtJni_setPropertyNative(
142*795d594fSAndroid Build Coastguard Worker JNIEnv* env, jobject, jstring j_key, jstring j_value) {
143*795d594fSAndroid Build Coastguard Worker std::string key(GET_UTF_OR_RETURN_VOID(env, j_key));
144*795d594fSAndroid Build Coastguard Worker std::string value(GET_UTF_OR_RETURN_VOID(env, j_value));
145*795d594fSAndroid Build Coastguard Worker if (!SetProperty(key, value)) {
146*795d594fSAndroid Build Coastguard Worker jniThrowExceptionFmt(env,
147*795d594fSAndroid Build Coastguard Worker "java/lang/IllegalStateException",
148*795d594fSAndroid Build Coastguard Worker "Failed to set property '%s' to '%s'",
149*795d594fSAndroid Build Coastguard Worker key.c_str(),
150*795d594fSAndroid Build Coastguard Worker value.c_str());
151*795d594fSAndroid Build Coastguard Worker }
152*795d594fSAndroid Build Coastguard Worker }
153*795d594fSAndroid Build Coastguard Worker
Java_com_android_server_art_ArtJni_ensureNoProcessInDirNative(JNIEnv * env,jobject,jstring j_dir,jint j_timeout_ms)154*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_com_android_server_art_ArtJni_ensureNoProcessInDirNative(
155*795d594fSAndroid Build Coastguard Worker JNIEnv* env, jobject, jstring j_dir, jint j_timeout_ms) {
156*795d594fSAndroid Build Coastguard Worker if (j_timeout_ms < 0) {
157*795d594fSAndroid Build Coastguard Worker jniThrowExceptionFmt(
158*795d594fSAndroid Build Coastguard Worker env, "java/lang/IllegalArgumentException", "Negative timeout '%d'", j_timeout_ms);
159*795d594fSAndroid Build Coastguard Worker return;
160*795d594fSAndroid Build Coastguard Worker }
161*795d594fSAndroid Build Coastguard Worker std::string dir(GET_UTF_OR_RETURN_VOID(env, j_dir));
162*795d594fSAndroid Build Coastguard Worker if (Result<void> result = tools::EnsureNoProcessInDir(dir, j_timeout_ms, /*try_kill=*/true);
163*795d594fSAndroid Build Coastguard Worker !result.ok()) {
164*795d594fSAndroid Build Coastguard Worker jniThrowException(env, "java/io/IOException", result.error().message().c_str());
165*795d594fSAndroid Build Coastguard Worker }
166*795d594fSAndroid Build Coastguard Worker }
167*795d594fSAndroid Build Coastguard Worker
168*795d594fSAndroid Build Coastguard Worker } // namespace service
169*795d594fSAndroid Build Coastguard Worker } // namespace art
170