Loading services/core/java/com/android/server/pm/Settings.java +31 −2 Original line number Diff line number Diff line Loading @@ -369,6 +369,8 @@ public final class Settings implements Watchable, Snappable { // Current settings file. private final File mSettingsFilename; // Compressed current settings file. private final File mCompressedSettingsFilename; // Previous settings file. // Removed when the current settings file successfully stored. private final File mPreviousSettingsFilename; Loading Loading @@ -639,6 +641,7 @@ public final class Settings implements Watchable, Snappable { mRuntimePermissionsPersistence = null; mPermissionDataProvider = null; mSettingsFilename = null; mCompressedSettingsFilename = null; mPreviousSettingsFilename = null; mPackageListFilename = null; mStoppedPackagesFilename = null; Loading Loading @@ -710,6 +713,7 @@ public final class Settings implements Watchable, Snappable { |FileUtils.S_IROTH|FileUtils.S_IXOTH, -1, -1); mSettingsFilename = new File(mSystemDir, "packages.xml"); mCompressedSettingsFilename = new File(mSystemDir, "packages.compressed"); mPreviousSettingsFilename = new File(mSystemDir, "packages-backup.xml"); mPackageListFilename = new File(mSystemDir, "packages.list"); FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID); Loading Loading @@ -751,6 +755,7 @@ public final class Settings implements Watchable, Snappable { mLock = null; mRuntimePermissionsPersistence = r.mRuntimePermissionsPersistence; mSettingsFilename = null; mCompressedSettingsFilename = null; mPreviousSettingsFilename = null; mPackageListFilename = null; mStoppedPackagesFilename = null; Loading Loading @@ -2588,6 +2593,8 @@ public final class Settings implements Watchable, Snappable { Slog.w(PackageManagerService.TAG, "Preserving older settings backup"); } } // Compressed settings are not valid anymore. mCompressedSettingsFilename.delete(); mPastSignatures.clear(); Loading Loading @@ -2677,10 +2684,30 @@ public final class Settings implements Watchable, Snappable { mPreviousSettingsFilename.delete(); FileUtils.setPermissions(mSettingsFilename.toString(), FileUtils.S_IRUSR|FileUtils.S_IWUSR |FileUtils.S_IRGRP|FileUtils.S_IWGRP, FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP, -1, -1); final FileInputStream fis = new FileInputStream(mSettingsFilename); final AtomicFile compressed = new AtomicFile(mCompressedSettingsFilename); final FileOutputStream fos = compressed.startWrite(); BackgroundThread.getHandler().post(() -> { try { if (!nativeCompressLz4(fis.getFD().getInt$(), fos.getFD().getInt$())) { throw new IOException("Failed to compress"); } compressed.finishWrite(fos); FileUtils.setPermissions(mCompressedSettingsFilename.toString(), FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP, -1, -1); } catch (IOException e) { Slog.e(PackageManagerService.TAG, "Failed to write compressed settings file: " + mCompressedSettingsFilename, e); compressed.delete(); } IoUtils.closeQuietly(fis); }); writeKernelMappingLPr(); writePackageListLPr(); writeAllUsersPackageRestrictionsLPr(sync); Loading @@ -2703,6 +2730,8 @@ public final class Settings implements Watchable, Snappable { //Debug.stopMethodTracing(); } private native boolean nativeCompressLz4(int inputFd, int outputFd); private void writeKernelRemoveUserLPr(int userId) { if (mKernelMappingFilename == null) return; Loading services/core/jni/Android.bp +25 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ cc_library_static { "com_android_server_PersistentDataBlockService.cpp", "com_android_server_am_LowMemDetector.cpp", "com_android_server_pm_PackageManagerShellCommandDataLoader.cpp", "com_android_server_pm_Settings.cpp", "com_android_server_sensor_SensorService.cpp", "com_android_server_wm_TaskFpsCallbackController.cpp", "onload.cpp", Loading Loading @@ -152,6 +153,7 @@ cc_defaults { "libpsi", "libdataloader", "libincfs", "liblz4", "android.hardware.audio.common@2.0", "android.media.audio.common.types-V1-ndk", "android.hardware.broadcastradio@1.0", Loading Loading @@ -232,3 +234,26 @@ filegroup { "com_android_server_app_GameManagerService.cpp", ], } // Settings JNI library for unit tests. cc_library_shared { name: "libservices.core.settings.testonly", defaults: ["libservices.core-libs"], cpp_std: "c++2a", cflags: [ "-Wall", "-Werror", "-Wno-unused-parameter", "-Wthread-safety", ], srcs: [ "com_android_server_pm_Settings.cpp", "onload_settings.cpp", ], header_libs: [ "bionic_libc_platform_headers", ], } services/core/jni/com_android_server_pm_Settings.cpp 0 → 100644 +161 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #define ATRACE_TAG ATRACE_TAG_ADB #define LOG_TAG "Settings-jni" #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/no_destructor.h> #include <core_jni_helpers.h> #include <lz4frame.h> #include <nativehelper/JNIHelp.h> #include <vector> namespace android { namespace { struct LZ4FCContextDeleter { void operator()(LZ4F_cctx* cctx) { LZ4F_freeCompressionContext(cctx); } }; static constexpr int LZ4_BUFFER_SIZE = 64 * 1024; static bool writeToFile(std::vector<char>& outBuffer, int fdOut) { if (!android::base::WriteFully(fdOut, outBuffer.data(), outBuffer.size())) { PLOG(ERROR) << "Error to write to output file"; return false; } outBuffer.clear(); return true; } static bool compressAndWriteLz4(LZ4F_cctx* context, std::vector<char>& inBuffer, std::vector<char>& outBuffer, int fdOut) { auto inSize = inBuffer.size(); if (inSize > 0) { auto prvSize = outBuffer.size(); auto outSize = LZ4F_compressBound(inSize, nullptr); outBuffer.resize(prvSize + outSize); auto rc = LZ4F_compressUpdate(context, outBuffer.data() + prvSize, outSize, inBuffer.data(), inSize, nullptr); if (LZ4F_isError(rc)) { LOG(ERROR) << "LZ4F_compressUpdate failed: " << LZ4F_getErrorName(rc); return false; } outBuffer.resize(prvSize + rc); } if (outBuffer.size() > LZ4_BUFFER_SIZE) { return writeToFile(outBuffer, fdOut); } return true; } static jboolean nativeCompressLz4(JNIEnv* env, jclass klass, jint fdIn, jint fdOut) { LZ4F_cctx* cctx; if (LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) != 0) { LOG(ERROR) << "Failed to initialize LZ4 compression context."; return false; } std::unique_ptr<LZ4F_cctx, LZ4FCContextDeleter> context(cctx); std::vector<char> inBuffer, outBuffer; inBuffer.reserve(LZ4_BUFFER_SIZE); outBuffer.reserve(2 * LZ4_BUFFER_SIZE); LZ4F_preferences_t prefs; memset(&prefs, 0, sizeof(prefs)); // Set compression parameters. prefs.autoFlush = 0; prefs.compressionLevel = 0; prefs.frameInfo.blockMode = LZ4F_blockLinked; prefs.frameInfo.blockSizeID = LZ4F_default; prefs.frameInfo.blockChecksumFlag = LZ4F_noBlockChecksum; prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; prefs.favorDecSpeed = 0; struct stat sb; if (fstat(fdIn, &sb) == -1) { PLOG(ERROR) << "Failed to obtain input file size."; return false; } prefs.frameInfo.contentSize = sb.st_size; // Write header first. outBuffer.resize(LZ4F_HEADER_SIZE_MAX); auto rc = LZ4F_compressBegin(context.get(), outBuffer.data(), outBuffer.size(), &prefs); if (LZ4F_isError(rc)) { LOG(ERROR) << "LZ4F_compressBegin failed: " << LZ4F_getErrorName(rc); return false; } outBuffer.resize(rc); bool eof = false; while (!eof) { constexpr auto capacity = LZ4_BUFFER_SIZE; inBuffer.resize(capacity); auto read = TEMP_FAILURE_RETRY(::read(fdIn, inBuffer.data(), inBuffer.size())); if (read < 0) { PLOG(ERROR) << "Failed to read from input file."; return false; } inBuffer.resize(read); if (read == 0) { eof = true; } if (!compressAndWriteLz4(context.get(), inBuffer, outBuffer, fdOut)) { return false; } } // Footer. auto prvSize = outBuffer.size(); outBuffer.resize(outBuffer.capacity()); rc = LZ4F_compressEnd(context.get(), outBuffer.data() + prvSize, outBuffer.size() - prvSize, nullptr); if (LZ4F_isError(rc)) { LOG(ERROR) << "LZ4F_compressEnd failed: " << LZ4F_getErrorName(rc); return false; } outBuffer.resize(prvSize + rc); if (!writeToFile(outBuffer, fdOut)) { return false; } return true; } static const JNINativeMethod method_table[] = { {"nativeCompressLz4", "(II)Z", (void*)nativeCompressLz4}, }; } // namespace int register_android_server_com_android_server_pm_Settings(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/server/pm/Settings", method_table, NELEM(method_table)); } } // namespace android services/core/jni/onload.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ int register_android_server_am_LowMemDetector(JNIEnv* env); int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(JNIEnv* env); int register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(JNIEnv* env); int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env); int register_android_server_com_android_server_pm_Settings(JNIEnv* env); int register_android_server_AdbDebuggingManager(JNIEnv* env); int register_android_server_FaceService(JNIEnv* env); int register_android_server_GpuService(JNIEnv* env); Loading Loading @@ -114,6 +115,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(env); register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(env); register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env); register_android_server_com_android_server_pm_Settings(env); register_android_server_AdbDebuggingManager(env); register_android_server_FaceService(env); register_android_server_GpuService(env); Loading services/core/jni/onload_settings.cpp 0 → 100644 +39 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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 "jni.h" #include "utils/Log.h" namespace android { int register_android_server_com_android_server_pm_Settings(JNIEnv* env); }; using namespace android; extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("GetEnv failed!"); return result; } ALOG_ASSERT(env, "Could not retrieve the env!"); register_android_server_com_android_server_pm_Settings(env); return JNI_VERSION_1_4; } Loading
services/core/java/com/android/server/pm/Settings.java +31 −2 Original line number Diff line number Diff line Loading @@ -369,6 +369,8 @@ public final class Settings implements Watchable, Snappable { // Current settings file. private final File mSettingsFilename; // Compressed current settings file. private final File mCompressedSettingsFilename; // Previous settings file. // Removed when the current settings file successfully stored. private final File mPreviousSettingsFilename; Loading Loading @@ -639,6 +641,7 @@ public final class Settings implements Watchable, Snappable { mRuntimePermissionsPersistence = null; mPermissionDataProvider = null; mSettingsFilename = null; mCompressedSettingsFilename = null; mPreviousSettingsFilename = null; mPackageListFilename = null; mStoppedPackagesFilename = null; Loading Loading @@ -710,6 +713,7 @@ public final class Settings implements Watchable, Snappable { |FileUtils.S_IROTH|FileUtils.S_IXOTH, -1, -1); mSettingsFilename = new File(mSystemDir, "packages.xml"); mCompressedSettingsFilename = new File(mSystemDir, "packages.compressed"); mPreviousSettingsFilename = new File(mSystemDir, "packages-backup.xml"); mPackageListFilename = new File(mSystemDir, "packages.list"); FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID); Loading Loading @@ -751,6 +755,7 @@ public final class Settings implements Watchable, Snappable { mLock = null; mRuntimePermissionsPersistence = r.mRuntimePermissionsPersistence; mSettingsFilename = null; mCompressedSettingsFilename = null; mPreviousSettingsFilename = null; mPackageListFilename = null; mStoppedPackagesFilename = null; Loading Loading @@ -2588,6 +2593,8 @@ public final class Settings implements Watchable, Snappable { Slog.w(PackageManagerService.TAG, "Preserving older settings backup"); } } // Compressed settings are not valid anymore. mCompressedSettingsFilename.delete(); mPastSignatures.clear(); Loading Loading @@ -2677,10 +2684,30 @@ public final class Settings implements Watchable, Snappable { mPreviousSettingsFilename.delete(); FileUtils.setPermissions(mSettingsFilename.toString(), FileUtils.S_IRUSR|FileUtils.S_IWUSR |FileUtils.S_IRGRP|FileUtils.S_IWGRP, FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP, -1, -1); final FileInputStream fis = new FileInputStream(mSettingsFilename); final AtomicFile compressed = new AtomicFile(mCompressedSettingsFilename); final FileOutputStream fos = compressed.startWrite(); BackgroundThread.getHandler().post(() -> { try { if (!nativeCompressLz4(fis.getFD().getInt$(), fos.getFD().getInt$())) { throw new IOException("Failed to compress"); } compressed.finishWrite(fos); FileUtils.setPermissions(mCompressedSettingsFilename.toString(), FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP, -1, -1); } catch (IOException e) { Slog.e(PackageManagerService.TAG, "Failed to write compressed settings file: " + mCompressedSettingsFilename, e); compressed.delete(); } IoUtils.closeQuietly(fis); }); writeKernelMappingLPr(); writePackageListLPr(); writeAllUsersPackageRestrictionsLPr(sync); Loading @@ -2703,6 +2730,8 @@ public final class Settings implements Watchable, Snappable { //Debug.stopMethodTracing(); } private native boolean nativeCompressLz4(int inputFd, int outputFd); private void writeKernelRemoveUserLPr(int userId) { if (mKernelMappingFilename == null) return; Loading
services/core/jni/Android.bp +25 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ cc_library_static { "com_android_server_PersistentDataBlockService.cpp", "com_android_server_am_LowMemDetector.cpp", "com_android_server_pm_PackageManagerShellCommandDataLoader.cpp", "com_android_server_pm_Settings.cpp", "com_android_server_sensor_SensorService.cpp", "com_android_server_wm_TaskFpsCallbackController.cpp", "onload.cpp", Loading Loading @@ -152,6 +153,7 @@ cc_defaults { "libpsi", "libdataloader", "libincfs", "liblz4", "android.hardware.audio.common@2.0", "android.media.audio.common.types-V1-ndk", "android.hardware.broadcastradio@1.0", Loading Loading @@ -232,3 +234,26 @@ filegroup { "com_android_server_app_GameManagerService.cpp", ], } // Settings JNI library for unit tests. cc_library_shared { name: "libservices.core.settings.testonly", defaults: ["libservices.core-libs"], cpp_std: "c++2a", cflags: [ "-Wall", "-Werror", "-Wno-unused-parameter", "-Wthread-safety", ], srcs: [ "com_android_server_pm_Settings.cpp", "onload_settings.cpp", ], header_libs: [ "bionic_libc_platform_headers", ], }
services/core/jni/com_android_server_pm_Settings.cpp 0 → 100644 +161 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #define ATRACE_TAG ATRACE_TAG_ADB #define LOG_TAG "Settings-jni" #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/no_destructor.h> #include <core_jni_helpers.h> #include <lz4frame.h> #include <nativehelper/JNIHelp.h> #include <vector> namespace android { namespace { struct LZ4FCContextDeleter { void operator()(LZ4F_cctx* cctx) { LZ4F_freeCompressionContext(cctx); } }; static constexpr int LZ4_BUFFER_SIZE = 64 * 1024; static bool writeToFile(std::vector<char>& outBuffer, int fdOut) { if (!android::base::WriteFully(fdOut, outBuffer.data(), outBuffer.size())) { PLOG(ERROR) << "Error to write to output file"; return false; } outBuffer.clear(); return true; } static bool compressAndWriteLz4(LZ4F_cctx* context, std::vector<char>& inBuffer, std::vector<char>& outBuffer, int fdOut) { auto inSize = inBuffer.size(); if (inSize > 0) { auto prvSize = outBuffer.size(); auto outSize = LZ4F_compressBound(inSize, nullptr); outBuffer.resize(prvSize + outSize); auto rc = LZ4F_compressUpdate(context, outBuffer.data() + prvSize, outSize, inBuffer.data(), inSize, nullptr); if (LZ4F_isError(rc)) { LOG(ERROR) << "LZ4F_compressUpdate failed: " << LZ4F_getErrorName(rc); return false; } outBuffer.resize(prvSize + rc); } if (outBuffer.size() > LZ4_BUFFER_SIZE) { return writeToFile(outBuffer, fdOut); } return true; } static jboolean nativeCompressLz4(JNIEnv* env, jclass klass, jint fdIn, jint fdOut) { LZ4F_cctx* cctx; if (LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) != 0) { LOG(ERROR) << "Failed to initialize LZ4 compression context."; return false; } std::unique_ptr<LZ4F_cctx, LZ4FCContextDeleter> context(cctx); std::vector<char> inBuffer, outBuffer; inBuffer.reserve(LZ4_BUFFER_SIZE); outBuffer.reserve(2 * LZ4_BUFFER_SIZE); LZ4F_preferences_t prefs; memset(&prefs, 0, sizeof(prefs)); // Set compression parameters. prefs.autoFlush = 0; prefs.compressionLevel = 0; prefs.frameInfo.blockMode = LZ4F_blockLinked; prefs.frameInfo.blockSizeID = LZ4F_default; prefs.frameInfo.blockChecksumFlag = LZ4F_noBlockChecksum; prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; prefs.favorDecSpeed = 0; struct stat sb; if (fstat(fdIn, &sb) == -1) { PLOG(ERROR) << "Failed to obtain input file size."; return false; } prefs.frameInfo.contentSize = sb.st_size; // Write header first. outBuffer.resize(LZ4F_HEADER_SIZE_MAX); auto rc = LZ4F_compressBegin(context.get(), outBuffer.data(), outBuffer.size(), &prefs); if (LZ4F_isError(rc)) { LOG(ERROR) << "LZ4F_compressBegin failed: " << LZ4F_getErrorName(rc); return false; } outBuffer.resize(rc); bool eof = false; while (!eof) { constexpr auto capacity = LZ4_BUFFER_SIZE; inBuffer.resize(capacity); auto read = TEMP_FAILURE_RETRY(::read(fdIn, inBuffer.data(), inBuffer.size())); if (read < 0) { PLOG(ERROR) << "Failed to read from input file."; return false; } inBuffer.resize(read); if (read == 0) { eof = true; } if (!compressAndWriteLz4(context.get(), inBuffer, outBuffer, fdOut)) { return false; } } // Footer. auto prvSize = outBuffer.size(); outBuffer.resize(outBuffer.capacity()); rc = LZ4F_compressEnd(context.get(), outBuffer.data() + prvSize, outBuffer.size() - prvSize, nullptr); if (LZ4F_isError(rc)) { LOG(ERROR) << "LZ4F_compressEnd failed: " << LZ4F_getErrorName(rc); return false; } outBuffer.resize(prvSize + rc); if (!writeToFile(outBuffer, fdOut)) { return false; } return true; } static const JNINativeMethod method_table[] = { {"nativeCompressLz4", "(II)Z", (void*)nativeCompressLz4}, }; } // namespace int register_android_server_com_android_server_pm_Settings(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/server/pm/Settings", method_table, NELEM(method_table)); } } // namespace android
services/core/jni/onload.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ int register_android_server_am_LowMemDetector(JNIEnv* env); int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(JNIEnv* env); int register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(JNIEnv* env); int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env); int register_android_server_com_android_server_pm_Settings(JNIEnv* env); int register_android_server_AdbDebuggingManager(JNIEnv* env); int register_android_server_FaceService(JNIEnv* env); int register_android_server_GpuService(JNIEnv* env); Loading Loading @@ -114,6 +115,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(env); register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(env); register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env); register_android_server_com_android_server_pm_Settings(env); register_android_server_AdbDebuggingManager(env); register_android_server_FaceService(env); register_android_server_GpuService(env); Loading
services/core/jni/onload_settings.cpp 0 → 100644 +39 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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 "jni.h" #include "utils/Log.h" namespace android { int register_android_server_com_android_server_pm_Settings(JNIEnv* env); }; using namespace android; extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("GetEnv failed!"); return result; } ALOG_ASSERT(env, "Could not retrieve the env!"); register_android_server_com_android_server_pm_Settings(env); return JNI_VERSION_1_4; }