android 13 from xiaosuan
This commit is contained in:
commit
b23f8b6eeb
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2013 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#ifndef LOG_NDEBUG
|
||||
#ifdef NDEBUG
|
||||
#define LOG_NDEBUG 1
|
||||
#else
|
||||
#define LOG_NDEBUG 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Basic log message macros intended to emulate the behavior of log/log.h
|
||||
* in system core. This should be dependent only on ndk exposed logging
|
||||
* functionality.
|
||||
*/
|
||||
|
||||
#ifndef ALOG
|
||||
#define ALOG(priority, tag, fmt, ...) \
|
||||
__android_log_print(ANDROID_##priority, tag, fmt, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef ALOGV
|
||||
#if LOG_NDEBUG
|
||||
#define ALOGV(...) ((void)0)
|
||||
#else
|
||||
#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ALOGD
|
||||
#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#ifndef ALOGI
|
||||
#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#ifndef ALOGW
|
||||
#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#ifndef ALOGE
|
||||
#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#ifndef ALOGF
|
||||
#define ALOGF(...) ((void)ALOG(LOG_FATAL, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Log a fatal error if cond is true. The condition test is inverted from
|
||||
* assert(3) semantics. The test and message are not stripped from release
|
||||
* builds
|
||||
*/
|
||||
#ifndef ALOG_ALWAYS_FATAL_IF
|
||||
#define ALOG_ALWAYS_FATAL_IF(cond, ...) \
|
||||
if (cond) __android_log_assert(#cond, LOG_TAG, __VA_ARGS__)
|
||||
#endif
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
// Copyright (C) 2009 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.
|
||||
|
||||
package {
|
||||
default_applicable_licenses: ["libnativehelper_license"],
|
||||
}
|
||||
|
||||
// Added automatically by a large-scale-change
|
||||
// http://go/android-license-faq
|
||||
license {
|
||||
name: "libnativehelper_license",
|
||||
visibility: [":__subpackages__"],
|
||||
license_kinds: [
|
||||
"SPDX-license-identifier-Apache-2.0",
|
||||
],
|
||||
license_text: [
|
||||
"NOTICE",
|
||||
],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "libnativehelper_defaults",
|
||||
cflags: [
|
||||
"-fvisibility=protected",
|
||||
"-std=c11",
|
||||
],
|
||||
shared_libs: ["liblog"],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "jni_headers",
|
||||
host_supported: true,
|
||||
export_include_dirs: ["include_jni"],
|
||||
native_bridge_supported: true,
|
||||
vendor_available: true,
|
||||
target: {
|
||||
windows: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"//apex_available:anyapex",
|
||||
],
|
||||
ramdisk_available: true,
|
||||
// recovery_available currently required for libchrome (https://r.android.com/799940).
|
||||
recovery_available: true,
|
||||
visibility: ["//visibility:public"],
|
||||
stl: "none",
|
||||
system_shared_libs: [],
|
||||
// The minimum sdk version required by users of this module.
|
||||
sdk_version: "minimum",
|
||||
// As part of mainline modules(APEX), it should support at least 29(Q)
|
||||
min_sdk_version: "29",
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "libnativehelper_header_only",
|
||||
host_supported: true,
|
||||
export_include_dirs: [
|
||||
"header_only_include",
|
||||
],
|
||||
header_libs: ["jni_headers"],
|
||||
export_header_lib_headers: ["jni_headers"],
|
||||
// As part of mainline modules(APEX), it should support at least 29(Q)
|
||||
min_sdk_version: "29",
|
||||
sdk_version: "minimum",
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"//apex_available:anyapex",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "jni_platform_headers",
|
||||
host_supported: true,
|
||||
export_include_dirs: [
|
||||
"include_platform_header_only",
|
||||
],
|
||||
header_libs: ["jni_headers"],
|
||||
export_header_lib_headers: ["jni_headers"],
|
||||
sdk_version: "minimum",
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"com.android.art",
|
||||
"com.android.art.debug",
|
||||
],
|
||||
min_sdk_version: "S",
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libnativehelper",
|
||||
defaults: ["libnativehelper_defaults"],
|
||||
bootstrap: false,
|
||||
host_supported: true,
|
||||
srcs: [
|
||||
"DlHelp.c",
|
||||
"ExpandableString.c",
|
||||
"JNIHelp.c",
|
||||
"JNIPlatformHelp.c",
|
||||
"JniConstants.c",
|
||||
"JniInvocation.c",
|
||||
"file_descriptor_jni.c",
|
||||
],
|
||||
export_include_dirs: [
|
||||
"header_only_include",
|
||||
"include",
|
||||
"include_jni",
|
||||
"include_platform",
|
||||
"include_platform_header_only",
|
||||
],
|
||||
stl: "none",
|
||||
stubs: {
|
||||
symbol_file: "libnativehelper.map.txt",
|
||||
versions: ["S"],
|
||||
},
|
||||
// Only distributed in the ART Module.
|
||||
apex_available: [
|
||||
"com.android.art",
|
||||
"com.android.art.debug",
|
||||
],
|
||||
min_sdk_version: "S",
|
||||
}
|
||||
|
||||
// Lazy loading version of libnativehelper that can be used by code
|
||||
// that is running before the ART APEX is mounted and
|
||||
// libnativehelper.so is available.
|
||||
cc_library_static {
|
||||
name: "libnativehelper_lazy",
|
||||
defaults: ["libnativehelper_defaults"],
|
||||
bootstrap: true,
|
||||
host_supported: true,
|
||||
export_include_dirs: [
|
||||
"header_only_include",
|
||||
"include",
|
||||
"include_jni",
|
||||
"include_platform",
|
||||
"include_platform_header_only",
|
||||
],
|
||||
apex_available: ["//apex_available:platform"],
|
||||
srcs: ["libnativehelper_lazy.c"],
|
||||
target: {
|
||||
linux: {
|
||||
version_script: "libnativehelper.map.txt",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
//
|
||||
// NDK-only build for the target (device), using libc++.
|
||||
// - Relies only on NDK exposed functionality.
|
||||
// - This doesn't include JniInvocation.
|
||||
//
|
||||
|
||||
cc_library {
|
||||
name: "libnativehelper_compat_libc++",
|
||||
defaults: ["libnativehelper_defaults"],
|
||||
header_libs: ["jni_headers"],
|
||||
cflags: ["-Werror"],
|
||||
export_header_lib_headers: ["jni_headers"],
|
||||
export_include_dirs: [
|
||||
"header_only_include",
|
||||
"include",
|
||||
],
|
||||
host_supported: true,
|
||||
local_include_dirs: [
|
||||
"header_only_include",
|
||||
"include_platform_header_only",
|
||||
],
|
||||
srcs: [
|
||||
"ExpandableString.c",
|
||||
"JNIHelp.c",
|
||||
],
|
||||
min_sdk_version: "29",
|
||||
sdk_version: "19",
|
||||
stl: "none",
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"com.android.art",
|
||||
"com.android.art.debug",
|
||||
"com.android.extservices",
|
||||
"com.android.tethering",
|
||||
],
|
||||
visibility: [
|
||||
"//art:__subpackages__",
|
||||
"//cts:__subpackages__",
|
||||
"//external/perfetto:__subpackages__",
|
||||
"//frameworks/base/packages/Connectivity/tests/integration:__pkg__",
|
||||
"//frameworks/base/packages/ConnectivityT:__subpackages__", // TODO: remove after code move
|
||||
"//frameworks/base/packages/Tethering:__subpackages__",
|
||||
"//frameworks/libs/net/common/native/bpfmapjni",
|
||||
"//frameworks/libs/net/common/native/bpfutiljni",
|
||||
"//libcore:__subpackages__",
|
||||
"//packages/modules/Connectivity:__subpackages__",
|
||||
"//packages/modules/ExtServices:__subpackages__",
|
||||
"//packages/modules/NetworkStack:__subpackages__",
|
||||
":__subpackages__",
|
||||
],
|
||||
}
|
||||
|
||||
// The NDK module definitions reside in
|
||||
// system/extras/module_ndk_libs/libnativehelper in platform, with copies of
|
||||
// these headers and map.txt. Any changes here should be synced there and vice
|
||||
// versa.
|
||||
//
|
||||
// TODO(b/170644498): Improve tooling to remove this duplication.
|
||||
//
|
||||
// ndk_headers {
|
||||
// name: "ndk_jni.h",
|
||||
// from: "include_jni",
|
||||
// to: "",
|
||||
// srcs: ["include_jni/jni.h"],
|
||||
// license: "NOTICE",
|
||||
// }
|
||||
//
|
||||
// ndk_headers {
|
||||
// name: "libnativehelper_ndk_headers",
|
||||
// from: "include",
|
||||
// to: "",
|
||||
// srcs: ["include/android/*.h"],
|
||||
// license: "NOTICE",
|
||||
// }
|
||||
//
|
||||
// ndk_library {
|
||||
// name: "libnativehelper",
|
||||
// symbol_file: "libnativehelper.map.txt",
|
||||
// first_version: "S",
|
||||
// }
|
||||
|
||||
//
|
||||
// Tests.
|
||||
//
|
||||
|
||||
subdirs = [
|
||||
"tests",
|
||||
"tests_mts",
|
||||
]
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 "DlHelp.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef WIN32_LEAN_AND_MEAN
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
DlLibrary DlOpenLibrary(const char* filename) {
|
||||
#ifdef _WIN32
|
||||
return LoadLibrary(filename);
|
||||
#else
|
||||
// Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed.
|
||||
// This is due to the fact that it is possible that some threads might have yet to finish
|
||||
// exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is
|
||||
// unloaded.
|
||||
return dlopen(filename, RTLD_NOW | RTLD_NODELETE);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DlCloseLibrary(DlLibrary library) {
|
||||
#ifdef _WIN32
|
||||
return (FreeLibrary(library) == TRUE);
|
||||
#else
|
||||
return (dlclose(library) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
DlSymbol DlGetSymbol(DlLibrary handle, const char* symbol) {
|
||||
#ifdef _WIN32
|
||||
return (DlSymbol) GetProcAddress(handle, symbol);
|
||||
#else
|
||||
return dlsym(handle, symbol);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* DlGetError() {
|
||||
#ifdef _WIN32
|
||||
static char buffer[256];
|
||||
|
||||
DWORD cause = GetLastError();
|
||||
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
DWORD length = FormatMessageA(flags, NULL, cause, 0, buffer, sizeof(buffer), NULL);
|
||||
if (length == 0) {
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"Error %lu while retrieving message for error %lu",
|
||||
GetLastError(), cause);
|
||||
length = strlen(buffer);
|
||||
}
|
||||
|
||||
// Trim trailing whitespace.
|
||||
for (DWORD i = length - 1; i > 0; --i) {
|
||||
if (!isspace(buffer[i])) {
|
||||
break;
|
||||
}
|
||||
buffer[i] = '\0';
|
||||
}
|
||||
|
||||
return buffer;
|
||||
#else
|
||||
return dlerror();
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
typedef void* DlLibrary;
|
||||
typedef void* DlSymbol;
|
||||
|
||||
DlLibrary DlOpenLibrary(const char* filename);
|
||||
bool DlCloseLibrary(DlLibrary library);
|
||||
DlSymbol DlGetSymbol(DlLibrary library, const char* symbol);
|
||||
const char* DlGetError();
|
||||
|
||||
__END_DECLS
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 "ExpandableString.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void ExpandableStringInitialize(struct ExpandableString *s) {
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
void ExpandableStringRelease(struct ExpandableString* s) {
|
||||
free(s->data);
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
bool ExpandableStringAppend(struct ExpandableString* s, const char* text) {
|
||||
size_t textSize = strlen(text);
|
||||
size_t requiredSize = s->dataSize + textSize + 1;
|
||||
char* data = (char*) realloc(s->data, requiredSize);
|
||||
if (data == NULL) {
|
||||
return false;
|
||||
}
|
||||
s->data = data;
|
||||
memcpy(s->data + s->dataSize, text, textSize + 1);
|
||||
s->dataSize += textSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpandableStringAssign(struct ExpandableString* s, const char* text) {
|
||||
ExpandableStringRelease(s);
|
||||
return ExpandableStringAppend(s, text);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct ExpandableString {
|
||||
size_t dataSize; // The length of the C string data (not including the null-terminator).
|
||||
char* data; // The C string data.
|
||||
};
|
||||
|
||||
// Initialize ExpandableString.
|
||||
void ExpandableStringInitialize(struct ExpandableString* s);
|
||||
|
||||
// Release memory associated with ExpandableString.
|
||||
void ExpandableStringRelease(struct ExpandableString* s);
|
||||
|
||||
// Append null-terminated string |text| to ExpandableString, expanding the storage if required.
|
||||
// Returns true on success, false othewise.
|
||||
bool ExpandableStringAppend(struct ExpandableString* s, const char* text);
|
||||
|
||||
// Assign null-terminate string |text| to ExpandableString, expanding the storage if required.
|
||||
// Returns true on success, false othewise.
|
||||
bool ExpandableStringAssign(struct ExpandableString*s, const char* text);
|
||||
|
||||
__END_DECLS
|
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* Copyright (C) 2006 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 "include/nativehelper/JNIHelp.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#define LOG_TAG "JNIHelp"
|
||||
#include "ALog-priv.h"
|
||||
|
||||
#include "ExpandableString.h"
|
||||
|
||||
//
|
||||
// Helper methods
|
||||
//
|
||||
|
||||
static const char* platformStrError(int errnum, char* buf, size_t buflen) {
|
||||
#ifdef _WIN32
|
||||
strerror_s(buf, buflen, errnum);
|
||||
return buf;
|
||||
#elif defined(__USE_GNU) && __ANDROID_API__ >= 23
|
||||
// char *strerror_r(int errnum, char *buf, size_t buflen); /* GNU-specific */
|
||||
return strerror_r(errnum, buf, buflen);
|
||||
#else
|
||||
// int strerror_r(int errnum, char *buf, size_t buflen); /* XSI-compliant */
|
||||
int rc = strerror_r(errnum, buf, buflen);
|
||||
if (rc != 0) {
|
||||
snprintf(buf, buflen, "errno %d", errnum);
|
||||
}
|
||||
return buf;
|
||||
#endif
|
||||
}
|
||||
|
||||
static jmethodID FindMethod(JNIEnv* env,
|
||||
const char* className,
|
||||
const char* methodName,
|
||||
const char* descriptor) {
|
||||
// This method is only valid for classes in the core library which are
|
||||
// not unloaded during the lifetime of managed code execution.
|
||||
jclass clazz = (*env)->FindClass(env, className);
|
||||
jmethodID methodId = (*env)->GetMethodID(env, clazz, methodName, descriptor);
|
||||
(*env)->DeleteLocalRef(env, clazz);
|
||||
return methodId;
|
||||
}
|
||||
|
||||
static bool AppendJString(JNIEnv* env, jstring text, struct ExpandableString* dst) {
|
||||
const char* utfText = (*env)->GetStringUTFChars(env, text, NULL);
|
||||
if (utfText == NULL) {
|
||||
return false;
|
||||
}
|
||||
bool success = ExpandableStringAppend(dst, utfText);
|
||||
(*env)->ReleaseStringUTFChars(env, text, utfText);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a human-readable summary of an exception object. The buffer will
|
||||
* be populated with the "binary" class name and, if present, the
|
||||
* exception message.
|
||||
*/
|
||||
static bool GetExceptionSummary(JNIEnv* env, jthrowable thrown, struct ExpandableString* dst) {
|
||||
// Summary is <exception_class_name> ": " <exception_message>
|
||||
jclass exceptionClass = (*env)->GetObjectClass(env, thrown); // Always succeeds
|
||||
jmethodID getName = FindMethod(env, "java/lang/Class", "getName", "()Ljava/lang/String;");
|
||||
jstring className = (jstring) (*env)->CallObjectMethod(env, exceptionClass, getName);
|
||||
if (className == NULL) {
|
||||
ExpandableStringAssign(dst, "<error getting class name>");
|
||||
(*env)->ExceptionClear(env);
|
||||
(*env)->DeleteLocalRef(env, exceptionClass);
|
||||
return false;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, exceptionClass);
|
||||
exceptionClass = NULL;
|
||||
|
||||
if (!AppendJString(env, className, dst)) {
|
||||
ExpandableStringAssign(dst, "<error getting class name UTF-8>");
|
||||
(*env)->ExceptionClear(env);
|
||||
(*env)->DeleteLocalRef(env, className);
|
||||
return false;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, className);
|
||||
className = NULL;
|
||||
|
||||
jmethodID getMessage =
|
||||
FindMethod(env, "java/lang/Throwable", "getMessage", "()Ljava/lang/String;");
|
||||
jstring message = (jstring) (*env)->CallObjectMethod(env, thrown, getMessage);
|
||||
if (message == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool success = (ExpandableStringAppend(dst, ": ") && AppendJString(env, message, dst));
|
||||
if (!success) {
|
||||
// Two potential reasons for reaching here:
|
||||
//
|
||||
// 1. managed heap allocation failure (OOME).
|
||||
// 2. native heap allocation failure for the storage in |dst|.
|
||||
//
|
||||
// Attempt to append failure notification, okay to fail, |dst| contains the class name
|
||||
// of |thrown|.
|
||||
ExpandableStringAppend(dst, "<error getting message>");
|
||||
// Clear OOME if present.
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, message);
|
||||
message = NULL;
|
||||
return success;
|
||||
}
|
||||
|
||||
static jobject NewStringWriter(JNIEnv* env) {
|
||||
jclass clazz = (*env)->FindClass(env, "java/io/StringWriter");
|
||||
jmethodID init = (*env)->GetMethodID(env, clazz, "<init>", "()V");
|
||||
jobject instance = (*env)->NewObject(env, clazz, init);
|
||||
(*env)->DeleteLocalRef(env, clazz);
|
||||
return instance;
|
||||
}
|
||||
|
||||
static jstring StringWriterToString(JNIEnv* env, jobject stringWriter) {
|
||||
jmethodID toString =
|
||||
FindMethod(env, "java/io/StringWriter", "toString", "()Ljava/lang/String;");
|
||||
return (jstring) (*env)->CallObjectMethod(env, stringWriter, toString);
|
||||
}
|
||||
|
||||
static jobject NewPrintWriter(JNIEnv* env, jobject writer) {
|
||||
jclass clazz = (*env)->FindClass(env, "java/io/PrintWriter");
|
||||
jmethodID init = (*env)->GetMethodID(env, clazz, "<init>", "(Ljava/io/Writer;)V");
|
||||
jobject instance = (*env)->NewObject(env, clazz, init, writer);
|
||||
(*env)->DeleteLocalRef(env, clazz);
|
||||
return instance;
|
||||
}
|
||||
|
||||
static bool GetStackTrace(JNIEnv* env, jthrowable thrown, struct ExpandableString* dst) {
|
||||
// This function is equivalent to the following Java snippet:
|
||||
// StringWriter sw = new StringWriter();
|
||||
// PrintWriter pw = new PrintWriter(sw);
|
||||
// thrown.printStackTrace(pw);
|
||||
// String trace = sw.toString();
|
||||
// return trace;
|
||||
jobject sw = NewStringWriter(env);
|
||||
if (sw == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jobject pw = NewPrintWriter(env, sw);
|
||||
if (pw == NULL) {
|
||||
(*env)->DeleteLocalRef(env, sw);
|
||||
return false;
|
||||
}
|
||||
|
||||
jmethodID printStackTrace =
|
||||
FindMethod(env, "java/lang/Throwable", "printStackTrace", "(Ljava/io/PrintWriter;)V");
|
||||
(*env)->CallVoidMethod(env, thrown, printStackTrace, pw);
|
||||
|
||||
jstring trace = StringWriterToString(env, sw);
|
||||
|
||||
(*env)->DeleteLocalRef(env, pw);
|
||||
pw = NULL;
|
||||
(*env)->DeleteLocalRef(env, sw);
|
||||
sw = NULL;
|
||||
|
||||
if (trace == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = AppendJString(env, trace, dst);
|
||||
(*env)->DeleteLocalRef(env, trace);
|
||||
return success;
|
||||
}
|
||||
|
||||
static void GetStackTraceOrSummary(JNIEnv* env, jthrowable thrown, struct ExpandableString* dst) {
|
||||
// This method attempts to get a stack trace or summary info for an exception.
|
||||
// The exception may be provided in the |thrown| argument to this function.
|
||||
// If |thrown| is NULL, then any pending exception is used if it exists.
|
||||
|
||||
// Save pending exception, callees may raise other exceptions. Any pending exception is
|
||||
// rethrown when this function exits.
|
||||
jthrowable pendingException = (*env)->ExceptionOccurred(env);
|
||||
if (pendingException != NULL) {
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
|
||||
if (thrown == NULL) {
|
||||
if (pendingException == NULL) {
|
||||
ExpandableStringAssign(dst, "<no pending exception>");
|
||||
return;
|
||||
}
|
||||
thrown = pendingException;
|
||||
}
|
||||
|
||||
if (!GetStackTrace(env, thrown, dst)) {
|
||||
// GetStackTrace may have raised an exception, clear it since it's not for the caller.
|
||||
(*env)->ExceptionClear(env);
|
||||
GetExceptionSummary(env, thrown, dst);
|
||||
}
|
||||
|
||||
if (pendingException != NULL) {
|
||||
// Re-throw the pending exception present when this method was called.
|
||||
(*env)->Throw(env, pendingException);
|
||||
(*env)->DeleteLocalRef(env, pendingException);
|
||||
}
|
||||
}
|
||||
|
||||
static void DiscardPendingException(JNIEnv* env, const char* className) {
|
||||
jthrowable exception = (*env)->ExceptionOccurred(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
if (exception == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct ExpandableString summary;
|
||||
ExpandableStringInitialize(&summary);
|
||||
GetExceptionSummary(env, exception, &summary);
|
||||
const char* details = (summary.data != NULL) ? summary.data : "Unknown";
|
||||
ALOGW("Discarding pending exception (%s) to throw %s", details, className);
|
||||
ExpandableStringRelease(&summary);
|
||||
(*env)->DeleteLocalRef(env, exception);
|
||||
}
|
||||
|
||||
static int ThrowException(JNIEnv* env, const char* className, const char* ctorSig, ...) {
|
||||
int status = -1;
|
||||
jclass exceptionClass = NULL;
|
||||
|
||||
va_list args;
|
||||
va_start(args, ctorSig);
|
||||
|
||||
DiscardPendingException(env, className);
|
||||
|
||||
{
|
||||
/* We want to clean up local references before returning from this function, so,
|
||||
* regardless of return status, the end block must run. Have the work done in a
|
||||
* nested block to avoid using any uninitialized variables in the end block. */
|
||||
exceptionClass = (*env)->FindClass(env, className);
|
||||
if (exceptionClass == NULL) {
|
||||
ALOGE("Unable to find exception class %s", className);
|
||||
/* an exception, most likely ClassNotFoundException, will now be pending */
|
||||
goto end;
|
||||
}
|
||||
|
||||
jmethodID init = (*env)->GetMethodID(env, exceptionClass, "<init>", ctorSig);
|
||||
if(init == NULL) {
|
||||
ALOGE("Failed to find constructor for '%s' '%s'", className, ctorSig);
|
||||
goto end;
|
||||
}
|
||||
|
||||
jobject instance = (*env)->NewObjectV(env, exceptionClass, init, args);
|
||||
if (instance == NULL) {
|
||||
ALOGE("Failed to construct '%s'", className);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((*env)->Throw(env, (jthrowable)instance) != JNI_OK) {
|
||||
ALOGE("Failed to throw '%s'", className);
|
||||
/* an exception, most likely OOM, will now be pending */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* everything worked fine, just update status to success and clean up */
|
||||
status = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
va_end(args);
|
||||
if (exceptionClass != NULL) {
|
||||
(*env)->DeleteLocalRef(env, exceptionClass);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static jstring CreateExceptionMsg(JNIEnv* env, const char* msg) {
|
||||
jstring detailMessage = (*env)->NewStringUTF(env, msg);
|
||||
if (detailMessage == NULL) {
|
||||
/* Not really much we can do here. We're probably dead in the water,
|
||||
but let's try to stumble on... */
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
return detailMessage;
|
||||
}
|
||||
|
||||
/* Helper macro to deal with conversion of the exception message from a C string
|
||||
* to jstring.
|
||||
*
|
||||
* This is useful because most exceptions have a message as the first parameter
|
||||
* and delegating the conversion to all the callers of ThrowException results in
|
||||
* code duplication. However, since we try to allow variable number of arguments
|
||||
* for the exception constructor we'd either need to do the conversion inside
|
||||
* the macro, or manipulate the va_list to replace the C string to a jstring.
|
||||
* This seems like the cleaner solution.
|
||||
*/
|
||||
#define THROW_EXCEPTION_WITH_MESSAGE(env, className, ctorSig, msg, ...) ({ \
|
||||
jstring _detailMessage = CreateExceptionMsg(env, msg); \
|
||||
int _status = ThrowException(env, className, ctorSig, _detailMessage, ## __VA_ARGS__); \
|
||||
if (_detailMessage != NULL) { \
|
||||
(*env)->DeleteLocalRef(env, _detailMessage); \
|
||||
} \
|
||||
_status; })
|
||||
|
||||
//
|
||||
// JNIHelp external API
|
||||
//
|
||||
|
||||
int jniRegisterNativeMethods(JNIEnv* env, const char* className,
|
||||
const JNINativeMethod* methods, int numMethods)
|
||||
{
|
||||
ALOGV("Registering %s's %d native methods...", className, numMethods);
|
||||
jclass clazz = (*env)->FindClass(env, className);
|
||||
ALOG_ALWAYS_FATAL_IF(clazz == NULL,
|
||||
"Native registration unable to find class '%s'; aborting...",
|
||||
className);
|
||||
int result = (*env)->RegisterNatives(env, clazz, methods, numMethods);
|
||||
(*env)->DeleteLocalRef(env, clazz);
|
||||
if (result == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Failure to register natives is fatal. Try to report the corresponding exception,
|
||||
// otherwise abort with generic failure message.
|
||||
jthrowable thrown = (*env)->ExceptionOccurred(env);
|
||||
if (thrown != NULL) {
|
||||
struct ExpandableString summary;
|
||||
ExpandableStringInitialize(&summary);
|
||||
if (GetExceptionSummary(env, thrown, &summary)) {
|
||||
ALOGF("%s", summary.data);
|
||||
}
|
||||
ExpandableStringRelease(&summary);
|
||||
(*env)->DeleteLocalRef(env, thrown);
|
||||
}
|
||||
ALOGF("RegisterNatives failed for '%s'; aborting...", className);
|
||||
return result;
|
||||
}
|
||||
|
||||
void jniLogException(JNIEnv* env, int priority, const char* tag, jthrowable thrown) {
|
||||
struct ExpandableString summary;
|
||||
ExpandableStringInitialize(&summary);
|
||||
GetStackTraceOrSummary(env, thrown, &summary);
|
||||
const char* details = (summary.data != NULL) ? summary.data : "No memory to report exception";
|
||||
__android_log_write(priority, tag, details);
|
||||
ExpandableStringRelease(&summary);
|
||||
}
|
||||
|
||||
int jniThrowException(JNIEnv* env, const char* className, const char* message) {
|
||||
return THROW_EXCEPTION_WITH_MESSAGE(env, className, "(Ljava/lang/String;)V", message);
|
||||
}
|
||||
|
||||
int jniThrowExceptionFmt(JNIEnv* env, const char* className, const char* fmt, va_list args) {
|
||||
char msgBuf[512];
|
||||
vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
|
||||
return jniThrowException(env, className, msgBuf);
|
||||
}
|
||||
|
||||
int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
|
||||
return jniThrowException(env, "java/lang/NullPointerException", msg);
|
||||
}
|
||||
|
||||
int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
|
||||
return jniThrowException(env, "java/lang/RuntimeException", msg);
|
||||
}
|
||||
|
||||
int jniThrowIOException(JNIEnv* env, int errno_value) {
|
||||
char buffer[80];
|
||||
const char* message = platformStrError(errno_value, buffer, sizeof(buffer));
|
||||
return jniThrowException(env, "java/io/IOException", message);
|
||||
}
|
||||
|
||||
int jniThrowErrnoException(JNIEnv* env, const char* functionName, int errno_value) {
|
||||
return THROW_EXCEPTION_WITH_MESSAGE(env, "android/system/ErrnoException",
|
||||
"(Ljava/lang/String;I)V", functionName, errno_value);
|
||||
}
|
||||
|
||||
jstring jniCreateString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
|
||||
return (*env)->NewString(env, unicodeChars, len);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2006 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 "include_platform/nativehelper/JNIPlatformHelp.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "JniConstants.h"
|
||||
|
||||
static int GetBufferPosition(JNIEnv* env, jobject nioBuffer) {
|
||||
return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_position(env));
|
||||
}
|
||||
|
||||
static int GetBufferLimit(JNIEnv* env, jobject nioBuffer) {
|
||||
return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_limit(env));
|
||||
}
|
||||
|
||||
static int GetBufferElementSizeShift(JNIEnv* env, jobject nioBuffer) {
|
||||
return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer__elementSizeShift(env));
|
||||
}
|
||||
|
||||
jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
|
||||
jclass nioAccessClass = JniConstants_NIOAccessClass(env);
|
||||
jmethodID getBaseArrayMethod = JniConstants_NIOAccess_getBaseArray(env);
|
||||
jobject object = (*env)->CallStaticObjectMethod(env,
|
||||
nioAccessClass, getBaseArrayMethod, nioBuffer);
|
||||
return (jarray) object;
|
||||
}
|
||||
|
||||
int jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
|
||||
jclass nioAccessClass = JniConstants_NIOAccessClass(env);
|
||||
jmethodID getBaseArrayOffsetMethod = JniConstants_NIOAccess_getBaseArrayOffset(env);
|
||||
return (*env)->CallStaticIntMethod(env, nioAccessClass, getBaseArrayOffsetMethod, nioBuffer);
|
||||
}
|
||||
|
||||
jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
|
||||
jlong baseAddress = (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
|
||||
if (baseAddress != 0) {
|
||||
const int position = GetBufferPosition(env, nioBuffer);
|
||||
const int shift = GetBufferElementSizeShift(env, nioBuffer);
|
||||
baseAddress += position << shift;
|
||||
}
|
||||
return baseAddress;
|
||||
}
|
||||
|
||||
jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
|
||||
jint* position, jint* limit, jint* elementSizeShift) {
|
||||
*position = GetBufferPosition(env, nioBuffer);
|
||||
*limit = GetBufferLimit(env, nioBuffer);
|
||||
*elementSizeShift = GetBufferElementSizeShift(env, nioBuffer);
|
||||
return (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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 "JniConstants.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LOG_TAG "JniConstants"
|
||||
#include "ALog-priv.h"
|
||||
|
||||
// jclass constants list:
|
||||
// <class, signature, androidOnly>
|
||||
|
||||
#define JCLASS_CONSTANTS_LIST(V) \
|
||||
V(FileDescriptor, "java/io/FileDescriptor", false) \
|
||||
V(NIOAccess, "java/nio/NIOAccess", true) \
|
||||
V(NioBuffer, "java/nio/Buffer", false)
|
||||
|
||||
// jmethodID's of public methods constants list:
|
||||
// <Class, method, method-string, signature, is_static>
|
||||
#define JMETHODID_CONSTANTS_LIST(V) \
|
||||
V(FileDescriptor, init, "<init>", "()V", false) \
|
||||
V(NIOAccess, getBaseArray, "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;", true) \
|
||||
V(NIOAccess, getBaseArrayOffset, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I", true) \
|
||||
V(NioBuffer, array, "array", "()Ljava/lang/Object;", false) \
|
||||
V(NioBuffer, arrayOffset, "arrayOffset", "()I", false)
|
||||
|
||||
// jfieldID constants list:
|
||||
// <Class, field, signature, is_static>
|
||||
#define JFIELDID_CONSTANTS_LIST(V) \
|
||||
V(FileDescriptor, descriptor, "I", false) \
|
||||
V(NioBuffer, _elementSizeShift, "I", false) \
|
||||
V(NioBuffer, address, "J", false) \
|
||||
V(NioBuffer, limit, "I", false) \
|
||||
V(NioBuffer, position, "I", false)
|
||||
|
||||
#define CLASS_NAME(cls) g_ ## cls
|
||||
#define METHOD_NAME(cls, method) g_ ## cls ## _ ## method
|
||||
#define FIELD_NAME(cls, field) g_ ## cls ## _ ## field
|
||||
|
||||
//
|
||||
// Declare storage for cached classes, methods and fields.
|
||||
//
|
||||
|
||||
#define JCLASS_DECLARE_STORAGE(cls, ...) \
|
||||
static jclass CLASS_NAME(cls) = NULL;
|
||||
JCLASS_CONSTANTS_LIST(JCLASS_DECLARE_STORAGE)
|
||||
#undef JCLASS_DECLARE_STORAGE
|
||||
|
||||
#define JMETHODID_DECLARE_STORAGE(cls, method, ...) \
|
||||
static jmethodID METHOD_NAME(cls, method) = NULL;
|
||||
JMETHODID_CONSTANTS_LIST(JMETHODID_DECLARE_STORAGE)
|
||||
#undef JMETHODID_DECLARE_STORAGE
|
||||
|
||||
#define JFIELDID_DECLARE_STORAGE(cls, field, ...) \
|
||||
static jfieldID FIELD_NAME(cls, field) = NULL;
|
||||
JFIELDID_CONSTANTS_LIST(JFIELDID_DECLARE_STORAGE)
|
||||
#undef JFIELDID_DECLARE_STORAGE
|
||||
|
||||
//
|
||||
// Helper methods
|
||||
//
|
||||
|
||||
static jclass FindClass(JNIEnv* env, const char* signature, bool androidOnly) {
|
||||
jclass cls = (*env)->FindClass(env, signature);
|
||||
if (cls == NULL) {
|
||||
ALOG_ALWAYS_FATAL_IF(!androidOnly, "Class not found: %s", signature);
|
||||
return NULL;
|
||||
}
|
||||
return (*env)->NewGlobalRef(env, cls);
|
||||
}
|
||||
|
||||
static jmethodID FindMethod(JNIEnv* env, jclass cls,
|
||||
const char* name, const char* signature, bool isStatic) {
|
||||
jmethodID method;
|
||||
if (isStatic) {
|
||||
method = (*env)->GetStaticMethodID(env, cls, name, signature);
|
||||
} else {
|
||||
method = (*env)->GetMethodID(env, cls, name, signature);
|
||||
}
|
||||
ALOG_ALWAYS_FATAL_IF(method == NULL, "Method not found: %s:%s", name, signature);
|
||||
return method;
|
||||
}
|
||||
|
||||
static jfieldID FindField(JNIEnv* env, jclass cls,
|
||||
const char* name, const char* signature, bool isStatic) {
|
||||
jfieldID field;
|
||||
if (isStatic) {
|
||||
field = (*env)->GetStaticFieldID(env, cls, name, signature);
|
||||
} else {
|
||||
field = (*env)->GetFieldID(env, cls, name, signature);
|
||||
}
|
||||
ALOG_ALWAYS_FATAL_IF(field == NULL, "Field not found: %s:%s", name, signature);
|
||||
return field;
|
||||
}
|
||||
|
||||
static pthread_once_t g_initialized = PTHREAD_ONCE_INIT;
|
||||
static JNIEnv* g_init_env;
|
||||
|
||||
static void InitializeConstants() {
|
||||
// Initialize cached classes.
|
||||
#define JCLASS_INITIALIZE(cls, signature, androidOnly) \
|
||||
CLASS_NAME(cls) = FindClass(g_init_env, signature, androidOnly);
|
||||
JCLASS_CONSTANTS_LIST(JCLASS_INITIALIZE)
|
||||
#undef JCLASS_INITIALIZE
|
||||
|
||||
// Initialize cached methods.
|
||||
#define JMETHODID_INITIALIZE(cls, method, name, signature, isStatic) \
|
||||
METHOD_NAME(cls, method) = \
|
||||
FindMethod(g_init_env, CLASS_NAME(cls), name, signature, isStatic);
|
||||
JMETHODID_CONSTANTS_LIST(JMETHODID_INITIALIZE)
|
||||
#undef JMETHODID_INITIALIZE
|
||||
|
||||
// Initialize cached fields.
|
||||
#define JFIELDID_INITIALIZE(cls, field, signature, isStatic) \
|
||||
FIELD_NAME(cls, field) = \
|
||||
FindField(g_init_env, CLASS_NAME(cls), #field, signature, isStatic);
|
||||
JFIELDID_CONSTANTS_LIST(JFIELDID_INITIALIZE)
|
||||
#undef JFIELDID_INITIALIZE
|
||||
}
|
||||
|
||||
void EnsureInitialized(JNIEnv* env) {
|
||||
// This method has to be called in every cache accesses because library can be built
|
||||
// 2 different ways and existing usage for compat version doesn't have a good hook for
|
||||
// initialization and is widely used.
|
||||
g_init_env = env;
|
||||
pthread_once(&g_initialized, InitializeConstants);
|
||||
}
|
||||
|
||||
// API exported by libnativehelper_api.h.
|
||||
|
||||
void jniUninitializeConstants() {
|
||||
// Uninitialize cached classes, methods and fields.
|
||||
//
|
||||
// NB we assume the runtime is stopped at this point and do not delete global
|
||||
// references.
|
||||
#define JCLASS_INVALIDATE(cls, ...) CLASS_NAME(cls) = NULL;
|
||||
JCLASS_CONSTANTS_LIST(JCLASS_INVALIDATE);
|
||||
#undef JCLASS_INVALIDATE
|
||||
|
||||
#define JMETHODID_INVALIDATE(cls, method, ...) METHOD_NAME(cls, method) = NULL;
|
||||
JMETHODID_CONSTANTS_LIST(JMETHODID_INVALIDATE);
|
||||
#undef JMETHODID_INVALIDATE
|
||||
|
||||
#define JFIELDID_INVALIDATE(cls, field, ...) FIELD_NAME(cls, field) = NULL;
|
||||
JFIELDID_CONSTANTS_LIST(JFIELDID_INVALIDATE);
|
||||
#undef JFIELDID_INVALIDATE
|
||||
|
||||
// If jniConstantsUninitialize is called, runtime has shutdown. Reset
|
||||
// state as some tests re-start the runtime.
|
||||
pthread_once_t o = PTHREAD_ONCE_INIT;
|
||||
memcpy(&g_initialized, &o, sizeof(o));
|
||||
}
|
||||
|
||||
//
|
||||
// Accessors
|
||||
//
|
||||
|
||||
#define JCLASS_ACCESSOR_IMPL(cls, ...) \
|
||||
jclass JniConstants_ ## cls ## Class(JNIEnv* env) { \
|
||||
EnsureInitialized(env); \
|
||||
return CLASS_NAME(cls); \
|
||||
}
|
||||
JCLASS_CONSTANTS_LIST(JCLASS_ACCESSOR_IMPL)
|
||||
#undef JCLASS_ACCESSOR_IMPL
|
||||
|
||||
#define JMETHODID_ACCESSOR_IMPL(cls, method, ...) \
|
||||
jmethodID JniConstants_ ## cls ## _ ## method(JNIEnv* env) { \
|
||||
EnsureInitialized(env); \
|
||||
return METHOD_NAME(cls, method); \
|
||||
}
|
||||
JMETHODID_CONSTANTS_LIST(JMETHODID_ACCESSOR_IMPL)
|
||||
|
||||
#define JFIELDID_ACCESSOR_IMPL(cls, field, ...) \
|
||||
jfieldID JniConstants_ ## cls ## _ ## field(JNIEnv* env) { \
|
||||
EnsureInitialized(env); \
|
||||
return FIELD_NAME(cls, field); \
|
||||
}
|
||||
JFIELDID_CONSTANTS_LIST(JFIELDID_ACCESSOR_IMPL)
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
//
|
||||
// Classes in constants cache.
|
||||
//
|
||||
// NB The implementations of these methods are generated by the JCLASS_ACCESSOR_IMPL macro in
|
||||
// JniConstants.c.
|
||||
//
|
||||
jclass JniConstants_FileDescriptorClass(JNIEnv* env);
|
||||
jclass JniConstants_NIOAccessClass(JNIEnv* env);
|
||||
jclass JniConstants_NioBufferClass(JNIEnv* env);
|
||||
|
||||
//
|
||||
// Methods in the constants cache.
|
||||
//
|
||||
// NB The implementations of these methods are generated by the JMETHODID_ACCESSOR_IMPL macro in
|
||||
// JniConstants.c.
|
||||
//
|
||||
jmethodID JniConstants_FileDescriptor_init(JNIEnv* env);
|
||||
jmethodID JniConstants_NIOAccess_getBaseArray(JNIEnv* env);
|
||||
jmethodID JniConstants_NIOAccess_getBaseArrayOffset(JNIEnv* env);
|
||||
jmethodID JniConstants_NioBuffer_array(JNIEnv* env);
|
||||
jmethodID JniConstants_NioBuffer_arrayOffset(JNIEnv* env);
|
||||
|
||||
//
|
||||
// Fields in the constants cache.
|
||||
//
|
||||
// NB The implementations of these methods are generated by the JFIELDID_ACCESSOR_IMPL macro in
|
||||
// JniConstants.c.
|
||||
//
|
||||
jfieldID JniConstants_FileDescriptor_descriptor(JNIEnv* env);
|
||||
jfieldID JniConstants_NioBuffer_address(JNIEnv* env);
|
||||
jfieldID JniConstants_NioBuffer__elementSizeShift(JNIEnv* env);
|
||||
jfieldID JniConstants_NioBuffer_limit(JNIEnv* env);
|
||||
jfieldID JniConstants_NioBuffer_position(JNIEnv* env);
|
||||
|
||||
__END_DECLS
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
const char* JniInvocationGetLibraryWith(const char* library,
|
||||
bool is_debuggable,
|
||||
const char* system_preferred_library);
|
||||
|
||||
__END_DECLS
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright (C) 2013 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 "include_platform/nativehelper/JniInvocation.h"
|
||||
|
||||
#define LOG_TAG "JniInvocation"
|
||||
#include "ALog-priv.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <sys/system_properties.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <jni.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "DlHelp.h"
|
||||
|
||||
// Name the default library providing the JNI Invocation API.
|
||||
static const char* kDefaultJniInvocationLibrary = "libart.so";
|
||||
static const char* kDebugJniInvocationLibrary = "libartd.so";
|
||||
#if defined(__LP64__)
|
||||
#define LIB_DIR "lib64"
|
||||
#else
|
||||
#define LIB_DIR "lib"
|
||||
#endif
|
||||
static const char* kDebugJniInvocationLibraryPath = "/apex/com.android.art/" LIB_DIR "/libartd.so";
|
||||
|
||||
struct JniInvocationImpl {
|
||||
// Name of library providing JNI_ method implementations.
|
||||
const char* jni_provider_library_name;
|
||||
|
||||
// Opaque pointer to shared library from dlopen / LoadLibrary.
|
||||
void* jni_provider_library;
|
||||
|
||||
// Function pointers to methods in JNI provider.
|
||||
jint (*JNI_GetDefaultJavaVMInitArgs)(void*);
|
||||
jint (*JNI_CreateJavaVM)(JavaVM**, JNIEnv**, void*);
|
||||
jint (*JNI_GetCreatedJavaVMs)(JavaVM**, jsize, jsize*);
|
||||
};
|
||||
|
||||
static struct JniInvocationImpl g_impl;
|
||||
|
||||
//
|
||||
// Internal helpers.
|
||||
//
|
||||
|
||||
#define UNUSED(x) (x) = (x)
|
||||
|
||||
static bool IsDebuggable() {
|
||||
#ifdef __ANDROID__
|
||||
char debuggable[PROP_VALUE_MAX] = {0};
|
||||
__system_property_get("ro.debuggable", debuggable);
|
||||
return strcmp(debuggable, "1") == 0;
|
||||
#else
|
||||
// Host is always treated as debuggable, which allows choice of library to be overridden.
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int GetLibrarySystemProperty(char* buffer) {
|
||||
#ifdef __ANDROID__
|
||||
return __system_property_get("persist.sys.dalvik.vm.lib.2", buffer);
|
||||
#else
|
||||
// Host does not use properties.
|
||||
UNUSED(buffer);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static DlSymbol FindSymbol(DlLibrary library, const char* symbol) {
|
||||
DlSymbol s = DlGetSymbol(library, symbol);
|
||||
if (s == NULL) {
|
||||
ALOGE("Failed to find symbol: %s", symbol);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
//
|
||||
// Exported functions for JNI based VM management from JNI spec.
|
||||
//
|
||||
|
||||
jint JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
|
||||
ALOG_ALWAYS_FATAL_IF(NULL == g_impl.JNI_GetDefaultJavaVMInitArgs, "Runtime library not loaded.");
|
||||
return g_impl.JNI_GetDefaultJavaVMInitArgs(vmargs);
|
||||
}
|
||||
|
||||
jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
|
||||
ALOG_ALWAYS_FATAL_IF(NULL == g_impl.JNI_CreateJavaVM, "Runtime library not loaded.");
|
||||
return g_impl.JNI_CreateJavaVM(p_vm, p_env, vm_args);
|
||||
}
|
||||
|
||||
jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
|
||||
if (NULL == g_impl.JNI_GetCreatedJavaVMs) {
|
||||
*vm_count = 0;
|
||||
return JNI_OK;
|
||||
}
|
||||
return g_impl.JNI_GetCreatedJavaVMs(vms, size, vm_count);
|
||||
}
|
||||
|
||||
//
|
||||
// JniInvocation functions for setting up JNI functions.
|
||||
//
|
||||
|
||||
const char* JniInvocationGetLibraryWith(const char* library,
|
||||
bool is_debuggable,
|
||||
const char* system_preferred_library) {
|
||||
if (is_debuggable) {
|
||||
// Debuggable property is set. Allow library providing JNI Invocation API to be overridden.
|
||||
|
||||
// Choose the library parameter (if provided).
|
||||
if (library != NULL) {
|
||||
return library;
|
||||
}
|
||||
|
||||
// If the debug library is installed, use it.
|
||||
// TODO(b/216099383): Do this in the test harness instead.
|
||||
struct stat st;
|
||||
if (stat(kDebugJniInvocationLibraryPath, &st) == 0) {
|
||||
return kDebugJniInvocationLibrary;
|
||||
} else if (errno != ENOENT) {
|
||||
ALOGW("Failed to stat %s: %s", kDebugJniInvocationLibraryPath, strerror(errno));
|
||||
}
|
||||
|
||||
// Choose the system_preferred_library (if provided).
|
||||
if (system_preferred_library != NULL) {
|
||||
return system_preferred_library;
|
||||
}
|
||||
|
||||
}
|
||||
return kDefaultJniInvocationLibrary;
|
||||
}
|
||||
|
||||
const char* JniInvocationGetLibrary(const char* library, char* buffer) {
|
||||
bool debuggable = IsDebuggable();
|
||||
const char* system_preferred_library = NULL;
|
||||
if (buffer != NULL && (GetLibrarySystemProperty(buffer) > 0)) {
|
||||
system_preferred_library = buffer;
|
||||
}
|
||||
return JniInvocationGetLibraryWith(library, debuggable, system_preferred_library);
|
||||
}
|
||||
|
||||
struct JniInvocationImpl* JniInvocationCreate() {
|
||||
// Android only supports a single JniInvocation instance and only a single JavaVM.
|
||||
if (g_impl.jni_provider_library != NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return &g_impl;
|
||||
}
|
||||
|
||||
bool JniInvocationInit(struct JniInvocationImpl* instance, const char* library_name) {
|
||||
#ifdef __ANDROID__
|
||||
char buffer[PROP_VALUE_MAX];
|
||||
#else
|
||||
char* buffer = NULL;
|
||||
#endif
|
||||
library_name = JniInvocationGetLibrary(library_name, buffer);
|
||||
DlLibrary library = DlOpenLibrary(library_name);
|
||||
if (library == NULL) {
|
||||
if (strcmp(library_name, kDefaultJniInvocationLibrary) == 0) {
|
||||
// Nothing else to try.
|
||||
ALOGE("Failed to dlopen %s: %s", library_name, DlGetError());
|
||||
return false;
|
||||
}
|
||||
// Note that this is enough to get something like the zygote
|
||||
// running, we can't property_set here to fix this for the future
|
||||
// because we are root and not the system user. See
|
||||
// RuntimeInit.commonInit for where we fix up the property to
|
||||
// avoid future fallbacks. http://b/11463182
|
||||
ALOGW("Falling back from %s to %s after dlopen error: %s",
|
||||
library_name, kDefaultJniInvocationLibrary, DlGetError());
|
||||
library_name = kDefaultJniInvocationLibrary;
|
||||
library = DlOpenLibrary(library_name);
|
||||
if (library == NULL) {
|
||||
ALOGE("Failed to dlopen %s: %s", library_name, DlGetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DlSymbol JNI_GetDefaultJavaVMInitArgs_ = FindSymbol(library, "JNI_GetDefaultJavaVMInitArgs");
|
||||
if (JNI_GetDefaultJavaVMInitArgs_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DlSymbol JNI_CreateJavaVM_ = FindSymbol(library, "JNI_CreateJavaVM");
|
||||
if (JNI_CreateJavaVM_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DlSymbol JNI_GetCreatedJavaVMs_ = FindSymbol(library, "JNI_GetCreatedJavaVMs");
|
||||
if (JNI_GetCreatedJavaVMs_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
instance->jni_provider_library_name = library_name;
|
||||
instance->jni_provider_library = library;
|
||||
instance->JNI_GetDefaultJavaVMInitArgs = (jint (*)(void *)) JNI_GetDefaultJavaVMInitArgs_;
|
||||
instance->JNI_CreateJavaVM = (jint (*)(JavaVM**, JNIEnv**, void*)) JNI_CreateJavaVM_;
|
||||
instance->JNI_GetCreatedJavaVMs = (jint (*)(JavaVM**, jsize, jsize*)) JNI_GetCreatedJavaVMs_;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JniInvocationDestroy(struct JniInvocationImpl* instance) {
|
||||
DlCloseLibrary(instance->jni_provider_library);
|
||||
memset(instance, 0, sizeof(*instance));
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
|
||||
Copyright (c) 2005-2008, 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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
[Builtin Hooks]
|
||||
bpfmt = true
|
|
@ -0,0 +1,97 @@
|
|||
# libnativehelper
|
||||
|
||||
libnativehelper is a collection of JNI related utilities used in Android.
|
||||
|
||||
There are several header and binary libraries here and not all of the
|
||||
functionality fits together well. The header libraries are mostly C++
|
||||
based. The binary libraries are entirely written in C with no C++
|
||||
dependencies. This is by design as the code here can be distributed in
|
||||
multiple ways, including mainline modules, so keeping the size down
|
||||
benefits everyone with smaller downloads and a stable ABI.
|
||||
|
||||
## Header Libraries
|
||||
|
||||
### jni_headers
|
||||
|
||||
This is a header library that contains provides the API represented in
|
||||
the JNI Specification 1.6. Any project in Android that depends on
|
||||
`jni.h` should depend on this.
|
||||
|
||||
See:
|
||||
|
||||
* [jni.h](include_jni/jni.h)
|
||||
|
||||
### libnativehelper_header_only
|
||||
|
||||
These headers provide utilities that defined entirely within the
|
||||
headers. There are scoped resource classes that make common JNI
|
||||
patterns of acquiring and releasing resources safer to use than the
|
||||
JNI specification equivalents. Examples being `ScopedLocalRef` to
|
||||
manage the lifetime of local references and `ScopedUtfChars` to manage
|
||||
the lifetime of Java strings in native code and provide access to utf8
|
||||
characters.
|
||||
|
||||
See:
|
||||
|
||||
* [nativehelper/nativehelper_utils.h](header_only_include/nativehelper/nativehelper_utils.h)
|
||||
* [nativehelper/scoped_utf_chars.h](header_only_include/nativehelper/scoped_utf_chars.h)
|
||||
* [nativehelper/scoped_bytes.h](header_only_include/nativehelper/scoped_bytes.h)
|
||||
* [nativehelper/scoped_string_chars.h](header_only_include/nativehelper/scoped_string_chars.h)
|
||||
* [nativehelper/scoped_primitive_array.h](header_only_include/nativehelper/scoped_primitive_array.h)
|
||||
* [nativehelper/scoped_local_ref.h](header_only_include/nativehelper/scoped_local_ref.h)
|
||||
* [nativehelper/scoped_local_frame.h](header_only_include/nativehelper/scoped_local_frame.h)
|
||||
|
||||
### jni_platform_headers
|
||||
|
||||
The `jni_macros.h` header provide compile time checking of JNI methods
|
||||
implemented in C++. They ensure the C++ method declaration match the
|
||||
Java signature they are associated with.
|
||||
|
||||
See:
|
||||
|
||||
* [nativehelper/jni_macros.h](include_platform_header_only/nativehelper/jni_macros.h)
|
||||
|
||||
## Libraries
|
||||
|
||||
### libnativehelper
|
||||
|
||||
A shared library distributed in the ART module that provides helper
|
||||
routines built on Java APIs. This library depends on details that are
|
||||
private to libcore and use should be restricted to platform code and
|
||||
within the ART module.
|
||||
|
||||
This library also contains the JNI invocation API from the JNI
|
||||
Specification and the glue that connects the ART runtime to the API
|
||||
implementation. The glue logic is platform only as it is used with the
|
||||
Zygote and the standalone dalvikvm.
|
||||
|
||||
See:
|
||||
* [nativehelper/JNIHelp.h](include/nativehelper/JNIHelp.h)
|
||||
* [nativehelper/JniInvocation.h](include_platform/nativehelper/JniInvocation.h)
|
||||
* [nativehelper/JNIPlatformHelp.h](include_platform/nativehelper/JNIPlatformHelp.h)
|
||||
* [nativehelper/ScopedBytes.h](include/nativehelper/ScopedBytes.h)
|
||||
* [nativehelper/ScopedUtfChars.h](include/nativehelper/ScopedUtfChars.h)
|
||||
* [nativehelper/ScopedLocalFrame.h](include/nativehelper/ScopedLocalFrame.h)
|
||||
* [nativehelper/ScopedLocalRef.h](include/nativehelper/ScopedLocalRef.h)
|
||||
* [nativehelper/ScopedPrimitiveArray.h](include/nativehelper/ScopedPrimitiveArray.h)
|
||||
* [nativehelper/ScopedStringChars.h](include/nativehelper/ScopedStringChars.h)
|
||||
* [nativehelper/toStringArray.h](include/nativehelper/toStringArray.h)
|
||||
|
||||
### libnativehelper_compat_libc++
|
||||
|
||||
This shared and static library contains a subset of the helper
|
||||
routines in libnativehelper based on public Java API. This code can be
|
||||
statically linked as the Java APIs it depends on are considered
|
||||
stable. The name of this library is a misnomer since it contains no
|
||||
C++ code.
|
||||
|
||||
See:
|
||||
|
||||
* [nativehelper/JNIHelp.h](include/nativehelper/JNIHelp.h)
|
||||
* [nativehelper/ScopedBytes.h](include/nativehelper/ScopedBytes.h)
|
||||
* [nativehelper/ScopedUtfChars.h](include/nativehelper/ScopedUtfChars.h)
|
||||
* [nativehelper/ScopedLocalFrame.h](include/nativehelper/ScopedLocalFrame.h)
|
||||
* [nativehelper/ScopedLocalRef.h](include/nativehelper/ScopedLocalRef.h)
|
||||
* [nativehelper/ScopedPrimitiveArray.h](include/nativehelper/ScopedPrimitiveArray.h)
|
||||
* [nativehelper/ScopedStringChars.h](include/nativehelper/ScopedStringChars.h)
|
||||
* [nativehelper/toStringArray.h](include/nativehelper/toStringArray.h)
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"presubmit": [
|
||||
{
|
||||
"name": "libnativehelper_tests"
|
||||
},
|
||||
{
|
||||
"name": "libnativehelper_lazy_tests"
|
||||
},
|
||||
{
|
||||
"name": "MtsLibnativehelperTestCases"
|
||||
},
|
||||
{
|
||||
"name": "MtsLibnativehelperLazyTestCases"
|
||||
},
|
||||
{
|
||||
"name": "CtsLibnativehelperTestCases"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <android/file_descriptor_jni.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define LOG_TAG "file_descriptor_jni"
|
||||
#include "ALog-priv.h"
|
||||
|
||||
#include "JniConstants.h"
|
||||
|
||||
static void EnsureArgumentIsFileDescriptor(JNIEnv* env, jobject instance) {
|
||||
ALOG_ALWAYS_FATAL_IF(instance == NULL, "FileDescriptor is NULL");
|
||||
jclass jifd = JniConstants_FileDescriptorClass(env);
|
||||
ALOG_ALWAYS_FATAL_IF(!(*env)->IsInstanceOf(env, instance, jifd),
|
||||
"Argument is not a FileDescriptor");
|
||||
}
|
||||
|
||||
JNIEXPORT _Nullable jobject AFileDescriptor_create(JNIEnv* env) {
|
||||
return (*env)->NewObject(env,
|
||||
JniConstants_FileDescriptorClass(env),
|
||||
JniConstants_FileDescriptor_init(env));
|
||||
}
|
||||
|
||||
JNIEXPORT int AFileDescriptor_getFd(JNIEnv* env, jobject fileDescriptor) {
|
||||
EnsureArgumentIsFileDescriptor(env, fileDescriptor);
|
||||
return (*env)->GetIntField(env, fileDescriptor, JniConstants_FileDescriptor_descriptor(env));
|
||||
}
|
||||
|
||||
JNIEXPORT void AFileDescriptor_setFd(JNIEnv* env, jobject fileDescriptor, int fd) {
|
||||
EnsureArgumentIsFileDescriptor(env, fileDescriptor);
|
||||
(*env)->SetIntField(env, fileDescriptor, JniConstants_FileDescriptor_descriptor(env), fd);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2007 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#if !defined(DISALLOW_COPY_AND_ASSIGN)
|
||||
// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. It goes in the private:
|
||||
// declarations in a class.
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&) = delete; \
|
||||
void operator=(const TypeName&) = delete
|
||||
#endif // !defined(DISALLOW_COPY_AND_ASSIGN)
|
||||
|
||||
// This seems a header-only include. Provide NPE throwing.
|
||||
static inline int jniThrowNullPointerException(JNIEnv* env) {
|
||||
if (env->ExceptionCheck()) {
|
||||
// Drop any pending exception.
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
jclass e_class = env->FindClass("java/lang/NullPointerException");
|
||||
if (e_class == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (env->ThrowNew(e_class, nullptr) != JNI_OK) {
|
||||
env->DeleteLocalRef(e_class);
|
||||
return -1;
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(e_class);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // defined(__cplusplus)
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "nativehelper_utils.h"
|
||||
|
||||
class ScopedLocalFrame {
|
||||
public:
|
||||
explicit ScopedLocalFrame(JNIEnv* env) : mEnv(env) {
|
||||
mEnv->PushLocalFrame(128);
|
||||
}
|
||||
|
||||
~ScopedLocalFrame() {
|
||||
mEnv->PopLocalFrame(nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
JNIEnv* const mEnv;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedLocalFrame);
|
||||
};
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "nativehelper_utils.h"
|
||||
|
||||
// A smart pointer that deletes a JNI local reference when it goes out of scope.
|
||||
template<typename T>
|
||||
class ScopedLocalRef {
|
||||
public:
|
||||
ScopedLocalRef(JNIEnv* env, T localRef) : mEnv(env), mLocalRef(localRef) {
|
||||
}
|
||||
|
||||
ScopedLocalRef(ScopedLocalRef&& s) noexcept : mEnv(s.mEnv), mLocalRef(s.release()) {
|
||||
}
|
||||
|
||||
explicit ScopedLocalRef(JNIEnv* env) : mEnv(env), mLocalRef(nullptr) {
|
||||
}
|
||||
|
||||
~ScopedLocalRef() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset(T ptr = nullptr) {
|
||||
if (ptr != mLocalRef) {
|
||||
if (mLocalRef != nullptr) {
|
||||
mEnv->DeleteLocalRef(mLocalRef);
|
||||
}
|
||||
mLocalRef = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
T release() __attribute__((warn_unused_result)) {
|
||||
T localRef = mLocalRef;
|
||||
mLocalRef = nullptr;
|
||||
return localRef;
|
||||
}
|
||||
|
||||
T get() const {
|
||||
return mLocalRef;
|
||||
}
|
||||
|
||||
|
||||
// We do not expose an empty constructor as it can easily lead to errors
|
||||
// using common idioms, e.g.:
|
||||
// ScopedLocalRef<...> ref;
|
||||
// ref.reset(...);
|
||||
|
||||
// Move assignment operator.
|
||||
ScopedLocalRef& operator=(ScopedLocalRef&& s) noexcept {
|
||||
reset(s.release());
|
||||
mEnv = s.mEnv;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Allows "if (scoped_ref == nullptr)"
|
||||
bool operator==(std::nullptr_t) const {
|
||||
return mLocalRef == nullptr;
|
||||
}
|
||||
|
||||
// Allows "if (scoped_ref != nullptr)"
|
||||
bool operator!=(std::nullptr_t) const {
|
||||
return mLocalRef != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
JNIEnv* mEnv;
|
||||
T mLocalRef;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);
|
||||
};
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "nativehelper_utils.h"
|
||||
|
||||
#ifdef POINTER_TYPE
|
||||
#error POINTER_TYPE is defined.
|
||||
#else
|
||||
#define POINTER_TYPE(T) T* /* NOLINT */
|
||||
#endif
|
||||
|
||||
#ifdef REFERENCE_TYPE
|
||||
#error REFERENCE_TYPE is defined.
|
||||
#else
|
||||
#define REFERENCE_TYPE(T) T& /* NOLINT */
|
||||
#endif
|
||||
|
||||
// ScopedBooleanArrayRO, ScopedByteArrayRO, ScopedCharArrayRO, ScopedDoubleArrayRO,
|
||||
// ScopedFloatArrayRO, ScopedIntArrayRO, ScopedLongArrayRO, and ScopedShortArrayRO provide
|
||||
// convenient read-only access to Java arrays from JNI code. This is cheaper than read-write
|
||||
// access and should be used by default.
|
||||
#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(PRIMITIVE_TYPE, NAME) \
|
||||
class Scoped ## NAME ## ArrayRO { \
|
||||
public: \
|
||||
explicit Scoped ## NAME ## ArrayRO(JNIEnv* env) \
|
||||
: mEnv(env), mJavaArray(nullptr), mRawArray(nullptr), mSize(0) {} \
|
||||
Scoped ## NAME ## ArrayRO(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
|
||||
: mEnv(env) { \
|
||||
if (javaArray == nullptr) { \
|
||||
mJavaArray = nullptr; \
|
||||
mSize = 0; \
|
||||
mRawArray = nullptr; \
|
||||
jniThrowNullPointerException(mEnv); \
|
||||
} else { \
|
||||
reset(javaArray); \
|
||||
} \
|
||||
} \
|
||||
~Scoped ## NAME ## ArrayRO() { \
|
||||
if (mRawArray != nullptr && mRawArray != mBuffer) { \
|
||||
mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, JNI_ABORT); \
|
||||
} \
|
||||
} \
|
||||
void reset(PRIMITIVE_TYPE ## Array javaArray) { \
|
||||
mJavaArray = javaArray; \
|
||||
mSize = mEnv->GetArrayLength(mJavaArray); \
|
||||
if (mSize <= buffer_size) { \
|
||||
mEnv->Get ## NAME ## ArrayRegion(mJavaArray, 0, mSize, mBuffer); \
|
||||
mRawArray = mBuffer; \
|
||||
} else { \
|
||||
mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
|
||||
} \
|
||||
} \
|
||||
const PRIMITIVE_TYPE* get() const { return mRawArray; } \
|
||||
PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
|
||||
const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
|
||||
size_t size() const { return mSize; } \
|
||||
private: \
|
||||
static const jsize buffer_size = 1024; \
|
||||
JNIEnv* const mEnv; \
|
||||
PRIMITIVE_TYPE ## Array mJavaArray; \
|
||||
POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
|
||||
jsize mSize; \
|
||||
PRIMITIVE_TYPE mBuffer[buffer_size]; \
|
||||
DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRO); \
|
||||
}
|
||||
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jboolean, Boolean);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jbyte, Byte);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jchar, Char);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jdouble, Double);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jfloat, Float);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jint, Int);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jlong, Long);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jshort, Short);
|
||||
|
||||
#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO
|
||||
|
||||
// ScopedBooleanArrayRW, ScopedByteArrayRW, ScopedCharArrayRW, ScopedDoubleArrayRW,
|
||||
// ScopedFloatArrayRW, ScopedIntArrayRW, ScopedLongArrayRW, and ScopedShortArrayRW provide
|
||||
// convenient read-write access to Java arrays from JNI code. These are more expensive,
|
||||
// since they entail a copy back onto the Java heap, and should only be used when necessary.
|
||||
#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(PRIMITIVE_TYPE, NAME) \
|
||||
class Scoped ## NAME ## ArrayRW { \
|
||||
public: \
|
||||
explicit Scoped ## NAME ## ArrayRW(JNIEnv* env) \
|
||||
: mEnv(env), mJavaArray(nullptr), mRawArray(nullptr) {} \
|
||||
Scoped ## NAME ## ArrayRW(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
|
||||
: mEnv(env), mJavaArray(javaArray), mRawArray(nullptr) { \
|
||||
if (mJavaArray == nullptr) { \
|
||||
jniThrowNullPointerException(mEnv); \
|
||||
} else { \
|
||||
mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
|
||||
} \
|
||||
} \
|
||||
~Scoped ## NAME ## ArrayRW() { \
|
||||
if (mRawArray) { \
|
||||
mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, 0); \
|
||||
} \
|
||||
} \
|
||||
void reset(PRIMITIVE_TYPE ## Array javaArray) { \
|
||||
mJavaArray = javaArray; \
|
||||
mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
|
||||
} \
|
||||
const PRIMITIVE_TYPE* get() const { return mRawArray; } \
|
||||
PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
|
||||
const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
|
||||
POINTER_TYPE(PRIMITIVE_TYPE) get() { return mRawArray; } \
|
||||
REFERENCE_TYPE(PRIMITIVE_TYPE) operator[](size_t n) { return mRawArray[n]; } \
|
||||
size_t size() const { return mEnv->GetArrayLength(mJavaArray); } \
|
||||
private: \
|
||||
JNIEnv* const mEnv; \
|
||||
PRIMITIVE_TYPE ## Array mJavaArray; \
|
||||
POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
|
||||
DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRW); \
|
||||
}
|
||||
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jboolean, Boolean);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jbyte, Byte);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jchar, Char);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jdouble, Double);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jfloat, Float);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jint, Int);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jlong, Long);
|
||||
INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jshort, Short);
|
||||
|
||||
#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW
|
||||
#undef POINTER_TYPE
|
||||
#undef REFERENCE_TYPE
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "nativehelper_utils.h"
|
||||
|
||||
// A smart pointer that provides access to a jchar* given a JNI jstring.
|
||||
// Unlike GetStringChars, we throw NullPointerException rather than abort if
|
||||
// passed a null jstring, and get will return nullptr.
|
||||
// This makes the correct idiom very simple:
|
||||
//
|
||||
// ScopedStringChars name(env, java_name);
|
||||
// if (name.get() == nullptr) {
|
||||
// return nullptr;
|
||||
// }
|
||||
class ScopedStringChars {
|
||||
public:
|
||||
ScopedStringChars(JNIEnv* env, jstring s) : env_(env), string_(s), size_(0) {
|
||||
if (s == nullptr) {
|
||||
chars_ = nullptr;
|
||||
jniThrowNullPointerException(env);
|
||||
} else {
|
||||
chars_ = env->GetStringChars(string_, nullptr);
|
||||
if (chars_ != nullptr) {
|
||||
size_ = env->GetStringLength(string_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedStringChars() {
|
||||
if (chars_ != nullptr) {
|
||||
env_->ReleaseStringChars(string_, chars_);
|
||||
}
|
||||
}
|
||||
|
||||
const jchar* get() const {
|
||||
return chars_;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
const jchar& operator[](size_t n) const {
|
||||
return chars_[n];
|
||||
}
|
||||
|
||||
private:
|
||||
JNIEnv* const env_;
|
||||
const jstring string_;
|
||||
const jchar* chars_;
|
||||
size_t size_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedStringChars);
|
||||
};
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "nativehelper_utils.h"
|
||||
|
||||
// A smart pointer that provides read-only access to a Java string's UTF chars.
|
||||
// Unlike GetStringUTFChars, we throw NullPointerException rather than abort if
|
||||
// passed a null jstring, and c_str will return nullptr.
|
||||
// This makes the correct idiom very simple:
|
||||
//
|
||||
// ScopedUtfChars name(env, java_name);
|
||||
// if (name.c_str() == nullptr) {
|
||||
// return nullptr;
|
||||
// }
|
||||
class ScopedUtfChars {
|
||||
public:
|
||||
ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
|
||||
if (s == nullptr) {
|
||||
utf_chars_ = nullptr;
|
||||
jniThrowNullPointerException(env);
|
||||
} else {
|
||||
utf_chars_ = env->GetStringUTFChars(s, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
ScopedUtfChars(ScopedUtfChars&& rhs) noexcept :
|
||||
env_(rhs.env_), string_(rhs.string_), utf_chars_(rhs.utf_chars_) {
|
||||
rhs.env_ = nullptr;
|
||||
rhs.string_ = nullptr;
|
||||
rhs.utf_chars_ = nullptr;
|
||||
}
|
||||
|
||||
~ScopedUtfChars() {
|
||||
if (utf_chars_) {
|
||||
env_->ReleaseStringUTFChars(string_, utf_chars_);
|
||||
}
|
||||
}
|
||||
|
||||
ScopedUtfChars& operator=(ScopedUtfChars&& rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
// Delete the currently owned UTF chars.
|
||||
this->~ScopedUtfChars();
|
||||
|
||||
// Move the rhs ScopedUtfChars and zero it out.
|
||||
env_ = rhs.env_;
|
||||
string_ = rhs.string_;
|
||||
utf_chars_ = rhs.utf_chars_;
|
||||
rhs.env_ = nullptr;
|
||||
rhs.string_ = nullptr;
|
||||
rhs.utf_chars_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char* c_str() const {
|
||||
return utf_chars_;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return strlen(utf_chars_);
|
||||
}
|
||||
|
||||
const char& operator[](size_t n) const {
|
||||
return utf_chars_[n];
|
||||
}
|
||||
|
||||
private:
|
||||
JNIEnv* env_;
|
||||
jstring string_;
|
||||
const char* utf_chars_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedUtfChars);
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup FileDescriptor File Descriptor
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file file_descriptor_jni.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#if !defined(__BIONIC__) && !defined(__INTRODUCED_IN)
|
||||
#define __INTRODUCED_IN(x)
|
||||
#endif
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* Returns a new java.io.FileDescriptor.
|
||||
*
|
||||
* The FileDescriptor created represents an invalid Unix file descriptor (represented by
|
||||
* a file descriptor value of -1).
|
||||
*
|
||||
* Callers of this method should be aware that it can fail, returning NULL with a pending Java
|
||||
* exception.
|
||||
*
|
||||
* Available since API level 31.
|
||||
*
|
||||
* \param env a pointer to the JNI Native Interface of the current thread.
|
||||
* \return a java.io.FileDescriptor on success, nullptr if insufficient heap memory is available.
|
||||
*/
|
||||
jobject AFileDescriptor_create(JNIEnv* env) __INTRODUCED_IN(31);
|
||||
|
||||
/**
|
||||
* Returns the Unix file descriptor represented by the given java.io.FileDescriptor.
|
||||
*
|
||||
* A return value of -1 indicates that \a fileDescriptor represents an invalid file descriptor.
|
||||
*
|
||||
* Aborts the program if \a fileDescriptor is not a java.io.FileDescriptor instance.
|
||||
*
|
||||
* Available since API level 31.
|
||||
*
|
||||
* \param env a pointer to the JNI Native Interface of the current thread.
|
||||
* \param fileDescriptor a java.io.FileDescriptor instance.
|
||||
* \return the Unix file descriptor wrapped by \a fileDescriptor.
|
||||
*/
|
||||
int AFileDescriptor_getFd(JNIEnv* env, jobject fileDescriptor) __INTRODUCED_IN(31);
|
||||
|
||||
/**
|
||||
* Sets the Unix file descriptor represented by the given java.io.FileDescriptor.
|
||||
*
|
||||
* This function performs no validation of the Unix file descriptor argument, \a fd. Android uses
|
||||
* the value -1 to represent an invalid file descriptor, all other values are considered valid.
|
||||
* The validity of a file descriptor can be checked with FileDescriptor#valid().
|
||||
*
|
||||
* Aborts the program if \a fileDescriptor is not a java.io.FileDescriptor instance.
|
||||
*
|
||||
* Available since API level 31.
|
||||
*
|
||||
* \param env a pointer to the JNI Native Interface of the current thread.
|
||||
* \param fileDescriptor a java.io.FileDescriptor instance.
|
||||
* \param fd a Unix file descriptor that \a fileDescriptor will subsequently represent.
|
||||
*/
|
||||
void AFileDescriptor_setFd(JNIEnv* env, jobject fileDescriptor, int fd) __INTRODUCED_IN(31);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* Copyright (C) 2007 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* JNI helper functions.
|
||||
*
|
||||
* This file may be included by C or C++ code, which is trouble because jni.h
|
||||
* uses different typedefs for JNIEnv in each language.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
// Avoid formatting this as it must match webview's usage (webview/graphics_utils.cpp).
|
||||
// clang-format off
|
||||
#ifndef NELEM
|
||||
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
/*
|
||||
* For C++ code, we provide inlines that map to the C functions. g++ always
|
||||
* inlines these, even on non-optimized builds.
|
||||
*/
|
||||
#if defined(__cplusplus)
|
||||
|
||||
namespace android::jnihelp {
|
||||
struct [[maybe_unused]] ExpandableString {
|
||||
size_t dataSize; // The length of the C string data (not including the null-terminator).
|
||||
char* data; // The C string data.
|
||||
};
|
||||
|
||||
[[maybe_unused]] static void ExpandableStringInitialize(struct ExpandableString* s) {
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
[[maybe_unused]] static void ExpandableStringRelease(struct ExpandableString* s) {
|
||||
free(s->data);
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
[[maybe_unused]] static bool ExpandableStringAppend(struct ExpandableString* s, const char* text) {
|
||||
size_t textSize = strlen(text);
|
||||
size_t requiredSize = s->dataSize + textSize + 1;
|
||||
char* data = (char*)realloc(s->data, requiredSize);
|
||||
if (data == NULL) {
|
||||
return false;
|
||||
}
|
||||
s->data = data;
|
||||
memcpy(s->data + s->dataSize, text, textSize + 1);
|
||||
s->dataSize += textSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static bool ExpandableStringAssign(struct ExpandableString* s, const char* text) {
|
||||
ExpandableStringRelease(s);
|
||||
return ExpandableStringAppend(s, text);
|
||||
}
|
||||
|
||||
[[maybe_unused]] inline char* safe_strerror(char* (*strerror_r_method)(int, char*, size_t),
|
||||
int errnum, char* buf, size_t buflen) {
|
||||
return strerror_r_method(errnum, buf, buflen);
|
||||
}
|
||||
|
||||
[[maybe_unused]] inline char* safe_strerror(int (*strerror_r_method)(int, char*, size_t),
|
||||
int errnum, char* buf, size_t buflen) {
|
||||
int rc = strerror_r_method(errnum, buf, buflen);
|
||||
if (rc != 0) {
|
||||
snprintf(buf, buflen, "errno %d", errnum);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static const char* platformStrError(int errnum, char* buf, size_t buflen) {
|
||||
return safe_strerror(strerror_r, errnum, buf, buflen);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static jmethodID FindMethod(JNIEnv* env, const char* className,
|
||||
const char* methodName, const char* descriptor) {
|
||||
// This method is only valid for classes in the core library which are
|
||||
// not unloaded during the lifetime of managed code execution.
|
||||
jclass clazz = env->FindClass(className);
|
||||
jmethodID methodId = env->GetMethodID(clazz, methodName, descriptor);
|
||||
env->DeleteLocalRef(clazz);
|
||||
return methodId;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static bool AppendJString(JNIEnv* env, jstring text,
|
||||
struct ExpandableString* dst) {
|
||||
const char* utfText = env->GetStringUTFChars(text, NULL);
|
||||
if (utfText == NULL) {
|
||||
return false;
|
||||
}
|
||||
bool success = ExpandableStringAppend(dst, utfText);
|
||||
env->ReleaseStringUTFChars(text, utfText);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a human-readable summary of an exception object. The buffer will
|
||||
* be populated with the "binary" class name and, if present, the
|
||||
* exception message.
|
||||
*/
|
||||
[[maybe_unused]] static bool GetExceptionSummary(JNIEnv* env, jthrowable thrown,
|
||||
struct ExpandableString* dst) {
|
||||
// Summary is <exception_class_name> ": " <exception_message>
|
||||
jclass exceptionClass = env->GetObjectClass(thrown); // Always succeeds
|
||||
jmethodID getName = FindMethod(env, "java/lang/Class", "getName", "()Ljava/lang/String;");
|
||||
jstring className = (jstring)env->CallObjectMethod(exceptionClass, getName);
|
||||
if (className == NULL) {
|
||||
ExpandableStringAssign(dst, "<error getting class name>");
|
||||
env->ExceptionClear();
|
||||
env->DeleteLocalRef(exceptionClass);
|
||||
return false;
|
||||
}
|
||||
env->DeleteLocalRef(exceptionClass);
|
||||
exceptionClass = NULL;
|
||||
|
||||
if (!AppendJString(env, className, dst)) {
|
||||
ExpandableStringAssign(dst, "<error getting class name UTF-8>");
|
||||
env->ExceptionClear();
|
||||
env->DeleteLocalRef(className);
|
||||
return false;
|
||||
}
|
||||
env->DeleteLocalRef(className);
|
||||
className = NULL;
|
||||
|
||||
jmethodID getMessage =
|
||||
FindMethod(env, "java/lang/Throwable", "getMessage", "()Ljava/lang/String;");
|
||||
jstring message = (jstring)env->CallObjectMethod(thrown, getMessage);
|
||||
if (message == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool success = (ExpandableStringAppend(dst, ": ") && AppendJString(env, message, dst));
|
||||
if (!success) {
|
||||
// Two potential reasons for reaching here:
|
||||
//
|
||||
// 1. managed heap allocation failure (OOME).
|
||||
// 2. native heap allocation failure for the storage in |dst|.
|
||||
//
|
||||
// Attempt to append failure notification, okay to fail, |dst| contains the class name
|
||||
// of |thrown|.
|
||||
ExpandableStringAppend(dst, "<error getting message>");
|
||||
// Clear OOME if present.
|
||||
env->ExceptionClear();
|
||||
}
|
||||
env->DeleteLocalRef(message);
|
||||
message = NULL;
|
||||
return success;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static jobject NewStringWriter(JNIEnv* env) {
|
||||
jclass clazz = env->FindClass("java/io/StringWriter");
|
||||
jmethodID init = env->GetMethodID(clazz, "<init>", "()V");
|
||||
jobject instance = env->NewObject(clazz, init);
|
||||
env->DeleteLocalRef(clazz);
|
||||
return instance;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static jstring StringWriterToString(JNIEnv* env, jobject stringWriter) {
|
||||
jmethodID toString =
|
||||
FindMethod(env, "java/io/StringWriter", "toString", "()Ljava/lang/String;");
|
||||
return (jstring)env->CallObjectMethod(stringWriter, toString);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static jobject NewPrintWriter(JNIEnv* env, jobject writer) {
|
||||
jclass clazz = env->FindClass("java/io/PrintWriter");
|
||||
jmethodID init = env->GetMethodID(clazz, "<init>", "(Ljava/io/Writer;)V");
|
||||
jobject instance = env->NewObject(clazz, init, writer);
|
||||
env->DeleteLocalRef(clazz);
|
||||
return instance;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static bool GetStackTrace(JNIEnv* env, jthrowable thrown,
|
||||
struct ExpandableString* dst) {
|
||||
// This function is equivalent to the following Java snippet:
|
||||
// StringWriter sw = new StringWriter();
|
||||
// PrintWriter pw = new PrintWriter(sw);
|
||||
// thrown.printStackTrace(pw);
|
||||
// String trace = sw.toString();
|
||||
// return trace;
|
||||
jobject sw = NewStringWriter(env);
|
||||
if (sw == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jobject pw = NewPrintWriter(env, sw);
|
||||
if (pw == NULL) {
|
||||
env->DeleteLocalRef(sw);
|
||||
return false;
|
||||
}
|
||||
|
||||
jmethodID printStackTrace =
|
||||
FindMethod(env, "java/lang/Throwable", "printStackTrace", "(Ljava/io/PrintWriter;)V");
|
||||
env->CallVoidMethod(thrown, printStackTrace, pw);
|
||||
|
||||
jstring trace = StringWriterToString(env, sw);
|
||||
|
||||
env->DeleteLocalRef(pw);
|
||||
pw = NULL;
|
||||
env->DeleteLocalRef(sw);
|
||||
sw = NULL;
|
||||
|
||||
if (trace == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = AppendJString(env, trace, dst);
|
||||
env->DeleteLocalRef(trace);
|
||||
return success;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static void GetStackTraceOrSummary(JNIEnv* env, jthrowable thrown,
|
||||
struct ExpandableString* dst) {
|
||||
// This method attempts to get a stack trace or summary info for an exception.
|
||||
// The exception may be provided in the |thrown| argument to this function.
|
||||
// If |thrown| is NULL, then any pending exception is used if it exists.
|
||||
|
||||
// Save pending exception, callees may raise other exceptions. Any pending exception is
|
||||
// rethrown when this function exits.
|
||||
jthrowable pendingException = env->ExceptionOccurred();
|
||||
if (pendingException != NULL) {
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
if (thrown == NULL) {
|
||||
if (pendingException == NULL) {
|
||||
ExpandableStringAssign(dst, "<no pending exception>");
|
||||
return;
|
||||
}
|
||||
thrown = pendingException;
|
||||
}
|
||||
|
||||
if (!GetStackTrace(env, thrown, dst)) {
|
||||
// GetStackTrace may have raised an exception, clear it since it's not for the caller.
|
||||
env->ExceptionClear();
|
||||
GetExceptionSummary(env, thrown, dst);
|
||||
}
|
||||
|
||||
if (pendingException != NULL) {
|
||||
// Re-throw the pending exception present when this method was called.
|
||||
env->Throw(pendingException);
|
||||
env->DeleteLocalRef(pendingException);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] static void DiscardPendingException(JNIEnv* env, const char* className) {
|
||||
jthrowable exception = env->ExceptionOccurred();
|
||||
env->ExceptionClear();
|
||||
if (exception == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct ExpandableString summary;
|
||||
ExpandableStringInitialize(&summary);
|
||||
GetExceptionSummary(env, exception, &summary);
|
||||
const char* details = (summary.data != NULL) ? summary.data : "Unknown";
|
||||
__android_log_print(ANDROID_LOG_WARN, "JNIHelp",
|
||||
"Discarding pending exception (%s) to throw %s", details, className);
|
||||
ExpandableStringRelease(&summary);
|
||||
env->DeleteLocalRef(exception);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static int ThrowException(JNIEnv* env, const char* className, const char* ctorSig,
|
||||
...) {
|
||||
int status = -1;
|
||||
jclass exceptionClass = NULL;
|
||||
|
||||
va_list args;
|
||||
va_start(args, ctorSig);
|
||||
|
||||
DiscardPendingException(env, className);
|
||||
|
||||
{
|
||||
/* We want to clean up local references before returning from this function, so,
|
||||
* regardless of return status, the end block must run. Have the work done in a
|
||||
* nested block to avoid using any uninitialized variables in the end block. */
|
||||
exceptionClass = env->FindClass(className);
|
||||
if (exceptionClass == NULL) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "JNIHelp", "Unable to find exception class %s",
|
||||
className);
|
||||
/* an exception, most likely ClassNotFoundException, will now be pending */
|
||||
goto end;
|
||||
}
|
||||
|
||||
jmethodID init = env->GetMethodID(exceptionClass, "<init>", ctorSig);
|
||||
if (init == NULL) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "JNIHelp",
|
||||
"Failed to find constructor for '%s' '%s'", className, ctorSig);
|
||||
goto end;
|
||||
}
|
||||
|
||||
jobject instance = env->NewObjectV(exceptionClass, init, args);
|
||||
if (instance == NULL) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "JNIHelp", "Failed to construct '%s'",
|
||||
className);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (env->Throw((jthrowable)instance) != JNI_OK) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "JNIHelp", "Failed to throw '%s'", className);
|
||||
/* an exception, most likely OOM, will now be pending */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* everything worked fine, just update status to success and clean up */
|
||||
status = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
va_end(args);
|
||||
if (exceptionClass != NULL) {
|
||||
env->DeleteLocalRef(exceptionClass);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static jstring CreateExceptionMsg(JNIEnv* env, const char* msg) {
|
||||
jstring detailMessage = env->NewStringUTF(msg);
|
||||
if (detailMessage == NULL) {
|
||||
/* Not really much we can do here. We're probably dead in the water,
|
||||
but let's try to stumble on... */
|
||||
env->ExceptionClear();
|
||||
}
|
||||
return detailMessage;
|
||||
}
|
||||
} // namespace android::jnihelp
|
||||
|
||||
/*
|
||||
* Register one or more native methods with a particular class. "className" looks like
|
||||
* "java/lang/String". Aborts on failure, returns 0 on success.
|
||||
*/
|
||||
[[maybe_unused]] static int jniRegisterNativeMethods(JNIEnv* env, const char* className,
|
||||
const JNINativeMethod* methods,
|
||||
int numMethods) {
|
||||
using namespace android::jnihelp;
|
||||
jclass clazz = env->FindClass(className);
|
||||
if (clazz == NULL) {
|
||||
__android_log_assert("clazz == NULL", "JNIHelp",
|
||||
"Native registration unable to find class '%s'; aborting...",
|
||||
className);
|
||||
}
|
||||
int result = env->RegisterNatives(clazz, methods, numMethods);
|
||||
env->DeleteLocalRef(clazz);
|
||||
if (result == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Failure to register natives is fatal. Try to report the corresponding exception,
|
||||
// otherwise abort with generic failure message.
|
||||
jthrowable thrown = env->ExceptionOccurred();
|
||||
if (thrown != NULL) {
|
||||
struct ExpandableString summary;
|
||||
ExpandableStringInitialize(&summary);
|
||||
if (GetExceptionSummary(env, thrown, &summary)) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, "JNIHelp", "%s", summary.data);
|
||||
}
|
||||
ExpandableStringRelease(&summary);
|
||||
env->DeleteLocalRef(thrown);
|
||||
}
|
||||
__android_log_print(ANDROID_LOG_FATAL, "JNIHelp",
|
||||
"RegisterNatives failed for '%s'; aborting...", className);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Throw an exception with the specified class and an optional message.
|
||||
*
|
||||
* The "className" argument will be passed directly to FindClass, which
|
||||
* takes strings with slashes (e.g. "java/lang/Object").
|
||||
*
|
||||
* If an exception is currently pending, we log a warning message and
|
||||
* clear it.
|
||||
*
|
||||
* Returns 0 on success, nonzero if something failed (e.g. the exception
|
||||
* class couldn't be found, so *an* exception will still be pending).
|
||||
*
|
||||
* Currently aborts the VM if it can't throw the exception.
|
||||
*/
|
||||
[[maybe_unused]] static int jniThrowException(JNIEnv* env, const char* className, const char* msg) {
|
||||
using namespace android::jnihelp;
|
||||
jstring _detailMessage = CreateExceptionMsg(env, msg);
|
||||
int _status = ThrowException(env, className, "(Ljava/lang/String;)V", _detailMessage);
|
||||
if (_detailMessage != NULL) {
|
||||
env->DeleteLocalRef(_detailMessage);
|
||||
}
|
||||
return _status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Throw an android.system.ErrnoException, with the given function name and errno value.
|
||||
*/
|
||||
[[maybe_unused]] static int jniThrowErrnoException(JNIEnv* env, const char* functionName,
|
||||
int errnum) {
|
||||
using namespace android::jnihelp;
|
||||
jstring _detailMessage = CreateExceptionMsg(env, functionName);
|
||||
int _status = ThrowException(env, "android/system/ErrnoException", "(Ljava/lang/String;I)V",
|
||||
_detailMessage, errnum);
|
||||
if (_detailMessage != NULL) {
|
||||
env->DeleteLocalRef(_detailMessage);
|
||||
}
|
||||
return _status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Throw an exception with the specified class and formatted error message.
|
||||
*
|
||||
* The "className" argument will be passed directly to FindClass, which
|
||||
* takes strings with slashes (e.g. "java/lang/Object").
|
||||
*
|
||||
* If an exception is currently pending, we log a warning message and
|
||||
* clear it.
|
||||
*
|
||||
* Returns 0 on success, nonzero if something failed (e.g. the exception
|
||||
* class couldn't be found, so *an* exception will still be pending).
|
||||
*
|
||||
* Currently aborts the VM if it can't throw the exception.
|
||||
*/
|
||||
[[maybe_unused]] static int jniThrowExceptionFmt(JNIEnv* env, const char* className,
|
||||
const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char msgBuf[512];
|
||||
vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
|
||||
va_end(args);
|
||||
return jniThrowException(env, className, msgBuf);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
|
||||
return jniThrowException(env, "java/lang/NullPointerException", msg);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
|
||||
return jniThrowException(env, "java/lang/RuntimeException", msg);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static int jniThrowIOException(JNIEnv* env, int errno_value) {
|
||||
using namespace android::jnihelp;
|
||||
char buffer[80];
|
||||
const char* message = platformStrError(errno_value, buffer, sizeof(buffer));
|
||||
return jniThrowException(env, "java/io/IOException", message);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a Java String object created from UTF-16 data either from jchar or,
|
||||
* if called from C++11, char16_t (a bitwise identical distinct type).
|
||||
*/
|
||||
[[maybe_unused]] static inline jstring jniCreateString(JNIEnv* env, const jchar* unicodeChars,
|
||||
jsize len) {
|
||||
return env->NewString(unicodeChars, len);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static inline jstring jniCreateString(JNIEnv* env, const char16_t* unicodeChars,
|
||||
jsize len) {
|
||||
return jniCreateString(env, reinterpret_cast<const jchar*>(unicodeChars), len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log a message and an exception.
|
||||
* If exception is NULL, logs the current exception in the JNI environment.
|
||||
*/
|
||||
[[maybe_unused]] static void jniLogException(JNIEnv* env, int priority, const char* tag,
|
||||
jthrowable exception = NULL) {
|
||||
using namespace android::jnihelp;
|
||||
struct ExpandableString summary;
|
||||
ExpandableStringInitialize(&summary);
|
||||
GetStackTraceOrSummary(env, exception, &summary);
|
||||
const char* details = (summary.data != NULL) ? summary.data : "No memory to report exception";
|
||||
__android_log_write(priority, tag, details);
|
||||
ExpandableStringRelease(&summary);
|
||||
}
|
||||
|
||||
#else // defined(__cplusplus)
|
||||
|
||||
// ART-internal only methods (not exported), exposed for legacy C users
|
||||
|
||||
int jniRegisterNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods,
|
||||
int numMethods);
|
||||
|
||||
void jniLogException(JNIEnv* env, int priority, const char* tag, jthrowable thrown);
|
||||
|
||||
int jniThrowException(JNIEnv* env, const char* className, const char* msg);
|
||||
|
||||
int jniThrowNullPointerException(JNIEnv* env, const char* msg);
|
||||
|
||||
#endif // defined(__cplusplus)
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nativehelper/scoped_local_frame.h>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JNIHelp.h"
|
||||
#include <nativehelper/scoped_local_ref.h>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JNIHelp.h"
|
||||
#include <nativehelper/scoped_primitive_array.h>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JNIHelp.h"
|
||||
#include <nativehelper/scoped_string_chars.h>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JNIHelp.h"
|
||||
#include <nativehelper/scoped_utf_chars.h>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "JNIHelp.h"
|
||||
#include "ScopedLocalRef.h"
|
||||
|
||||
template <typename StringVisitor>
|
||||
jobjectArray toStringArray(JNIEnv* env, size_t count, StringVisitor&& visitor) {
|
||||
jclass stringClass = env->FindClass("java/lang/String");
|
||||
ScopedLocalRef<jobjectArray> result(env, env->NewObjectArray(count, stringClass, NULL));
|
||||
env->DeleteLocalRef(stringClass);
|
||||
if (result == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
ScopedLocalRef<jstring> s(env, env->NewStringUTF(visitor(i)));
|
||||
if (env->ExceptionCheck()) {
|
||||
return nullptr;
|
||||
}
|
||||
env->SetObjectArrayElement(result.get(), i, s.get());
|
||||
if (env->ExceptionCheck()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return result.release();
|
||||
}
|
||||
|
||||
inline jobjectArray toStringArray(JNIEnv* env, const std::vector<std::string>& strings) {
|
||||
return toStringArray(env, strings.size(), [&strings](size_t i) { return strings[i].c_str(); });
|
||||
}
|
||||
|
||||
inline jobjectArray toStringArray(JNIEnv* env, const char* const* strings) {
|
||||
size_t count = 0;
|
||||
for (; strings[count] != nullptr; ++count) {}
|
||||
return toStringArray(env, count, [&strings](size_t i) { return strings[i]; });
|
||||
}
|
||||
|
||||
template <typename Counter, typename Getter>
|
||||
jobjectArray toStringArray(JNIEnv* env, Counter* counter, Getter* getter) {
|
||||
return toStringArray(env, counter(), [getter](size_t i) { return getter(i); });
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (C) 2007 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* JNI helper functions.
|
||||
*
|
||||
* This file may be included by C or C++ code, which is trouble because jni.h
|
||||
* uses different typedefs for JNIEnv in each language.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Gets the managed heap array backing a java.nio.Buffer instance.
|
||||
*
|
||||
* Returns nullptr if there is no array backing.
|
||||
*
|
||||
* This method performs a JNI call to java.nio.NIOAccess.getBaseArray().
|
||||
*/
|
||||
jarray jniGetNioBufferBaseArray(C_JNIEnv* env, jobject nioBuffer);
|
||||
|
||||
/*
|
||||
* Gets the offset of the current buffer position in bytes from the start of the managed heap
|
||||
* array backing the buffer.
|
||||
*
|
||||
* Returns 0 if there is no array backing.
|
||||
*
|
||||
* This method performs a JNI call to java.nio.NIOAccess.getBaseArrayOffset().
|
||||
*/
|
||||
jint jniGetNioBufferBaseArrayOffset(C_JNIEnv* env, jobject nioBuffer);
|
||||
|
||||
/*
|
||||
* Gets field information from a java.nio.Buffer instance.
|
||||
*
|
||||
* Reads the |position|, |limit|, and |elementSizeShift| fields from the buffer instance.
|
||||
*
|
||||
* Returns the |address| field of the java.nio.Buffer instance which is only valid (non-zero) when
|
||||
* the buffer is backed by a direct buffer.
|
||||
*/
|
||||
jlong jniGetNioBufferFields(C_JNIEnv* env,
|
||||
jobject nioBuffer,
|
||||
/*out*/jint* position,
|
||||
/*out*/jint* limit,
|
||||
/*out*/jint* elementSizeShift);
|
||||
|
||||
/*
|
||||
* Gets the current position from a java.nio.Buffer as a pointer to memory in a fixed buffer.
|
||||
*
|
||||
* Returns 0 if |nioBuffer| is not backed by a direct buffer.
|
||||
*
|
||||
* This method reads the |address|, |position|, and |elementSizeShift| fields from the
|
||||
* java.nio.Buffer instance to calculate the pointer address for the current position.
|
||||
*/
|
||||
jlong jniGetNioBufferPointer(C_JNIEnv* env, jobject nioBuffer);
|
||||
|
||||
/*
|
||||
* Clear the cache of constants libnativehelper is using.
|
||||
*/
|
||||
void jniUninitializeConstants();
|
||||
|
||||
__END_DECLS
|
||||
|
||||
/*
|
||||
* For C++ code, we provide inlines that map to the C functions. g++ always
|
||||
* inlines these, even on non-optimized builds.
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#include <android/file_descriptor_jni.h>
|
||||
|
||||
inline jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
|
||||
jobject fileDescriptor = AFileDescriptor_create(env);
|
||||
if (fileDescriptor != nullptr) {
|
||||
AFileDescriptor_setFd(env, fileDescriptor, fd);
|
||||
}
|
||||
return fileDescriptor;
|
||||
}
|
||||
|
||||
inline int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
|
||||
if (fileDescriptor == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
return AFileDescriptor_getFd(env, fileDescriptor);
|
||||
}
|
||||
|
||||
inline void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor, int value) {
|
||||
if (fileDescriptor == nullptr) {
|
||||
jniThrowNullPointerException(env, "fileDescriptor is null");
|
||||
return;
|
||||
}
|
||||
AFileDescriptor_setFd(env, fileDescriptor, value);
|
||||
}
|
||||
|
||||
inline jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
|
||||
return jniGetNioBufferBaseArray(&env->functions, nioBuffer);
|
||||
}
|
||||
|
||||
inline jint jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
|
||||
return jniGetNioBufferBaseArrayOffset(&env->functions, nioBuffer);
|
||||
}
|
||||
|
||||
inline jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
|
||||
jint* position, jint* limit, jint* elementSizeShift) {
|
||||
return jniGetNioBufferFields(&env->functions, nioBuffer,
|
||||
position, limit, elementSizeShift);
|
||||
}
|
||||
|
||||
inline jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
|
||||
return jniGetNioBufferPointer(&env->functions, nioBuffer);
|
||||
}
|
||||
|
||||
#endif // defined(__cplusplus)
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (C) 2013 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* The JNI invocation API exists to allow a choice of library responsible for managing virtual
|
||||
* machines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Opaque structure used to hold JNI invocation internal state.
|
||||
*/
|
||||
struct JniInvocationImpl;
|
||||
|
||||
/*
|
||||
* Creates an instance of a JniInvocationImpl.
|
||||
*/
|
||||
struct JniInvocationImpl* JniInvocationCreate();
|
||||
|
||||
/*
|
||||
* Associates a library with a JniInvocationImpl instance. The library should export C symbols for
|
||||
* JNI_GetDefaultJavaVMInitArgs, JNI_CreateJavaVM and JNI_GetDefaultJavaVMInitArgs.
|
||||
*
|
||||
* The specified |library| should be the filename of a shared library. The |library| is opened with
|
||||
* dlopen(3).
|
||||
*
|
||||
* If there is an error opening the specified |library|, then function will fallback to the
|
||||
* default library "libart.so". If the fallback library is successfully used then a warning is
|
||||
* written to the Android log buffer. Use of the fallback library is not considered an error.
|
||||
*
|
||||
* If the fallback library cannot be opened or the expected symbols are not found in the library
|
||||
* opened, then an error message is written to the Android log buffer and the function returns 0.
|
||||
*
|
||||
* Returns true on success, false otherwise.
|
||||
*/
|
||||
bool JniInvocationInit(struct JniInvocationImpl* instance, const char* library);
|
||||
|
||||
/*
|
||||
* Release resources associated with JniInvocationImpl instance.
|
||||
*/
|
||||
void JniInvocationDestroy(struct JniInvocationImpl* instance);
|
||||
|
||||
/*
|
||||
* Gets the default library for JNI invocation. The default library is "libart.so". This value may
|
||||
* be overridden for debuggable builds using the persist.sys.dalvik.vm.lib.2 system property.
|
||||
*
|
||||
* The |library| argument is the preferred library to use on debuggable builds (when
|
||||
* ro.debuggable=1). If the |library| argument is nullptr, then the system preferred value will be
|
||||
* queried from persist.sys.dalvik.vm.lib.2 if the caller has provided |buffer| argument.
|
||||
*
|
||||
* The |buffer| argument is used for reading system properties in debuggable builds. It is
|
||||
* optional, but should be provisioned to be PROP_VALUE_MAX bytes if provided to ensure it is
|
||||
* large enough to hold a system property.
|
||||
*
|
||||
* Returns the filename of the invocation library determined from the inputs and system
|
||||
* properties. The returned value may be |library|, |buffer|, or a pointer to a string constant
|
||||
* "libart.so".
|
||||
*/
|
||||
const char* JniInvocationGetLibrary(const char* library, char* buffer);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// JniInvocation adds a layer of indirection for applications using
|
||||
// the JNI invocation API to allow the JNI implementation to be
|
||||
// selected dynamically. Apps can specify a specific implementation to
|
||||
// be used by calling InitJniInvocation. If this is not done, the
|
||||
// library will chosen based on the value of Android system property
|
||||
// persist.sys.dalvik.vm.lib on the device, and otherwise fall back to
|
||||
// a hard-coded default implementation.
|
||||
class JniInvocation final {
|
||||
public:
|
||||
JniInvocation() {
|
||||
impl_ = JniInvocationCreate();
|
||||
}
|
||||
|
||||
~JniInvocation() {
|
||||
JniInvocationDestroy(impl_);
|
||||
}
|
||||
|
||||
// Initialize JNI invocation API. library should specify a valid
|
||||
// shared library for opening via dlopen providing a JNI invocation
|
||||
// implementation, or null to allow defaulting via
|
||||
// persist.sys.dalvik.vm.lib.
|
||||
bool Init(const char* library) {
|
||||
return JniInvocationInit(impl_, library) != 0;
|
||||
}
|
||||
|
||||
// Exposes which library is actually loaded from the given name. The
|
||||
// buffer of size PROPERTY_VALUE_MAX will be used to load the system
|
||||
// property for the default library, if necessary. If no buffer is
|
||||
// provided, the fallback value will be used.
|
||||
static const char* GetLibrary(const char* library, char* buffer) {
|
||||
return JniInvocationGetLibrary(library, buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
JniInvocation(const JniInvocation&) = delete;
|
||||
JniInvocation& operator=(const JniInvocation&) = delete;
|
||||
|
||||
JniInvocationImpl* impl_;
|
||||
};
|
||||
|
||||
#endif // __cplusplus
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compile-time, zero-cost checking of JNI signatures against their C++ function type.
|
||||
* This can trigger compile-time assertions if any of the input is invalid:
|
||||
* (a) The signature specified does not conform to the JNI function descriptor syntax.
|
||||
* (b) The C++ function is itself an invalid JNI function (e.g. missing JNIEnv*, etc).
|
||||
* (c) The descriptor does not match the C++ function (e.g. "()V" will not match jint(jint)).
|
||||
*
|
||||
* The fundamental macros are as following:
|
||||
* MAKE_JNI_[FAST_|CRITICAL_]NATIVE_METHOD - Create a checked JNINativeMethod{name, sig, func}.
|
||||
* MAKE_JNI_[FAST_|CRITICAL_]NATIVE_METHOD_AUTOSIG - Same as above, but infer the JNI signature.
|
||||
*
|
||||
* Usage examples:
|
||||
* // path/to/package/KlassName.java
|
||||
* class KlassName {
|
||||
* native jobject normal(int x);
|
||||
* @FastNative native jobject fast(int x);
|
||||
* @CriticalNative native int critical(long ptr);
|
||||
* }
|
||||
* // path_to_package_KlassName.cpp
|
||||
* jobject KlassName_normal(JNIEnv*,jobject,jint) {...}
|
||||
* jobject KlassName_fast(JNIEnv*,jobject,jint) {...}
|
||||
* jint KlassName_critical(jlong) {...}
|
||||
*
|
||||
* // Manually specify each signature:
|
||||
* JNINativeMethod[] gMethods = {
|
||||
* MAKE_JNI_NATIVE_METHOD("normal", "(I)Ljava/lang/Object;", KlassName_normal),
|
||||
* MAKE_JNI_FAST_NATIVE_METHOD("fast", "(I)Ljava/lang/Object;", KlassName_fast),
|
||||
* MAKE_JNI_CRITICAL_NATIVE_METHOD("critical", "(Z)I", KlassName_critical),
|
||||
* };
|
||||
*
|
||||
* // Automatically infer the signature:
|
||||
* JNINativeMethod[] gMethodsAutomaticSignature = {
|
||||
* MAKE_JNI_NATIVE_METHOD_AUTOSIG("normal", KlassName_normal),
|
||||
* MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG("fast", KlassName_fast),
|
||||
* MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG("critical", KlassName_critical),
|
||||
* };
|
||||
*
|
||||
* // and then call JNIEnv::RegisterNatives with gMethods as usual.
|
||||
*
|
||||
* For convenience the following macros are defined:
|
||||
* [FAST_|CRITICAL_]NATIVE_METHOD - Return JNINativeMethod for class, func name, and signature.
|
||||
* OVERLOADED_[FAST_|CRITICAL_]NATIVE_METHOD - Same as above but allows a separate func identifier.
|
||||
* [FAST_|CRITICAL_]NATIVE_METHOD_AUTOSIG - Return JNINativeMethod, sig inferred from function.
|
||||
*
|
||||
* The FAST_ prefix corresponds to functions annotated with @FastNative,
|
||||
* and the CRITICAL_ prefix corresponds to functions annotated with @CriticalNative.
|
||||
* See dalvik.annotation.optimization.CriticalNative for more details.
|
||||
*
|
||||
* =======================================
|
||||
* Checking rules
|
||||
* =======================================
|
||||
*
|
||||
* ---------------------------------------
|
||||
* JNI descriptor syntax for functions
|
||||
*
|
||||
* Refer to "Chapter 3: JNI Types and Data Structures" of the JNI specification
|
||||
* under the subsection "Type Signatures" table entry "method type".
|
||||
*
|
||||
* JNI signatures not conforming to the above syntax are rejected.
|
||||
* ---------------------------------------
|
||||
* C++ function types
|
||||
*
|
||||
* A normal or @FastNative JNI function type must be of the form
|
||||
*
|
||||
* ReturnType (JNIEnv*, jclass|jobject, [ArgTypes...]) {}
|
||||
*
|
||||
* A @CriticalNative JNI function type:
|
||||
*
|
||||
* must be of the form... ReturnType ([ArgTypes...]){}
|
||||
* and must not contain any Reference Types.
|
||||
*
|
||||
* Refer to "Chapter 3: JNI Types and Data Structures" of the JNI specification
|
||||
* under the subsection "Primitive Types" and "Reference Types" for the list
|
||||
* of valid argument/return types.
|
||||
*
|
||||
* C++ function types not conforming to the above requirements are rejected.
|
||||
* ---------------------------------------
|
||||
* Matching of C++ function type against JNI function descriptor.
|
||||
*
|
||||
* Assuming all of the above conditions are met for signature and C++ type validity,
|
||||
* then matching between the signature and the type validity can occur:
|
||||
*
|
||||
* Given a signature (Args...)Ret and the
|
||||
* C++ function type of the form "CRet fn(JNIEnv*, jclass|jobject, CArgs...)",
|
||||
* or for @CriticalNative of the form "CRet fn(CArgs...)"
|
||||
*
|
||||
* The number of Args... and the number of CArgs... must be equal.
|
||||
*
|
||||
* If so, attempt to match every component from the signature and function type
|
||||
* against each other:
|
||||
*
|
||||
* ReturnType:
|
||||
* V <-> void
|
||||
* ArgumentType
|
||||
*
|
||||
* ArgumentType:
|
||||
* PrimitiveType
|
||||
* ReferenceType [except for @CriticalNative]
|
||||
*
|
||||
* PrimitiveType:
|
||||
* Z <-> jboolean
|
||||
* B <-> jbyte
|
||||
* C <-> jchar
|
||||
* S <-> jshort
|
||||
* I <-> jint
|
||||
* J <-> jlong
|
||||
* F <-> jfloat
|
||||
* D <-> jdouble
|
||||
*
|
||||
* ReferenceType:
|
||||
* Ljava/lang/String; <-> jstring
|
||||
* Ljava/lang/Class; <-> jclass
|
||||
* L*; <- jobject
|
||||
* Ljava/lang/Throwable; -> jthrowable
|
||||
* L*; <- jthrowable
|
||||
* [ PrimitiveType <-> ${CPrimitiveType}Array
|
||||
* [ ReferenceType <-> jobjectArray
|
||||
* [* <- jarray
|
||||
*
|
||||
* Wherein <-> represents a strong match (if the left or right pattern occurs,
|
||||
* then left must match right, otherwise matching fails). <- and -> represent
|
||||
* weak matches (that is, other match rules can be still attempted).
|
||||
*
|
||||
* Sidenote: Whilst a jobject could also represent a jclass, jstring, etc,
|
||||
* the stricter approach is taken: the most exact C++ type must be used.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// The below basic macros do not perform automatic stringification,
|
||||
// invoked e.g. as MAKE_JNI_NATIVE_METHOD("some_name", "()V", void_fn)
|
||||
|
||||
// An expression that evaluates to JNINativeMethod { name, signature, function },
|
||||
// and applies the above compile-time checking for signature+function.
|
||||
// The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative.
|
||||
#define MAKE_JNI_NATIVE_METHOD(name, signature, function) \
|
||||
_NATIVEHELPER_JNI_MAKE_METHOD(kNormalNative, name, signature, function)
|
||||
|
||||
// An expression that evaluates to JNINativeMethod { name, signature, function },
|
||||
// and applies the above compile-time checking for signature+function.
|
||||
// The equivalent Java Language code must be annotated with @FastNative.
|
||||
#define MAKE_JNI_FAST_NATIVE_METHOD(name, signature, function) \
|
||||
_NATIVEHELPER_JNI_MAKE_METHOD(kFastNative, name, signature, function)
|
||||
|
||||
// An expression that evaluates to JNINativeMethod { name, signature, function },
|
||||
// and applies the above compile-time checking for signature+function.
|
||||
// The equivalent Java Language code must be annotated with @CriticalNative.
|
||||
#define MAKE_JNI_CRITICAL_NATIVE_METHOD(name, signature, function) \
|
||||
_NATIVEHELPER_JNI_MAKE_METHOD(kCriticalNative, name, signature, function)
|
||||
|
||||
// Automatically signature-inferencing macros are also available,
|
||||
// which also checks the C++ function types for validity:
|
||||
|
||||
// An expression that evalutes to JNINativeMethod { name, infersig(function), function) }
|
||||
// by inferring the signature at compile-time. Only works when the C++ function type
|
||||
// corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???).
|
||||
//
|
||||
// The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative.
|
||||
#define MAKE_JNI_NATIVE_METHOD_AUTOSIG(name, function) \
|
||||
_NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kNormalNative, name, function)
|
||||
|
||||
// An expression that evalutes to JNINativeMethod { name, infersig(function), function) }
|
||||
// by inferring the signature at compile-time. Only works when the C++ function type
|
||||
// corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???).
|
||||
//
|
||||
// The equivalent Java Language code must be annotated with @FastNative.
|
||||
#define MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(name, function) \
|
||||
_NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kFastNative, name, function)
|
||||
|
||||
// An expression that evalutes to JNINativeMethod { name, infersig(function), function) }
|
||||
// by inferring the signature at compile-time.
|
||||
//
|
||||
// The equivalent Java Language code must be annotated with @CriticalNative.
|
||||
#define MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(name, function) \
|
||||
_NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kCriticalNative, name, function)
|
||||
|
||||
// Convenience macros when the functions follow the naming convention:
|
||||
// .java file .cpp file
|
||||
// JavaLanguageName <-> ${ClassName}_${JavaLanguageName}
|
||||
//
|
||||
// Stringification is done automatically, invoked as:
|
||||
// NATIVE_[FAST_|CRITICAL]_METHOD(ClassName, JavaLanguageName, Signature)
|
||||
//
|
||||
// Intended to construct a JNINativeMethod.
|
||||
// (Assumes the C name is the ClassName_JavaMethodName).
|
||||
//
|
||||
// The Java Language code must be annotated with one of (none,@FastNative,@CriticalNative)
|
||||
// for the (none,FAST_,CRITICAL_) variants of these macros.
|
||||
|
||||
#define NATIVE_METHOD(className, functionName, signature) \
|
||||
MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName)
|
||||
|
||||
#define OVERLOADED_NATIVE_METHOD(className, functionName, signature, identifier) \
|
||||
MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier)
|
||||
|
||||
#define NATIVE_METHOD_AUTOSIG(className, functionName) \
|
||||
MAKE_JNI_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName)
|
||||
|
||||
#define FAST_NATIVE_METHOD(className, functionName, signature) \
|
||||
MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName)
|
||||
|
||||
#define OVERLOADED_FAST_NATIVE_METHOD(className, functionName, signature, identifier) \
|
||||
MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier)
|
||||
|
||||
#define FAST_NATIVE_METHOD_AUTOSIG(className, functionName) \
|
||||
MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName)
|
||||
|
||||
#define CRITICAL_NATIVE_METHOD(className, functionName, signature) \
|
||||
MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName)
|
||||
|
||||
#define OVERLOADED_CRITICAL_NATIVE_METHOD(className, functionName, signature, identifier) \
|
||||
MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier)
|
||||
|
||||
#define CRITICAL_NATIVE_METHOD_AUTOSIG(className, functionName) \
|
||||
MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName)
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// IMPLEMENTATION ONLY.
|
||||
// DO NOT USE DIRECTLY.
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus >= 201402L
|
||||
#include "nativehelper/detail/signature_checker.h" // for MAKE_CHECKED_JNI_NATIVE_METHOD
|
||||
#endif
|
||||
|
||||
// Expands to an expression whose type is JNINativeMethod.
|
||||
// This is for older versions of C++ or C, so it has no compile-time checking.
|
||||
#define _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn) \
|
||||
( \
|
||||
(JNINativeMethod) { \
|
||||
(name), \
|
||||
(sig), \
|
||||
_NATIVEHELPER_JNI_MACRO_CAST(reinterpret_cast, void *)(fn) \
|
||||
} \
|
||||
)
|
||||
|
||||
// C++14 or better, use compile-time checking.
|
||||
#if defined(__cplusplus) && __cplusplus >= 201402L
|
||||
// Expands to a compound expression whose type is JNINativeMethod.
|
||||
#define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \
|
||||
MAKE_CHECKED_JNI_NATIVE_METHOD(kind, name, sig, fn)
|
||||
|
||||
// Expands to a compound expression whose type is JNINativeMethod.
|
||||
#define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \
|
||||
MAKE_INFERRED_JNI_NATIVE_METHOD(kind, name, function)
|
||||
|
||||
#else
|
||||
// Older versions of C++ or C code get the regular macro that's unchecked.
|
||||
// Expands to a compound expression whose type is JNINativeMethod.
|
||||
#define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \
|
||||
_NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn)
|
||||
|
||||
// Need C++14 or newer to use the AUTOSIG macros.
|
||||
#define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \
|
||||
static_assert(false, "Cannot infer JNI signatures prior to C++14 for function " #function);
|
||||
|
||||
#endif // C++14 check
|
||||
|
||||
// C-style cast for C, C++-style cast for C++ to avoid warnings/errors.
|
||||
#if defined(__cplusplus)
|
||||
#define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \
|
||||
which_cast<to>
|
||||
#else
|
||||
#define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \
|
||||
(to)
|
||||
#endif
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
LIBNATIVEHELPER_S { # introduced=S
|
||||
global:
|
||||
# NDK API for libnativehelper.
|
||||
AFileDescriptor_create;
|
||||
AFileDescriptor_getFd;
|
||||
AFileDescriptor_setFd;
|
||||
|
||||
# JNI Invocation methods available to platform and apps.
|
||||
JNI_CreateJavaVM;
|
||||
JNI_GetDefaultJavaVMInitArgs;
|
||||
JNI_GetCreatedJavaVMs;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
LIBNATIVEHELPER_PLATFORM { # platform-only
|
||||
global:
|
||||
JniInvocationCreate;
|
||||
JniInvocationDestroy;
|
||||
JniInvocationInit;
|
||||
JniInvocationGetLibrary;
|
||||
|
||||
jniGetNioBufferBaseArray;
|
||||
jniGetNioBufferBaseArrayOffset;
|
||||
jniGetNioBufferPointer;
|
||||
jniGetNioBufferFields;
|
||||
|
||||
jniUninitializeConstants;
|
||||
};
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 "libnativehelper_lazy.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "log/log.h"
|
||||
|
||||
#include "android/file_descriptor_jni.h"
|
||||
#include "nativehelper/JNIHelp.h"
|
||||
#include "nativehelper/JNIPlatformHelp.h"
|
||||
#include "nativehelper/JniInvocation.h"
|
||||
|
||||
// This file provides a lazy interface to libnativehelper.so to address early boot dependencies.
|
||||
// Specifically bootanimation now runs before the ART APEX is loaded and libnativehelper.so is
|
||||
// in the ART APEX. bootanimation does not call any code in libnativehelper.
|
||||
|
||||
// Method pointers to libnativehelper methods are held in array which simplifies checking
|
||||
// all pointers are initialized.
|
||||
enum MethodIndex {
|
||||
// NDK file descriptor API in file_descriptor_jni.h.
|
||||
k_AFileDescriptor_create,
|
||||
k_AFileDescriptor_getFd,
|
||||
k_AFileDescriptor_setFd,
|
||||
|
||||
// JNI_Invocation API declared in jni.h.
|
||||
k_JNI_CreateJavaVM,
|
||||
k_JNI_GetCreatedJavaVMs,
|
||||
k_JNI_GetDefaultJavaVMInitArgs,
|
||||
|
||||
// Methods in JNIPlatformHelp.h.
|
||||
k_jniGetNioBufferBaseArray,
|
||||
k_jniGetNioBufferBaseArrayOffset,
|
||||
k_jniGetNioBufferFields,
|
||||
k_jniGetNioBufferPointer,
|
||||
k_jniUninitializeConstants,
|
||||
|
||||
// Methods in JniInvocation.h.
|
||||
k_JniInvocationCreate,
|
||||
k_JniInvocationDestroy,
|
||||
k_JniInvocationGetLibrary,
|
||||
k_JniInvocationInit,
|
||||
|
||||
// Marker for count of methods
|
||||
k_MethodCount
|
||||
};
|
||||
|
||||
// Table of methods pointers in libnativehelper APIs.
|
||||
static void* g_Methods[k_MethodCount];
|
||||
|
||||
//
|
||||
// Libnativehelper lazy loading.
|
||||
//
|
||||
|
||||
static atomic_bool gPreventLibnativehelperLoading = false; // Allows tests to block loading.
|
||||
|
||||
void PreventLibnativehelperLazyLoadingForTests() {
|
||||
atomic_store_explicit(&gPreventLibnativehelperLoading, true, memory_order_release);
|
||||
}
|
||||
|
||||
static void* LoadLibnativehelper(int dlopen_flags) {
|
||||
if (atomic_load_explicit(&gPreventLibnativehelperLoading, memory_order_acquire)) {
|
||||
return NULL;
|
||||
}
|
||||
return dlopen("libnativehelper.so", dlopen_flags);
|
||||
}
|
||||
|
||||
static bool IsLibnativehelperLoaded() {
|
||||
return LoadLibnativehelper(RTLD_NOLOAD) != NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialization and symbol binding.
|
||||
//
|
||||
|
||||
static void BindSymbol(void* handle, const char* name, enum MethodIndex index) {
|
||||
void* symbol = dlsym(handle, name);
|
||||
LOG_ALWAYS_FATAL_IF(symbol == NULL,
|
||||
"Failed to find symbol '%s' in libnativehelper.so: %s", name, dlerror());
|
||||
g_Methods[index] = symbol;
|
||||
}
|
||||
|
||||
static void InitializeOnce() {
|
||||
void* handle = LoadLibnativehelper(RTLD_NOW);
|
||||
LOG_ALWAYS_FATAL_IF(handle == NULL, "Failed to load libnativehelper.so: %s", dlerror());
|
||||
|
||||
#undef BIND_SYMBOL
|
||||
#define BIND_SYMBOL(name) BindSymbol(handle, #name, k_ ## name);
|
||||
|
||||
// NDK file descriptor API in file_descriptor_jni.h.
|
||||
BIND_SYMBOL(AFileDescriptor_create);
|
||||
BIND_SYMBOL(AFileDescriptor_getFd);
|
||||
BIND_SYMBOL(AFileDescriptor_setFd);
|
||||
|
||||
// JNI_Invocation API declared in jni.h.
|
||||
BIND_SYMBOL(JNI_CreateJavaVM);
|
||||
BIND_SYMBOL(JNI_GetCreatedJavaVMs);
|
||||
BIND_SYMBOL(JNI_GetDefaultJavaVMInitArgs);
|
||||
|
||||
// Methods in JNIPlatformHelp.h.
|
||||
BIND_SYMBOL(jniGetNioBufferBaseArray);
|
||||
BIND_SYMBOL(jniGetNioBufferBaseArrayOffset);
|
||||
BIND_SYMBOL(jniGetNioBufferFields);
|
||||
BIND_SYMBOL(jniGetNioBufferPointer);
|
||||
BIND_SYMBOL(jniUninitializeConstants);
|
||||
|
||||
// Methods in JniInvocation.h.
|
||||
BIND_SYMBOL(JniInvocationCreate);
|
||||
BIND_SYMBOL(JniInvocationDestroy);
|
||||
BIND_SYMBOL(JniInvocationGetLibrary);
|
||||
BIND_SYMBOL(JniInvocationInit);
|
||||
|
||||
#undef BIND_SYMBOL
|
||||
|
||||
// Check every symbol is bound.
|
||||
for (int i = 0; i < k_MethodCount; ++i) {
|
||||
LOG_ALWAYS_FATAL_IF(g_Methods[i] == NULL,
|
||||
"Uninitialized method in libnativehelper_lazy at index: %d", i);
|
||||
}
|
||||
}
|
||||
|
||||
static void EnsureInitialized() {
|
||||
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
|
||||
pthread_once(&initialized, InitializeOnce);
|
||||
}
|
||||
|
||||
#define INVOKE_METHOD(name, method_type, args...) \
|
||||
do { \
|
||||
EnsureInitialized(); \
|
||||
void* method = g_Methods[k_ ## name]; \
|
||||
return ((method_type) method)(args); \
|
||||
} while (0)
|
||||
|
||||
#define INVOKE_VOID_METHOD(name, method_type, args...) \
|
||||
do { \
|
||||
EnsureInitialized(); \
|
||||
void* method = g_Methods[k_ ## name]; \
|
||||
((method_type) method)(args); \
|
||||
} while (0)
|
||||
|
||||
//
|
||||
// Forwarding for methods in file_descriptor_jni.h.
|
||||
//
|
||||
|
||||
jobject AFileDescriptor_create(JNIEnv* env) {
|
||||
typedef jobject (*M)(JNIEnv*);
|
||||
INVOKE_METHOD(AFileDescriptor_create, M, env);
|
||||
}
|
||||
|
||||
int AFileDescriptor_getFd(JNIEnv* env, jobject fileDescriptor) {
|
||||
typedef int (*M)(JNIEnv*, jobject);
|
||||
INVOKE_METHOD(AFileDescriptor_getFd, M, env, fileDescriptor);
|
||||
}
|
||||
|
||||
void AFileDescriptor_setFd(JNIEnv* env, jobject fileDescriptor, int fd) {
|
||||
typedef void (*M)(JNIEnv*, jobject, int);
|
||||
INVOKE_VOID_METHOD(AFileDescriptor_setFd, M, env, fileDescriptor, fd);
|
||||
}
|
||||
|
||||
//
|
||||
// Forwarding for the JNI_Invocation API declarded in jni.h.
|
||||
//
|
||||
|
||||
// Some code may attempt to use this JNI_Invocation API to establish if there is a VM (b/174768641).
|
||||
// Because INVOKE_METHOD produces a fatal error if used before libnativehelper.so, we need some
|
||||
// additional logic for the JNI_Invocation API to allow JNI_GetCreatedJavaVMs to be called even
|
||||
// if libnativehelper.so is not loaded.
|
||||
//
|
||||
// Consequently, we use an atomic variable if a VM is created through this API. But note
|
||||
// this is not the only way a JavaVM may be created so checking this flag alone is not enough.
|
||||
static atomic_bool gJavaVmCreatedLazily = false;
|
||||
|
||||
static jint JNI_CreateJavaVMImpl(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
|
||||
typedef jint (*M)(JavaVM**, JNIEnv**, void*);
|
||||
INVOKE_METHOD(JNI_CreateJavaVM, M, p_vm, p_env, vm_args);
|
||||
}
|
||||
|
||||
jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
|
||||
jint status = JNI_CreateJavaVMImpl(p_vm, p_env, vm_args);
|
||||
if (status == JNI_OK) {
|
||||
atomic_store_explicit(&gJavaVmCreatedLazily, true, memory_order_release);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
|
||||
typedef jint (*M)(void*);
|
||||
INVOKE_METHOD(JNI_GetDefaultJavaVMInitArgs, M, vm_args);
|
||||
}
|
||||
|
||||
jint JNI_GetCreatedJavaVMs(JavaVM** p_vm, jsize vm_max, jsize* p_vm_count) {
|
||||
typedef jint (*M)(JavaVM**, jsize, jsize*);
|
||||
// If no VMs have been created created lazily and libnativehelper.so has not been loaded
|
||||
// by other means, then fill-in the VM count as zero and return JNI_OK.
|
||||
if (!atomic_load_explicit(&gJavaVmCreatedLazily, memory_order_acquire) &&
|
||||
!IsLibnativehelperLoaded()) {
|
||||
*p_vm_count = 0;
|
||||
return JNI_OK;
|
||||
}
|
||||
INVOKE_METHOD(JNI_GetCreatedJavaVMs, M, p_vm, vm_max, p_vm_count);
|
||||
}
|
||||
|
||||
//
|
||||
// Forwarding for methods in JNIPlatformHelp.h.
|
||||
//
|
||||
|
||||
jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
|
||||
typedef jarray (*M)(JNIEnv*, jobject);
|
||||
INVOKE_METHOD(jniGetNioBufferBaseArray, M, env, nioBuffer);
|
||||
}
|
||||
|
||||
int jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
|
||||
typedef int (*M)(JNIEnv*, jobject);
|
||||
INVOKE_METHOD(jniGetNioBufferBaseArrayOffset, M, env, nioBuffer);
|
||||
}
|
||||
|
||||
jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
|
||||
jint* position, jint* limit, jint* elementSizeShift) {
|
||||
typedef jlong (*M)(JNIEnv*, jobject, jint*, jint*, jint*);
|
||||
INVOKE_METHOD(jniGetNioBufferFields, M, env, nioBuffer, position, limit,
|
||||
elementSizeShift);
|
||||
}
|
||||
|
||||
jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
|
||||
typedef jlong (*M)(JNIEnv*, jobject);
|
||||
INVOKE_METHOD(jniGetNioBufferPointer, M, env, nioBuffer);
|
||||
}
|
||||
|
||||
void jniUninitializeConstants() {
|
||||
typedef void (*M)();
|
||||
INVOKE_VOID_METHOD(jniUninitializeConstants, M);
|
||||
}
|
||||
|
||||
//
|
||||
// Forwarding for methods in JniInvocation.h.
|
||||
//
|
||||
|
||||
struct JniInvocationImpl* JniInvocationCreate() {
|
||||
typedef struct JniInvocationImpl* (*M)();
|
||||
INVOKE_METHOD(JniInvocationCreate, M);
|
||||
}
|
||||
|
||||
void JniInvocationDestroy(struct JniInvocationImpl* instance) {
|
||||
typedef void (*M)(struct JniInvocationImpl*);
|
||||
INVOKE_METHOD(JniInvocationDestroy, M, instance);
|
||||
}
|
||||
|
||||
bool JniInvocationInit(struct JniInvocationImpl* instance, const char* library) {
|
||||
typedef bool (*M)(struct JniInvocationImpl*, const char*);
|
||||
INVOKE_METHOD(JniInvocationInit, M, instance, library);
|
||||
}
|
||||
|
||||
const char* JniInvocationGetLibrary(const char* library, char* buffer) {
|
||||
typedef const char* (*M)(const char*, char*);
|
||||
INVOKE_METHOD(JniInvocationGetLibrary, M, library, buffer);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
void PreventLibnativehelperLazyLoadingForTests();
|
||||
|
||||
__END_DECLS
|
|
@ -0,0 +1,103 @@
|
|||
// Build the unit tests.
|
||||
|
||||
package {
|
||||
// http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// the below license kinds from "libnativehelper_license":
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["libnativehelper_license"],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "libnativehelper_test_defaults",
|
||||
cflags: [
|
||||
// Base set of cflags used by all things ART.
|
||||
"-fno-rtti",
|
||||
"-ggdb3",
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-Wextra",
|
||||
"-Wstrict-aliasing",
|
||||
"-fstrict-aliasing",
|
||||
"-Wunreachable-code",
|
||||
"-Wredundant-decls",
|
||||
"-Wshadow",
|
||||
"-Wunused",
|
||||
"-fvisibility=protected",
|
||||
|
||||
// Warn about thread safety violations with clang.
|
||||
"-Wthread-safety",
|
||||
"-Wthread-safety-negative",
|
||||
|
||||
// Warn if switch fallthroughs aren't annotated.
|
||||
"-Wimplicit-fallthrough",
|
||||
|
||||
// Enable float equality warnings.
|
||||
"-Wfloat-equal",
|
||||
|
||||
// Enable warning of converting ints to void*.
|
||||
"-Wint-to-void-pointer-cast",
|
||||
|
||||
// Enable warning for deprecated language features.
|
||||
"-Wdeprecated",
|
||||
|
||||
// Disable warning from external/libcxxabi/include/cxxabi.h
|
||||
"-Wno-deprecated-dynamic-exception-spec",
|
||||
|
||||
// Enable warning for unreachable break & return.
|
||||
"-Wunreachable-code-break",
|
||||
"-Wunreachable-code-return",
|
||||
|
||||
// Enable thread annotations for std::mutex, etc.
|
||||
"-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
|
||||
],
|
||||
host_supported: true,
|
||||
test_options: {
|
||||
unit_test: true,
|
||||
},
|
||||
tidy: true,
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "libnativehelper_tests",
|
||||
defaults: ["libnativehelper_test_defaults"],
|
||||
test_suites: ["general-tests"],
|
||||
srcs: [
|
||||
"scoped_local_frame_test.cpp",
|
||||
"scoped_local_ref_test.cpp",
|
||||
"scoped_primitive_array_test.cpp",
|
||||
"libnativehelper_api_test.c",
|
||||
"JniSafeRegisterNativeMethods_test.cpp",
|
||||
],
|
||||
shared_libs: ["libnativehelper"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "libnativehelper_lazy_tests",
|
||||
defaults: ["libnativehelper_test_defaults"],
|
||||
test_suites: ["general-tests"],
|
||||
srcs: ["libnativehelper_lazy_test.cpp"],
|
||||
shared_libs: ["liblog"],
|
||||
static_libs: ["libnativehelper_lazy"],
|
||||
}
|
||||
|
||||
// Tests for internal functions that aren't present in the APEX stub API. Use
|
||||
// `bootstrap:true` to bypass the stub library. This test won't link when
|
||||
// prebuilts are preferred, because we cannot link against the source variant
|
||||
// then.
|
||||
// TODO(b/180107266): Enable in TEST_MAPPING. Also use a better way than
|
||||
// `bootstrap:true` - `test_for` ought to work but fails because the test is
|
||||
// host enabled so host variants of the APEXes are expected.
|
||||
cc_test {
|
||||
name: "libnativehelper_internal_tests",
|
||||
defaults: [
|
||||
"art_module_source_build_defaults",
|
||||
"libnativehelper_test_defaults",
|
||||
],
|
||||
srcs: [
|
||||
"ExpandableString_test.cpp",
|
||||
"JniInvocation_test.cpp",
|
||||
],
|
||||
bootstrap: true,
|
||||
shared_libs: ["libnativehelper"],
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <array>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../ExpandableString.h"
|
||||
|
||||
|
||||
TEST(ExpandableString, InitializeAppendRelease) {
|
||||
const char* kAhoy = "Ahoy!";
|
||||
struct ExpandableString s;
|
||||
ExpandableStringInitialize(&s);
|
||||
EXPECT_TRUE(s.data == NULL);
|
||||
EXPECT_EQ(s.dataSize, 0u);
|
||||
EXPECT_TRUE(ExpandableStringAppend(&s, kAhoy));
|
||||
EXPECT_TRUE(s.data != NULL);
|
||||
EXPECT_GE(s.dataSize, strlen(kAhoy));
|
||||
ExpandableStringRelease(&s);
|
||||
EXPECT_TRUE(s.data == NULL);
|
||||
EXPECT_GE(s.dataSize, 0u);
|
||||
}
|
||||
|
||||
TEST(ExpandableString, InitializeWriteRelease) {
|
||||
const char* kAhoy = "Ahoy!";
|
||||
const char* kMercy = "Mercy, Mercy, Mercy!";
|
||||
|
||||
struct ExpandableString s;
|
||||
ExpandableStringInitialize(&s);
|
||||
EXPECT_TRUE(s.data == NULL);
|
||||
EXPECT_EQ(s.dataSize, 0u);
|
||||
EXPECT_TRUE(ExpandableStringAssign(&s, kAhoy));
|
||||
EXPECT_TRUE(s.data != NULL);
|
||||
EXPECT_GE(s.dataSize, strlen(kAhoy));
|
||||
EXPECT_TRUE(ExpandableStringAssign(&s, kMercy));
|
||||
EXPECT_TRUE(s.data != NULL);
|
||||
EXPECT_GE(s.dataSize, strlen(kMercy));
|
||||
EXPECT_TRUE(ExpandableStringAssign(&s, kAhoy));
|
||||
EXPECT_TRUE(s.data != NULL);
|
||||
EXPECT_GE(s.dataSize, strlen(kAhoy));
|
||||
ExpandableStringRelease(&s);
|
||||
EXPECT_TRUE(s.data == NULL);
|
||||
EXPECT_GE(s.dataSize, 0u);
|
||||
}
|
||||
|
||||
class ExpandableStringTestFixture : public :: testing::TestWithParam<size_t> {
|
||||
protected:
|
||||
struct ExpandableString expandableString;
|
||||
};
|
||||
|
||||
TEST_P(ExpandableStringTestFixture, AppendTest) {
|
||||
size_t step = GetParam();
|
||||
|
||||
std::array<std::string, 3> inputs = {
|
||||
std::string(step, 'a'),
|
||||
std::string(step, 'b'),
|
||||
std::string(step, 'c'),
|
||||
};
|
||||
|
||||
for (size_t offset = 0; offset < step; ++offset) {
|
||||
ExpandableStringInitialize(&expandableString);
|
||||
|
||||
std::string pad(step - 1u, '_');
|
||||
EXPECT_TRUE(ExpandableStringAppend(&expandableString, pad.c_str()));
|
||||
|
||||
for (size_t i = 0; i < 4096u; ++i) {
|
||||
const std::string& appendee = inputs[i % inputs.size()];
|
||||
EXPECT_TRUE(ExpandableStringAppend(&expandableString, appendee.c_str()));
|
||||
size_t requiredSize = pad.size() + i * step + 1u;
|
||||
EXPECT_GE(expandableString.dataSize, requiredSize);
|
||||
}
|
||||
|
||||
size_t position = 0u;
|
||||
for (char c : pad) {
|
||||
EXPECT_EQ(c, expandableString.data[position]);
|
||||
position++;
|
||||
}
|
||||
for (size_t i = 0; i < 4096; ++i) {
|
||||
const std::string& expected = inputs[i % inputs.size()];
|
||||
EXPECT_EQ(0, strncmp(expected.c_str(), expandableString.data + position, expected.size()));
|
||||
position += expected.size();
|
||||
}
|
||||
|
||||
ExpandableStringRelease(&expandableString);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AppendTest,
|
||||
ExpandableStringTestFixture,
|
||||
::testing::Values(
|
||||
1, 2, 3, 4, 5, 11, 17
|
||||
));
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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 "../JniInvocation-priv.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <jni.h>
|
||||
|
||||
|
||||
static const char* kDefaultJniInvocationLibrary = "libart.so";
|
||||
static const char* kTestNonNull = "libartd.so";
|
||||
static const char* kTestNonNull2 = "libartd2.so";
|
||||
|
||||
TEST(JNIInvocation, Debuggable) {
|
||||
const char* result = JniInvocationGetLibraryWith(nullptr, true, kTestNonNull2);
|
||||
EXPECT_STREQ(result, kTestNonNull2);
|
||||
|
||||
result = JniInvocationGetLibraryWith(kTestNonNull, true, kTestNonNull2);
|
||||
EXPECT_STREQ(result, kTestNonNull);
|
||||
|
||||
result = JniInvocationGetLibraryWith(kTestNonNull, true, nullptr);
|
||||
EXPECT_STREQ(result, kTestNonNull);
|
||||
|
||||
result = JniInvocationGetLibraryWith(nullptr, true, nullptr);
|
||||
EXPECT_STREQ(result, kDefaultJniInvocationLibrary);
|
||||
}
|
||||
|
||||
TEST(JNIInvocation, NonDebuggable) {
|
||||
const char* result = JniInvocationGetLibraryWith(nullptr, false, kTestNonNull2);
|
||||
EXPECT_STREQ(result, kDefaultJniInvocationLibrary);
|
||||
|
||||
result = JniInvocationGetLibraryWith(kTestNonNull, false, kTestNonNull2);
|
||||
EXPECT_STREQ(result, kDefaultJniInvocationLibrary);
|
||||
|
||||
result = JniInvocationGetLibraryWith(kTestNonNull, false, nullptr);
|
||||
EXPECT_STREQ(result, kDefaultJniInvocationLibrary);
|
||||
|
||||
result = JniInvocationGetLibraryWith(nullptr, false, nullptr);
|
||||
EXPECT_STREQ(result, kDefaultJniInvocationLibrary);
|
||||
}
|
||||
|
||||
TEST(JNIInvocation, GetDefaultJavaVMInitArgsBeforeInit) {
|
||||
EXPECT_DEATH(JNI_GetDefaultJavaVMInitArgs(nullptr), "Runtime library not loaded.");
|
||||
}
|
||||
|
||||
TEST(JNIInvocation, CreateJavaVMBeforeInit) {
|
||||
JavaVM *vm;
|
||||
JNIEnv *env;
|
||||
EXPECT_DEATH(JNI_CreateJavaVM(&vm, &env, nullptr), "Runtime library not loaded.");
|
||||
}
|
||||
|
||||
TEST(JNIInvocation, GetCreatedJavaVMsBeforeInit) {
|
||||
jsize vm_count;
|
||||
JavaVM *vm;
|
||||
int status = JNI_GetCreatedJavaVMs(&vm, 1, &vm_count);
|
||||
EXPECT_EQ(status, JNI_OK);
|
||||
EXPECT_EQ(vm_count, 0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
|||
// Do not use directly. Use the defaults below.
|
||||
package {
|
||||
// http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// the below license kinds from "libnativehelper_license":
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["libnativehelper_license"],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "jni_gtest_headers",
|
||||
host_supported: true,
|
||||
export_include_dirs: ["base"],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "jni_gtest_defaults",
|
||||
header_libs: ["jni_gtest_headers"],
|
||||
shared_libs: ["libnativehelper"],
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <jni.h>
|
||||
#include <nativehelper/JniInvocation.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// Example test setup following googletest docs:
|
||||
//
|
||||
// template <typename Provider>
|
||||
// class TemplatedTest : public JNITestBase<Provider> {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// typedef ::testing::Types<MockJNIProvider> Providers;
|
||||
// TYPED_TEST_CASE(TemplatedTest, Providers);
|
||||
//
|
||||
// TYPED_TEST() {
|
||||
// // Test code. Use "this->" to access TemplatedTest members.
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// Provider is a concept that must follow this structure:
|
||||
//
|
||||
// class JNIProvider {
|
||||
// public:
|
||||
// JNIProvider();
|
||||
//
|
||||
// void SetUp();
|
||||
// JNIEnv* CreateJNIEnv();
|
||||
//
|
||||
// void DestroyJNIEnv(JNIEnv* env);
|
||||
// void TearDown();
|
||||
// }
|
||||
|
||||
template <typename Provider, typename Test = ::testing::Test>
|
||||
class JNITestBase : public Test {
|
||||
protected:
|
||||
JNITestBase() : provider_(), env_(nullptr), java_vm_(nullptr) {
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
Test::SetUp();
|
||||
provider_.SetUp();
|
||||
env_ = provider_.CreateJNIEnv();
|
||||
ASSERT_TRUE(env_ != nullptr);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
provider_->DestroyJNIEnv(env_);
|
||||
provider_->TearDown();
|
||||
Test::TearDown();
|
||||
}
|
||||
|
||||
protected:
|
||||
Provider provider_;
|
||||
|
||||
JNIEnv* env_;
|
||||
JavaVM* java_vm_;
|
||||
};
|
||||
|
||||
// A mockable implementation of the Provider concept. It is the responsibility
|
||||
// of the test to stub out any needed functions (all function pointers will be
|
||||
// null initially).
|
||||
//
|
||||
// TODO: Consider googlemock.
|
||||
class MockJNIProvider {
|
||||
public:
|
||||
MockJNIProvider() {
|
||||
}
|
||||
|
||||
void SetUp() {
|
||||
// Nothing to here.
|
||||
}
|
||||
|
||||
// TODO: Spawn threads to allow more envs?
|
||||
JNIEnv* CreateJNIEnv() {
|
||||
return CreateMockedJNIEnv().release();
|
||||
}
|
||||
|
||||
void DestroyJNIEnv(JNIEnv* env) {
|
||||
delete env->functions;
|
||||
delete env;
|
||||
}
|
||||
|
||||
void TearDown() {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<JNIEnv> CreateMockedJNIEnv() {
|
||||
JNINativeInterface* inf = new JNINativeInterface();
|
||||
memset(inf, 0, sizeof(JNINativeInterface));
|
||||
|
||||
std::unique_ptr<JNIEnv> ret(new JNIEnv{0});
|
||||
ret->functions = inf;
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) 2019 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.
|
||||
*/
|
||||
|
||||
// All header files with MODULE_API decorated function declarations.
|
||||
#include "nativehelper/JNIHelp.h"
|
||||
#include "nativehelper/JniInvocation.h"
|
||||
#include "nativehelper/toStringArray.h"
|
||||
|
||||
int libnativehelper_api_test_main() {
|
||||
// The test here is that the headers are properly guarded to support
|
||||
// compilation with a C compiler.
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 "../libnativehelper_lazy.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "jni.h"
|
||||
|
||||
#include "nativehelper/JniInvocation.h"
|
||||
#include "nativehelper/JNIHelp.h"
|
||||
#include "nativehelper/JNIPlatformHelp.h"
|
||||
|
||||
// The tests here are just for the case when libnativehelper.so cannot be loaded by
|
||||
// libnativehelper_lazy.
|
||||
class LibnativehelperLazyTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
::testing::Test::SetUp();
|
||||
PreventLibnativehelperLazyLoadingForTests();
|
||||
}
|
||||
};
|
||||
|
||||
static const char* kLoadFailed = "Failed to load libnativehelper.so";
|
||||
|
||||
TEST_F(LibnativehelperLazyTest, NoLibnativehelperIsForJNIPlatformHelp) {
|
||||
C_JNIEnv* env = NULL;
|
||||
EXPECT_DEATH(jniGetNioBufferBaseArray(env, NULL), kLoadFailed);
|
||||
EXPECT_DEATH(jniGetNioBufferBaseArrayOffset(env, NULL), kLoadFailed);
|
||||
EXPECT_DEATH(jniGetNioBufferFields(env, NULL, NULL, NULL, NULL), kLoadFailed);
|
||||
EXPECT_DEATH(jniGetNioBufferPointer(env, NULL), kLoadFailed);
|
||||
EXPECT_DEATH(jniUninitializeConstants(), kLoadFailed);
|
||||
}
|
||||
|
||||
TEST_F(LibnativehelperLazyTest, NoLibnativehelperIsForJniInvocation) {
|
||||
EXPECT_DEATH(JniInvocationCreate(), kLoadFailed);
|
||||
EXPECT_DEATH(JniInvocationDestroy(NULL), kLoadFailed);
|
||||
EXPECT_DEATH(JniInvocationGetLibrary("a", NULL), kLoadFailed);
|
||||
EXPECT_DEATH(JniInvocationInit(NULL, "a"), kLoadFailed);
|
||||
}
|
||||
|
||||
TEST_F(LibnativehelperLazyTest, NoLibnativehelperIsForJniApi) {
|
||||
PreventLibnativehelperLazyLoadingForTests();
|
||||
|
||||
JavaVM* vm = NULL;
|
||||
JNIEnv* env = NULL;
|
||||
jsize count = 0;
|
||||
|
||||
EXPECT_DEATH(JNI_GetDefaultJavaVMInitArgs(NULL), kLoadFailed);
|
||||
EXPECT_DEATH(JNI_CreateJavaVM(&vm, &env, NULL), kLoadFailed);
|
||||
EXPECT_EQ(JNI_OK, JNI_GetCreatedJavaVMs(&vm, 1, &count));
|
||||
EXPECT_EQ(0, count);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 "nativehelper/scoped_local_frame.h"
|
||||
|
||||
// This is a test that scoped headers work independently.
|
||||
|
||||
void TestScopedLocalFrame(JNIEnv* env) {
|
||||
ScopedLocalFrame slf(env);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 "nativehelper/scoped_local_ref.h"
|
||||
|
||||
// This is a test that scoped headers work independently.
|
||||
|
||||
void TestScopedLocalRef(JNIEnv* env) {
|
||||
ScopedLocalRef<jarray> slr1(env);
|
||||
slr1.reset(nullptr);
|
||||
slr1.get();
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 "nativehelper/scoped_primitive_array.h"
|
||||
|
||||
// This is a test that scoped headers work independently.
|
||||
|
||||
void TestScopedPrimitiveArrayRO(JNIEnv* env, jbooleanArray array) {
|
||||
ScopedBooleanArrayRO sba(env, array);
|
||||
sba.reset(nullptr);
|
||||
sba.get();
|
||||
sba.size();
|
||||
}
|
||||
|
||||
void TestCompilationRW(JNIEnv* env, jintArray array) {
|
||||
ScopedIntArrayRW sba(env, array);
|
||||
sba.reset(nullptr);
|
||||
sba.get();
|
||||
sba.size();
|
||||
sba[3] = 3;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 "nativehelper/scoped_string_chars.h"
|
||||
|
||||
// This is a test that scoped headers work independently.
|
||||
|
||||
void TestCompilationScopedStringChars(JNIEnv* env, string s) {
|
||||
ScopedStringChars ssc(s);
|
||||
ssc.get();
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 "nativehelper/scoped_utf_chars.h"
|
||||
|
||||
// This is a test that scoped headers work independently.
|
||||
|
||||
void TestCompilationScopedUtfChars(JNIEnv* env, jstring s) {
|
||||
ScopedUtfChars suc(env, s);
|
||||
suc.c_str();
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (C) 2020 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.
|
||||
|
||||
package {
|
||||
// http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// the below license kinds from "libnativehelper_license":
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["libnativehelper_license"],
|
||||
}
|
||||
|
||||
java_defaults {
|
||||
name: "mts_libnativehelper_defaults",
|
||||
compile_multilib: "both",
|
||||
libs: [
|
||||
"android.test.base.stubs",
|
||||
],
|
||||
static_libs: [
|
||||
"ctstestrunner-axt",
|
||||
"nativetesthelper",
|
||||
],
|
||||
jni_uses_platform_apis: true,
|
||||
sdk_version: "test_current",
|
||||
srcs: ["src/com/android/art/libnativehelper/JniHelpTest.java"],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"mts",
|
||||
],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "MtsLibnativehelperTestCases",
|
||||
defaults: [
|
||||
"cts_defaults",
|
||||
"mts_libnativehelper_defaults",
|
||||
],
|
||||
jni_libs: [
|
||||
"libnativehelper_mts_jni",
|
||||
],
|
||||
manifest: "AndroidManifest.xml",
|
||||
srcs: [
|
||||
"src/com/android/art/libnativehelper/LibnativehelperGTests.java",
|
||||
],
|
||||
}
|
||||
|
||||
// Same tests as "MtsLibnativehelperTestCases", but with the jni library
|
||||
// linked against libnativehelper_lazy.a rather than libnativehelper.so.
|
||||
|
||||
android_test {
|
||||
name: "MtsLibnativehelperLazyTestCases",
|
||||
defaults: [
|
||||
"cts_defaults",
|
||||
"mts_libnativehelper_defaults",
|
||||
],
|
||||
jni_libs: [
|
||||
"libnativehelper_lazy_mts_jni",
|
||||
],
|
||||
srcs: [
|
||||
"src/com/android/art/libnativehelper/LibnativehelperLazyGTests.java",
|
||||
],
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.art.libnativehelper"
|
||||
android:targetSandboxVersion="2">
|
||||
<application android:usesCleartextTraffic="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.art.libnativehelper"
|
||||
android:label="MTS tests for libnativehelper">
|
||||
<meta-data android:name="listener"
|
||||
android:value="com.android.cts.runner.CtsTestRunListener" />
|
||||
</instrumentation>
|
||||
</manifest>
|
|
@ -0,0 +1,5 @@
|
|||
# Bug component: 86431
|
||||
enh@google.com
|
||||
mast@google.com
|
||||
ngeoffray@google.com
|
||||
oth@google.com
|
|
@ -0,0 +1,51 @@
|
|||
# libnativehelper MTS tests
|
||||
|
||||
These tests cover the API surface of libnativehelper that is applicable once
|
||||
the runtime is initialized.
|
||||
|
||||
These tests do not cover the API surface relating to the binding of the ART
|
||||
runtime (DalvikVM), that preclude the initialization of the runtime, nor do
|
||||
they cover JNI_CreateJavaVM(). These APIs have been invoked before the test
|
||||
harness runs these tests.
|
||||
|
||||
API surface not directly covered here are:
|
||||
|
||||
```
|
||||
JNI_GetCreatedJavaVMs
|
||||
|
||||
JniInvocationCreate
|
||||
JniInvocationDestroy
|
||||
JniInvocationInit
|
||||
JniInvocationGetLibrary
|
||||
|
||||
jniUninitializeConstants
|
||||
```
|
||||
|
||||
`JniInvocationInit()` is responsible for binding the ART runtime and
|
||||
specifically the following methods:
|
||||
|
||||
```
|
||||
JNI_CreateJavaVM
|
||||
JNI_GetCreatedJavaVMs
|
||||
JNI_GetDefaultJavaVMInitArgs
|
||||
```
|
||||
|
||||
These tests do check that `JNI_GetCreatedJavaVMs()` and
|
||||
`JNI_GetDefaultJavaVMInitArgs()` behave as expected and are thus asserted to
|
||||
be correctly bound. `JNI_CreateJavaVM()` cannot be called in these tests
|
||||
because Android only supports a single runtime per process.
|
||||
|
||||
`JniInvocationInit()` uses `JniInvocationGetLibrary()` to determine which
|
||||
runtime to load (release, debug, or custom). The code responsible for that
|
||||
decision is tested comprehensively in `libnativehelper_gtests`.
|
||||
|
||||
`jniUninitializeConstants` is only intended to be called when the runtime is
|
||||
shutting down and unloading the managed core libraries.
|
||||
|
||||
## Potential Issues
|
||||
|
||||
The test harness depends on libnativehelper_compat_libc++ and the tests
|
||||
depend on libnativehelper. The former library is a subset of libnativehelper.
|
||||
There are potential ODR problems if the two libraries having overlapping
|
||||
global state. It would be better to have two separate test suites for these
|
||||
two libraries.
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (C) 2020 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.
|
||||
|
||||
package {
|
||||
// http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// the below license kinds from "libnativehelper_license":
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["libnativehelper_license"],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "libnativehelper_jni_defaults",
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-Wno-unused-parameter",
|
||||
],
|
||||
srcs: [
|
||||
"jni_invocation_test.cpp",
|
||||
"jni_helper_jni.cpp",
|
||||
"libnativehelper_test.cpp",
|
||||
],
|
||||
shared_libs: ["liblog"],
|
||||
static_libs: ["libgmock_ndk"],
|
||||
stl: "c++_static",
|
||||
// libnativetesthelper_jni depends on libnativehelper_compat_libc++.
|
||||
// At the time of writing there is no duplicated global state in the
|
||||
// libnativehelper sources between these functions. Should this change,
|
||||
// then there could be ODR problems here.
|
||||
whole_static_libs: ["libnativetesthelper_jni"],
|
||||
tidy: true,
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libnativehelper_mts_jni",
|
||||
defaults: ["libnativehelper_jni_defaults"],
|
||||
shared_libs: ["libnativehelper"],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libnativehelper_lazy_mts_jni",
|
||||
defaults: ["libnativehelper_jni_defaults"],
|
||||
static_libs: ["libnativehelper_lazy"],
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <iterator>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <nativehelper/jni_macros.h>
|
||||
#include <nativehelper/scoped_local_ref.h>
|
||||
#include <nativehelper/scoped_string_chars.h>
|
||||
#include <nativehelper/scoped_utf_chars.h>
|
||||
#include <nativehelper/JNIPlatformHelp.h>
|
||||
|
||||
#include "libnativehelper_test.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static void throwException(JNIEnv* env, jclass /*clazz*/, jstring className, jstring message) {
|
||||
ScopedUtfChars c(env, className);
|
||||
ScopedUtfChars m(env, message);
|
||||
jniThrowException(env, c.c_str(), m.c_str());
|
||||
}
|
||||
|
||||
static void throwExceptionWithIntFormat(JNIEnv* env,
|
||||
jclass /*clazz*/,
|
||||
jstring className,
|
||||
jstring format,
|
||||
jint value) {
|
||||
ScopedUtfChars c(env, className);
|
||||
ScopedUtfChars f(env, format);
|
||||
jniThrowExceptionFmt(env, c.c_str(), f.c_str(), value);
|
||||
}
|
||||
|
||||
static void throwNullPointerException(JNIEnv* env,
|
||||
jclass /*clazz*/,
|
||||
jstring message) {
|
||||
ScopedUtfChars m(env, message);
|
||||
jniThrowNullPointerException(env, m.c_str());
|
||||
}
|
||||
|
||||
static void throwRuntimeException(JNIEnv* env, jclass /*clazz*/, jstring message) {
|
||||
ScopedUtfChars m(env, message);
|
||||
jniThrowRuntimeException(env, m.c_str());
|
||||
}
|
||||
|
||||
static void throwIOException(JNIEnv* env, jclass /*clazz*/, jint cause) {
|
||||
jniThrowIOException(env, cause);
|
||||
}
|
||||
|
||||
static void throwErrnoException(JNIEnv* env, jclass /*clazz*/, jstring functionName, jint cause) {
|
||||
ScopedUtfChars m(env, functionName);
|
||||
jniThrowErrnoException(env, m.c_str(), cause);
|
||||
}
|
||||
|
||||
static void logException(JNIEnv* env, jclass /*clazz*/, jthrowable throwable) {
|
||||
jniLogException(env, ANDROID_LOG_VERBOSE, __FILE__, throwable);
|
||||
}
|
||||
|
||||
static jobject fileDescriptorCreate(JNIEnv* env, jclass /*clazz*/, jint unix_fd) {
|
||||
return jniCreateFileDescriptor(env, unix_fd);
|
||||
}
|
||||
|
||||
static jint fileDescriptorGetFD(JNIEnv* env, jclass /*clazz*/, jobject jiofd) {
|
||||
return jniGetFDFromFileDescriptor(env, jiofd);
|
||||
}
|
||||
|
||||
static void fileDescriptorSetFD(JNIEnv* env, jclass /*clazz*/, jobject jiofd, jint unix_fd) {
|
||||
jniSetFileDescriptorOfFD(env, jiofd, unix_fd);
|
||||
}
|
||||
|
||||
static jstring createString(JNIEnv* env, jclass /*clazz*/, jstring value) {
|
||||
ScopedStringChars ssc(env, value);
|
||||
return jniCreateString(env, ssc.get(), ssc.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
JNIEnv* env;
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
static const JNINativeMethod methods[] = {
|
||||
MAKE_JNI_NATIVE_METHOD("throwException",
|
||||
"(Ljava/lang/String;Ljava/lang/String;)V",
|
||||
throwException),
|
||||
MAKE_JNI_NATIVE_METHOD("throwExceptionWithIntFormat",
|
||||
"(Ljava/lang/String;Ljava/lang/String;I)V",
|
||||
throwExceptionWithIntFormat),
|
||||
MAKE_JNI_NATIVE_METHOD("throwNullPointerException",
|
||||
"(Ljava/lang/String;)V",
|
||||
throwNullPointerException),
|
||||
MAKE_JNI_NATIVE_METHOD("throwRuntimeException",
|
||||
"(Ljava/lang/String;)V",
|
||||
throwRuntimeException),
|
||||
MAKE_JNI_NATIVE_METHOD("throwIOException",
|
||||
"(I)V",
|
||||
throwIOException),
|
||||
MAKE_JNI_NATIVE_METHOD("throwErrnoException",
|
||||
"(Ljava/lang/String;I)V",
|
||||
throwErrnoException),
|
||||
MAKE_JNI_NATIVE_METHOD("logException",
|
||||
"(Ljava/lang/Throwable;)V",
|
||||
logException),
|
||||
MAKE_JNI_NATIVE_METHOD("fileDescriptorCreate",
|
||||
"(I)Ljava/io/FileDescriptor;",
|
||||
fileDescriptorCreate),
|
||||
MAKE_JNI_NATIVE_METHOD("fileDescriptorGetFD",
|
||||
"(Ljava/io/FileDescriptor;)I",
|
||||
fileDescriptorGetFD),
|
||||
MAKE_JNI_NATIVE_METHOD("fileDescriptorSetFD",
|
||||
"(Ljava/io/FileDescriptor;I)V",
|
||||
fileDescriptorSetFD),
|
||||
MAKE_JNI_NATIVE_METHOD("createString",
|
||||
"(Ljava/lang/String;)Ljava/lang/String;",
|
||||
createString),
|
||||
};
|
||||
int rc = jniRegisterNativeMethods(env,
|
||||
"com/android/art/libnativehelper/JniHelpTest",
|
||||
methods,
|
||||
std::size(methods));
|
||||
if (rc != JNI_OK) return rc;
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 "libnativehelper_test.h"
|
||||
|
||||
TEST_F(LibnativehelperTest, GetCreatedJavaVMs) {
|
||||
JavaVM* createdVMs[2] = { nullptr, nullptr };
|
||||
jsize count;
|
||||
ASSERT_NE(nullptr, mEnv);
|
||||
ASSERT_EQ(JNI_OK, JNI_GetCreatedJavaVMs(&createdVMs[0], 2, &count));
|
||||
ASSERT_EQ(1, count);
|
||||
ASSERT_NE(nullptr, createdVMs[0]);
|
||||
ASSERT_EQ(nullptr, createdVMs[1]);
|
||||
|
||||
JavaVM* currentVM;
|
||||
ASSERT_EQ(JNI_OK, mEnv->GetJavaVM(¤tVM));
|
||||
ASSERT_EQ(createdVMs[0], currentVM);
|
||||
}
|
||||
|
||||
TEST_F(LibnativehelperTest, GetDefaultJavaVMInitArgs) {
|
||||
JavaVMOption options[1];
|
||||
JavaVMInitArgs initArgs;
|
||||
initArgs.version = JNI_VERSION_1_6;
|
||||
initArgs.nOptions = 0;
|
||||
initArgs.options = options;
|
||||
initArgs.ignoreUnrecognized = JNI_TRUE;
|
||||
// ART does not support JNI_GetDefaultJavaVMInitArgs(), should this change it'll need a test.
|
||||
ASSERT_EQ(JNI_ERR, JNI_GetDefaultJavaVMInitArgs(&initArgs));
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <libnativehelper_test.h>
|
||||
|
||||
#include <nativetesthelper_jni/utils.h>
|
||||
|
||||
void LibnativehelperTest::SetUp() {
|
||||
int result = GetJavaVM()->GetEnv(reinterpret_cast<void**>(&mEnv), JNI_VERSION_1_6);
|
||||
EXPECT_EQ(JNI_OK, result);
|
||||
EXPECT_NE(nullptr, mEnv);
|
||||
}
|
||||
|
||||
void LibnativehelperTest::TearDown() {
|
||||
mEnv = nullptr;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
class LibnativehelperTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() override;
|
||||
virtual void TearDown() override;
|
||||
|
||||
JNIEnv* mEnv;
|
||||
};
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
package com.android.art.libnativehelper;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
import android.system.ErrnoException;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
public class JniHelpTest extends AndroidTestCase {
|
||||
private static native void throwException(String className, String message);
|
||||
private static native void throwExceptionWithIntFormat(String className,
|
||||
String format,
|
||||
int value);
|
||||
private static native void throwNullPointerException(String message);
|
||||
private static native void throwRuntimeException(String message);
|
||||
private static native void throwIOException(int cause) throws IOException;
|
||||
private static native void throwErrnoException(String fileName, int cause) throws ErrnoException;
|
||||
private static native void logException(Throwable throwable);
|
||||
|
||||
private static native FileDescriptor fileDescriptorCreate(int unixFd);
|
||||
private static native int fileDescriptorGetFD(FileDescriptor jiofd);
|
||||
private static native void fileDescriptorSetFD(FileDescriptor jiofd, int unixFd);
|
||||
|
||||
private static native String createString(String input);
|
||||
|
||||
public void testThrowException() {
|
||||
final String message = "Because test";
|
||||
try {
|
||||
throwException("java/lang/RuntimeException", message);
|
||||
fail("Unreachable");
|
||||
} catch (RuntimeException e) {
|
||||
assertEquals(message, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testThrowExceptionWithIntFormat() {
|
||||
final String format = "Because test %d";
|
||||
try {
|
||||
throwExceptionWithIntFormat("java/lang/RuntimeException", format, 101);
|
||||
fail("Unreachable");
|
||||
} catch (RuntimeException e) {
|
||||
assertEquals("Because test 101", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testThrowNullPointerException() {
|
||||
final String message = "Because another test";
|
||||
try {
|
||||
throwNullPointerException(message);
|
||||
fail("Unreachable");
|
||||
} catch (NullPointerException e) {
|
||||
assertEquals(message, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testThrowRuntimeException() {
|
||||
final String message = "Because test again";
|
||||
try {
|
||||
throwRuntimeException(message);
|
||||
fail("Unreachable");
|
||||
} catch (RuntimeException e) {
|
||||
assertEquals(message, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testIOException() {
|
||||
String s1 = null;
|
||||
try {
|
||||
throwIOException(70);
|
||||
fail("Unreachable");
|
||||
} catch (IOException e) {
|
||||
s1 = e.getMessage();
|
||||
}
|
||||
assertNotNull(s1);
|
||||
|
||||
String s2 = null;
|
||||
try {
|
||||
throwIOException(71);
|
||||
fail("Unreachable");
|
||||
} catch (IOException e) {
|
||||
s2 = e.getMessage();
|
||||
}
|
||||
assertNotNull(s2);
|
||||
|
||||
assertFalse(s1.equals(s2));
|
||||
}
|
||||
|
||||
public void testErrnoException() {
|
||||
final String functionName = "execve";
|
||||
final int err = 42;
|
||||
try {
|
||||
throwErrnoException(functionName, err);
|
||||
fail("Unreachable");
|
||||
} catch (ErrnoException e) {
|
||||
// The message contains the function name as well as the string for the errno, just only
|
||||
// check the first part of the message
|
||||
assertTrue("Function name", e.getMessage().startsWith(functionName));
|
||||
assertEquals(err, e.errno);
|
||||
}
|
||||
}
|
||||
|
||||
public void testLogException() {
|
||||
try {
|
||||
throw new RuntimeException("Exception for logging test");
|
||||
} catch (RuntimeException e) {
|
||||
// TODO: Mock/redirect logcat to test output is logged appropriately.
|
||||
// Or add extend JNIHelp API to write to a buffer or file.
|
||||
logException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFileDescriptorCreate() {
|
||||
int [] unix_fds = { -999, -1, 0, 1, 1000 };
|
||||
for (int unix_fd : unix_fds) {
|
||||
FileDescriptor f0 = fileDescriptorCreate(unix_fd);
|
||||
assertNotNull(f0);
|
||||
assertSame(f0.getClass(), FileDescriptor.class);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFileDescriptorGetNull() {
|
||||
assertEquals(-1, fileDescriptorGetFD(null));
|
||||
}
|
||||
|
||||
public void testFileDescriptorGetNonNull() {
|
||||
final int UNIX_FD = 77;
|
||||
FileDescriptor jiofd = fileDescriptorCreate(UNIX_FD);
|
||||
assertEquals(UNIX_FD, fileDescriptorGetFD(jiofd));
|
||||
}
|
||||
|
||||
public void testFileDescriptorSetNull() {
|
||||
try {
|
||||
fileDescriptorSetFD(null, 1);
|
||||
fail("Expected NullPointerException to be thrown.");
|
||||
} catch (NullPointerException e) {}
|
||||
}
|
||||
|
||||
public void testFileDescriptorSetNonNull() {
|
||||
final int UNIX_FD = 127;
|
||||
FileDescriptor jiofd = fileDescriptorCreate(0);
|
||||
fileDescriptorSetFD(jiofd, UNIX_FD);
|
||||
assertEquals(UNIX_FD, fileDescriptorGetFD(jiofd));
|
||||
}
|
||||
|
||||
public void testCreateString() {
|
||||
String input = "The treacherous mountain path lay ahead.";
|
||||
String output = createString(input);
|
||||
assertEquals(input, output);
|
||||
assertNotSame(input, output);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
package com.android.art.libnativehelper;
|
||||
|
||||
import com.android.gtestrunner.GtestRunner;
|
||||
import com.android.gtestrunner.TargetLibrary;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(GtestRunner.class)
|
||||
@TargetLibrary("nativehelper_mts_jni")
|
||||
public class LibnativehelperGTests {}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
package com.android.art.libnativehelper;
|
||||
|
||||
import com.android.gtestrunner.GtestRunner;
|
||||
import com.android.gtestrunner.TargetLibrary;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(GtestRunner.class)
|
||||
@TargetLibrary("nativehelper_lazy_mts_jni")
|
||||
public class LibnativehelperLazyGTests {}
|
Loading…
Reference in New Issue