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