2011-04-13 15:39:37 -07:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
#define LOG_TAG "AndroidRuntime"
|
|
|
|
//#define LOG_NDEBUG 0
|
|
|
|
|
|
|
|
#include <android_runtime/AndroidRuntime.h>
|
2009-05-19 19:08:10 -07:00
|
|
|
#include <binder/IBinder.h>
|
2010-12-13 16:52:35 -08:00
|
|
|
#include <binder/IPCThreadState.h>
|
2009-05-19 19:08:10 -07:00
|
|
|
#include <binder/IServiceManager.h>
|
2009-03-03 19:31:44 -08:00
|
|
|
#include <utils/Log.h>
|
|
|
|
#include <utils/misc.h>
|
2009-05-19 19:08:10 -07:00
|
|
|
#include <binder/Parcel.h>
|
2009-03-03 19:31:44 -08:00
|
|
|
#include <utils/threads.h>
|
|
|
|
#include <cutils/properties.h>
|
|
|
|
|
|
|
|
#include <SkGraphics.h>
|
|
|
|
#include <SkImageDecoder.h>
|
|
|
|
|
|
|
|
#include "jni.h"
|
|
|
|
#include "JNIHelp.h"
|
2013-06-19 13:49:36 -07:00
|
|
|
#include "JniInvocation.h"
|
2009-03-03 19:31:44 -08:00
|
|
|
#include "android_util_Binder.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
|
|
using namespace android;
|
|
|
|
|
|
|
|
extern int register_android_os_Binder(JNIEnv* env);
|
|
|
|
extern int register_android_os_Process(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_Bitmap(JNIEnv*);
|
|
|
|
extern int register_android_graphics_BitmapFactory(JNIEnv*);
|
2010-09-07 17:32:18 +08:00
|
|
|
extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_graphics_Camera(JNIEnv* env);
|
2013-09-06 16:46:57 -04:00
|
|
|
extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_graphics_Graphics(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_Interpolator(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_MaskFilter(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_Movie(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_NinePatch(JNIEnv*);
|
|
|
|
extern int register_android_graphics_PathEffect(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_Shader(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_Typeface(JNIEnv* env);
|
2009-11-30 17:52:05 +08:00
|
|
|
extern int register_android_graphics_YuvImage(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
extern int register_com_google_android_gles_jni_EGLImpl(JNIEnv* env);
|
|
|
|
extern int register_com_google_android_gles_jni_GLImpl(JNIEnv* env);
|
2012-07-03 13:37:35 -07:00
|
|
|
extern int register_android_opengl_jni_EGL14(JNIEnv* env);
|
2013-05-06 11:36:57 -07:00
|
|
|
extern int register_android_opengl_jni_EGLExt(JNIEnv* env);
|
Manually merge 129, 174, and 233 from donut
This adds a static OpenGL ES API.
Here are the three commit messages for the original changes:
Clean up trivial Eclipse warnings and fix whitespace.
Added @Override to overridden methods.
Removed unused imports.
Converted tabs to spaces.
Removed \r characters from end-of-lines.
Add .gitignore file to ignore the .class files that are
generated when the "gen" script is run.
This is the 2nd commit message:
Improve glgen
+ gen script is really a bash script rather than a sh script,
so declare that to be true. (For example, it uses pushd,
which is a part of bash, but not a part of sh. Not sure
how this worked until now. Possibly gen was only run in
environments where /bin/sh was really bash.
+ Check the results of the java compile of the code generator,
and abort the script if the compile fails.
+ Turn on the bash shell option that guards against using
uninitialized variables in the script.
+ Remove the generated class files.
Refactor JniCodeEmitter into two classes: a general-purpose
JniCodeEmitter and a specific Jsr239CodeEmitter. The hope is
to use JniCodeEmitter as a base for emitting static OpenGL ES
bindings.
This is the 3rd commit message:
Add an Android-specific static OpenGL ES 1.1 Java API.
This change adds four new public classes that expose a static OpenGL ES 1.1 API:
android.opengl.GLES10
android.opengl.GLES10Ext
android.opengl.GLES11
android.opengl.GLES11Ext
Benefits:
+ The static API is slightly faster (1% to 4%) than the existing Interface based JSR239 API.
+ The static API is similar to the C API, which should make it easier to import C-based
example code.
+ The static API provides a clear path for adding new OpenGL ES 1.1 extensions
and OpenGL ES 2.0 APIs, neither of which currently have a JSR standard.
Example:
import static android.opengl.GLES10.*;
...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Note that it is possible to mix-and-match calls to both the static and JSR239 APIs.
This works because neither API maintains state. They both call through to the same underlying
C OpenGL ES APIs.
Implementation details:
This change enhances the "glgen" "gen" script to generate both the original JSR239 and
new static OpenGL ES APIs. The contents of the generated JSR239 classes remained the same as before,
so there is no need to check in new versions of the generated JSR239 classes.
As part of this work the gen script was updated to be somewhat more robust, and to
work with git instead of perforce. The script prints out commands to git add the generated files,
but leaves it up to the script runner to actually execute those commands.
2009-04-13 16:22:25 -07:00
|
|
|
extern int register_android_opengl_jni_GLES10(JNIEnv* env);
|
|
|
|
extern int register_android_opengl_jni_GLES10Ext(JNIEnv* env);
|
|
|
|
extern int register_android_opengl_jni_GLES11(JNIEnv* env);
|
|
|
|
extern int register_android_opengl_jni_GLES11Ext(JNIEnv* env);
|
2009-11-19 16:34:55 +08:00
|
|
|
extern int register_android_opengl_jni_GLES20(JNIEnv* env);
|
2013-04-29 15:59:35 -07:00
|
|
|
extern int register_android_opengl_jni_GLES30(JNIEnv* env);
|
2014-05-19 15:13:41 -07:00
|
|
|
extern int register_android_opengl_jni_GLES31(JNIEnv* env);
|
|
|
|
extern int register_android_opengl_jni_GLES31Ext(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
extern int register_android_hardware_Camera(JNIEnv *env);
|
2013-07-25 17:12:05 -07:00
|
|
|
extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env);
|
2014-05-09 19:58:49 -07:00
|
|
|
extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env);
|
2014-05-29 17:17:07 -07:00
|
|
|
extern int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv *env);
|
2014-05-22 12:33:54 -07:00
|
|
|
extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_hardware_SensorManager(JNIEnv *env);
|
2011-08-29 20:11:07 -04:00
|
|
|
extern int register_android_hardware_SerialPort(JNIEnv *env);
|
2014-04-18 17:50:49 -07:00
|
|
|
extern int register_android_hardware_SoundTrigger(JNIEnv *env);
|
2010-12-30 13:39:37 -05:00
|
|
|
extern int register_android_hardware_UsbDevice(JNIEnv *env);
|
2011-03-11 08:18:08 -05:00
|
|
|
extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
|
2010-12-30 13:39:37 -05:00
|
|
|
extern int register_android_hardware_UsbRequest(JNIEnv *env);
|
2014-07-09 10:46:39 -07:00
|
|
|
extern int register_android_hardware_location_ActivityRecognitionHardware(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
extern int register_android_media_AudioRecord(JNIEnv *env);
|
|
|
|
extern int register_android_media_AudioSystem(JNIEnv *env);
|
|
|
|
extern int register_android_media_AudioTrack(JNIEnv *env);
|
|
|
|
extern int register_android_media_JetPlayer(JNIEnv *env);
|
|
|
|
extern int register_android_media_ToneGenerator(JNIEnv *env);
|
|
|
|
|
|
|
|
extern int register_android_util_FloatMath(JNIEnv* env);
|
|
|
|
|
|
|
|
namespace android {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* JNI-based registration functions. Note these are properly contained in
|
|
|
|
* namespace android.
|
|
|
|
*/
|
|
|
|
extern int register_android_content_AssetManager(JNIEnv* env);
|
|
|
|
extern int register_android_util_EventLog(JNIEnv* env);
|
|
|
|
extern int register_android_util_Log(JNIEnv* env);
|
|
|
|
extern int register_android_content_StringBlock(JNIEnv* env);
|
|
|
|
extern int register_android_content_XmlBlock(JNIEnv* env);
|
2009-03-09 11:52:12 -07:00
|
|
|
extern int register_android_emoji_EmojiFactory(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_graphics_Canvas(JNIEnv* env);
|
2014-05-01 21:27:37 -07:00
|
|
|
extern int register_android_graphics_CanvasProperty(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_graphics_ColorFilter(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_DrawFilter(JNIEnv* env);
|
2014-01-30 16:06:28 -08:00
|
|
|
extern int register_android_graphics_FontFamily(JNIEnv* env);
|
2014-05-07 11:48:37 -04:00
|
|
|
extern int register_android_graphics_LayerRasterizer(JNIEnv*);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_graphics_Matrix(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_Paint(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_Path(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_PathMeasure(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_Picture(JNIEnv*);
|
|
|
|
extern int register_android_graphics_PorterDuff(JNIEnv* env);
|
|
|
|
extern int register_android_graphics_Rasterizer(JNIEnv* env);
|
2011-01-16 14:06:57 -08:00
|
|
|
extern int register_android_graphics_Region(JNIEnv* env);
|
2011-01-06 17:04:26 -08:00
|
|
|
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_graphics_Xfermode(JNIEnv* env);
|
2013-09-18 15:58:28 -07:00
|
|
|
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
|
2014-09-04 21:17:17 -07:00
|
|
|
extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
|
2014-04-24 18:40:42 -07:00
|
|
|
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
|
2011-12-02 02:25:22 -08:00
|
|
|
extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
|
2014-03-14 16:24:57 -07:00
|
|
|
extern int register_android_view_RenderNode(JNIEnv* env);
|
2014-04-15 09:50:16 -07:00
|
|
|
extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
extern int register_android_view_GraphicBuffer(JNIEnv* env);
|
2010-06-16 18:44:05 -07:00
|
|
|
extern int register_android_view_GLES20Canvas(JNIEnv* env);
|
2014-02-05 16:38:25 -08:00
|
|
|
extern int register_android_view_HardwareLayer(JNIEnv* env);
|
2013-11-05 13:27:50 -08:00
|
|
|
extern int register_android_view_ThreadedRenderer(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_view_Surface(JNIEnv* env);
|
2013-02-11 22:08:48 -08:00
|
|
|
extern int register_android_view_SurfaceControl(JNIEnv* env);
|
2012-08-26 02:47:39 -07:00
|
|
|
extern int register_android_view_SurfaceSession(JNIEnv* env);
|
2011-05-02 17:24:22 -07:00
|
|
|
extern int register_android_view_TextureView(JNIEnv* env);
|
2014-05-09 19:21:04 -07:00
|
|
|
extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_database_CursorWindow(JNIEnv* env);
|
Rewrite SQLite database wrappers.
The main theme of this change is encapsulation. This change
preserves all existing functionality but the implementation
is now much cleaner.
Instead of a "database lock", access to the database is treated
as a resource acquisition problem. If a thread's owns a database
connection, then it can access the database; otherwise, it must
acquire a database connection first, and potentially wait for other
threads to give up theirs. The SQLiteConnectionPool encapsulates
the details of how connections are created, configured, acquired,
released and disposed.
One new feature is that SQLiteConnectionPool can make scheduling
decisions about which thread should next acquire a database
connection when there is contention among threads. The factors
considered include wait queue ordering (fairness among peers),
whether the connection is needed for an interactive operation
(unfairness on behalf of the UI), and whether the primary connection
is needed or if any old connection will do. Thus one goal of the
new SQLiteConnectionPool is to improve the utilization of
database connections.
To emulate some quirks of the old "database lock," we introduce
the concept of the primary database connection. The primary
database connection is the one that is typically used to perform
write operations to the database. When a thread holds the primary
database connection, it effectively prevents other threads from
modifying the database (although they can still read). What's
more, those threads will block when they try to acquire the primary
connection, which provides the same kind of mutual exclusion
features that the old "database lock" had. (In truth, we
probably don't need to be requiring use of the primary database
connection in as many places as we do now, but we can seek to refine
that behavior in future patches.)
Another significant change is that native sqlite3_stmt objects
(prepared statements) are fully encapsulated by the SQLiteConnection
object that owns them. This ensures that the connection can
finalize (destroy) all extant statements that belong to a database
connection when the connection is closed. (In the original code,
this was very complicated because the sqlite3_stmt objects were
managed by SQLiteCompiledSql objects which had different lifetime
from the original SQLiteDatabase that created them. Worse, the
SQLiteCompiledSql finalizer method couldn't actually destroy the
sqlite3_stmt objects because it ran on the finalizer thread and
therefore could not guarantee that it could acquire the database
lock in order to do the work. This resulted in some rather
tortured logic involving a list of pending finalizable statements
and a high change of deadlocks or leaks.)
Because sqlite3_stmt objects never escape the confines of the
SQLiteConnection that owns them, we can also greatly simplify
the design of the SQLiteProgram, SQLiteQuery and SQLiteStatement
objects. They no longer have to wrangle a native sqlite3_stmt
object pointer and manage its lifecycle. So now all they do
is hold bind arguments and provide a fancy API.
All of the JNI glue related to managing database connections
and performing transactions is now bound to SQLiteConnection
(rather than being scattered everywhere). This makes sense because
SQLiteConnection owns the native sqlite3 object, so it is the
only class in the system that can interact with the native
SQLite database directly. Encapsulation for the win.
One particularly tricky part of this change is managing the
ownership of SQLiteConnection objects. At any given time,
a SQLiteConnection is either owned by a SQLiteConnectionPool
or by a SQLiteSession. SQLiteConnections should never be leaked,
but we handle that case too (and yell about it with CloseGuard).
A SQLiteSession object is responsible for acquiring and releasing
a SQLiteConnection object on behalf of a single thread as needed.
For example, the session acquires a connection when a transaction
begins and releases it when finished. If the session cannot
acquire a connection immediately, then the requested operation
blocks until a connection becomes available.
SQLiteSessions are thread-local. A SQLiteDatabase assigns a
distinct session to each thread that performs database operations.
This is very very important. First, it prevents two threads
from trying to use the same SQLiteConnection at the same time
(because two threads can't share the same session).
Second, it prevents a single thread from trying to acquire two
SQLiteConnections simultaneously from the same database (because
a single thread can't have two sessions for the same database which,
in addition to being greedy, could result in a deadlock).
There is strict layering between the various database objects,
objects at lower layers are not aware of objects at higher layers.
Moreover, objects at higher layers generally own objects at lower
layers and are responsible for ensuring they are properly disposed
when no longer needed (good for the environment).
API layer: SQLiteDatabase, SQLiteProgram, SQLiteQuery, SQLiteStatement.
Session layer: SQLiteSession.
Connection layer: SQLiteConnectionPool, SQLiteConnection.
Native layer: JNI glue.
By avoiding cyclic dependencies between layers, we make the
architecture much more intelligible, maintainable and robust.
Finally, this change adds a great deal of new debugging information.
It is now possible to view a list of the most recent database
operations including how long they took to run using
"adb shell dumpsys dbinfo". (Because most of the interesting
work happens in SQLiteConnection, it is easy to add debugging
instrumentation to track all database operations in one place.)
Change-Id: Iffb4ce72d8bcf20b4e087d911da6aa84d2f15297
2011-10-31 17:48:13 -07:00
|
|
|
extern int register_android_database_SQLiteConnection(JNIEnv* env);
|
|
|
|
extern int register_android_database_SQLiteGlobal(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_database_SQLiteDebug(JNIEnv* env);
|
|
|
|
extern int register_android_nio_utils(JNIEnv* env);
|
|
|
|
extern int register_android_os_Debug(JNIEnv* env);
|
2010-05-06 12:07:10 -07:00
|
|
|
extern int register_android_os_MessageQueue(JNIEnv* env);
|
2012-03-06 18:26:19 -08:00
|
|
|
extern int register_android_os_Parcel(JNIEnv* env);
|
2012-01-13 08:31:39 -05:00
|
|
|
extern int register_android_os_SELinux(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_os_SystemProperties(JNIEnv *env);
|
|
|
|
extern int register_android_os_SystemClock(JNIEnv* env);
|
2012-03-09 14:41:15 -08:00
|
|
|
extern int register_android_os_Trace(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_os_FileObserver(JNIEnv *env);
|
|
|
|
extern int register_android_os_UEventObserver(JNIEnv* env);
|
|
|
|
extern int register_android_os_MemoryFile(JNIEnv* env);
|
|
|
|
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
|
|
|
|
extern int register_android_net_NetworkUtils(JNIEnv* env);
|
2010-04-07 17:30:50 -07:00
|
|
|
extern int register_android_net_TrafficStats(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_text_AndroidCharacter(JNIEnv *env);
|
2014-06-24 14:39:43 -07:00
|
|
|
extern int register_android_text_StaticLayout(JNIEnv *env);
|
2010-02-24 14:33:15 -08:00
|
|
|
extern int register_android_text_AndroidBidi(JNIEnv *env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_android_opengl_classes(JNIEnv *env);
|
|
|
|
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
|
2014-08-07 10:57:40 +01:00
|
|
|
extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
|
2009-03-03 19:31:44 -08:00
|
|
|
extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
|
2009-06-12 11:06:24 -07:00
|
|
|
extern int register_android_backup_BackupDataInput(JNIEnv *env);
|
2009-05-19 13:41:21 -07:00
|
|
|
extern int register_android_backup_BackupDataOutput(JNIEnv *env);
|
2009-06-18 20:10:37 -07:00
|
|
|
extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
|
2009-06-25 18:29:18 -04:00
|
|
|
extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env);
|
Full local backup infrastructure
This is the basic infrastructure for pulling a full(*) backup of the
device's data over an adb(**) connection to the local device. The
basic process consists of these interacting pieces:
1. The framework's BackupManagerService, which coordinates the
collection of app data and routing to the destination.
2. A new framework-provided BackupAgent implementation called
FullBackupAgent, which is instantiated in the target applications'
processes in turn, and knows how to emit a datastream that contains
all of the app's saved data files.
3. A new shell-level program called "bu" that is used to bridge from
adb to the framework's Backup Manager.
4. adb itself, which now knows how to use 'bu' to kick off a backup
operation and pull the resulting data stream to the desktop host.
5. A system-provided application that verifies with the user that
an attempted backup/restore operation is in fact expected and to
be allowed.
The full agent implementation is not used during normal operation of
the delta-based app-customized remote backup process. Instead it's
used during user-confirmed *full* backup of applications and all their
data to a local destination, e.g. via the adb connection.
The output format is 'tar'. This makes it very easy for the end
user to examine the resulting dataset, e.g. for purpose of extracting
files for debug purposes; as well as making it easy to contemplate
adding things like a direct gzip stage to the data pipeline during
backup/restore. It also makes it convenient to construct and maintain
synthetic backup datasets for testing purposes.
Within the tar format, certain artificial conventions are used.
All files are stored within top-level directories according to
their semantic origin:
apps/pkgname/a/ : Application .apk file itself
apps/pkgname/obb/: The application's associated .obb containers
apps/pkgname/f/ : The subtree rooted at the getFilesDir() location
apps/pkgname/db/ : The subtree rooted at the getDatabasePath() parent
apps/pkgname/sp/ : The subtree rooted at the getSharedPrefsFile() parent
apps/pkgname/r/ : Files stored relative to the root of the app's file tree
apps/pkgname/c/ : Reserved for the app's getCacheDir() tree; not stored.
For each package, the first entry in the tar stream is a file called
"_manifest", nominally rooted at apps/pkgname. This file contains some
metadata about the package whose data is stored in the archive.
The contents of shared storage can optionally be included in the tar
stream. It is placed in the synthetic location:
shared/...
uid/gid are ignored; app uids are assigned at install time, and the
app's data is handled from within its own execution environment, so
will automatically have the app's correct uid.
Forward-locked .apk files are never backed up. System-partition
.apk files are not backed up unless they have been overridden by a
post-factory upgrade, in which case the current .apk *is* backed up --
i.e. the .apk that matches the on-disk data. The manifest preceding
each application's portion of the tar stream provides version numbers
and signature blocks for version checking, as well as an indication
of whether the restore logic should expect to install the .apk before
extracting the data.
System packages can designate their own full backup agents. This is
to manage things like the settings provider which (a) cannot be shut
down on the fly in order to do a clean snapshot of their file trees,
and (b) manage data that is not only irrelevant but actively hostile
to non-identical devices -- CDMA telephony settings would seriously
mess up a GSM device if emplaced there blind, for example.
When a full backup or restore is initiated from adb, the system will
present a confirmation UI that the user must explicitly respond to
within a short [~ 30 seconds] timeout. This is to avoid the
possibility of malicious desktop-side software secretly grabbing a copy
of all the user's data for nefarious purposes.
(*) The backup is not strictly a full mirror. In particular, the
settings database is not cloned; it is handled the same way that
it is in cloud backup/restore. This is because some settings
are actively destructive if cloned onto a different (or
especially a different-model) device: telephony settings and
AndroidID are good examples of this.
(**) On the framework side it doesn't care that it's adb; it just
sends the tar stream to a file descriptor. This can easily be
retargeted around whatever transport we might decide to use
in the future.
KNOWN ISSUES:
* the security UI is desperately ugly; no proper designs have yet
been done for it
* restore is not yet implemented
* shared storage backup is not yet implemented
* symlinks aren't yet handled, though some infrastructure for
dealing with them has been put in place.
Change-Id: Ia8347611e23b398af36ea22c36dff0a276b1ce91
2011-04-01 14:43:32 -07:00
|
|
|
extern int register_android_app_backup_FullBackup(JNIEnv *env);
|
2011-03-24 10:51:31 -07:00
|
|
|
extern int register_android_app_ActivityThread(JNIEnv *env);
|
2010-05-04 11:40:40 -07:00
|
|
|
extern int register_android_app_NativeActivity(JNIEnv *env);
|
2012-09-04 21:57:59 -07:00
|
|
|
extern int register_android_media_RemoteDisplay(JNIEnv *env);
|
Native input dispatch rewrite work in progress.
The old dispatch mechanism has been left in place and continues to
be used by default for now. To enable native input dispatch,
edit the ENABLE_NATIVE_DISPATCH constant in WindowManagerPolicy.
Includes part of the new input event NDK API. Some details TBD.
To wire up input dispatch, as the ViewRoot adds a window to the
window session it receives an InputChannel object as an output
argument. The InputChannel encapsulates the file descriptors for a
shared memory region and two pipe end-points. The ViewRoot then
provides the InputChannel to the InputQueue. Behind the
scenes, InputQueue simply attaches handlers to the native PollLoop object
that underlies the MessageQueue. This way MessageQueue doesn't need
to know anything about input dispatch per-se, it just exposes (in native
code) a PollLoop that other components can use to monitor file descriptor
state changes.
There can be zero or more targets for any given input event. Each
input target is specified by its input channel and some parameters
including flags, an X/Y coordinate offset, and the dispatch timeout.
An input target can request either synchronous dispatch (for foreground apps)
or asynchronous dispatch (fire-and-forget for wallpapers and "outside"
targets). Currently, finding the appropriate input targets for an event
requires a call back into the WindowManagerServer from native code.
In the future this will be refactored to avoid most of these callbacks
except as required to handle pending focus transitions.
End-to-end event dispatch mostly works!
To do: event injection, rate limiting, ANRs, testing, optimization, etc.
Change-Id: I8c36b2b9e0a2d27392040ecda0f51b636456de25
2010-04-22 18:58:52 -07:00
|
|
|
extern int register_android_view_InputChannel(JNIEnv* env);
|
2012-04-10 14:30:49 -07:00
|
|
|
extern int register_android_view_InputDevice(JNIEnv* env);
|
2011-12-01 14:01:49 -08:00
|
|
|
extern int register_android_view_InputEventReceiver(JNIEnv* env);
|
2013-03-26 15:42:39 -07:00
|
|
|
extern int register_android_view_InputEventSender(JNIEnv* env);
|
2013-04-10 21:12:00 -07:00
|
|
|
extern int register_android_view_InputQueue(JNIEnv* env);
|
2012-04-10 14:30:49 -07:00
|
|
|
extern int register_android_view_KeyCharacterMap(JNIEnv *env);
|
Native input dispatch rewrite work in progress.
The old dispatch mechanism has been left in place and continues to
be used by default for now. To enable native input dispatch,
edit the ENABLE_NATIVE_DISPATCH constant in WindowManagerPolicy.
Includes part of the new input event NDK API. Some details TBD.
To wire up input dispatch, as the ViewRoot adds a window to the
window session it receives an InputChannel object as an output
argument. The InputChannel encapsulates the file descriptors for a
shared memory region and two pipe end-points. The ViewRoot then
provides the InputChannel to the InputQueue. Behind the
scenes, InputQueue simply attaches handlers to the native PollLoop object
that underlies the MessageQueue. This way MessageQueue doesn't need
to know anything about input dispatch per-se, it just exposes (in native
code) a PollLoop that other components can use to monitor file descriptor
state changes.
There can be zero or more targets for any given input event. Each
input target is specified by its input channel and some parameters
including flags, an X/Y coordinate offset, and the dispatch timeout.
An input target can request either synchronous dispatch (for foreground apps)
or asynchronous dispatch (fire-and-forget for wallpapers and "outside"
targets). Currently, finding the appropriate input targets for an event
requires a call back into the WindowManagerServer from native code.
In the future this will be refactored to avoid most of these callbacks
except as required to handle pending focus transitions.
End-to-end event dispatch mostly works!
To do: event injection, rate limiting, ANRs, testing, optimization, etc.
Change-Id: I8c36b2b9e0a2d27392040ecda0f51b636456de25
2010-04-22 18:58:52 -07:00
|
|
|
extern int register_android_view_KeyEvent(JNIEnv* env);
|
|
|
|
extern int register_android_view_MotionEvent(JNIEnv* env);
|
2011-04-12 22:39:53 -07:00
|
|
|
extern int register_android_view_PointerIcon(JNIEnv* env);
|
2011-03-14 19:39:54 -07:00
|
|
|
extern int register_android_view_VelocityTracker(JNIEnv* env);
|
2010-07-01 08:10:18 -07:00
|
|
|
extern int register_android_content_res_ObbScanner(JNIEnv* env);
|
2010-08-04 11:12:40 -07:00
|
|
|
extern int register_android_content_res_Configuration(JNIEnv* env);
|
2010-11-03 19:41:18 -07:00
|
|
|
extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
|
2011-07-12 14:14:01 -07:00
|
|
|
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
|
2013-01-14 16:48:51 -08:00
|
|
|
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
|
2014-03-31 13:41:26 +01:00
|
|
|
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
|
2014-05-09 15:26:59 -07:00
|
|
|
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
static AndroidRuntime* gCurRuntime = NULL;
|
|
|
|
|
|
|
|
static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
|
|
|
|
{
|
|
|
|
if (jniThrowException(env, exc, msg) != 0)
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Code written in the Java Programming Language calls here from main().
|
|
|
|
*/
|
2012-03-15 16:53:55 -07:00
|
|
|
static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz)
|
2009-03-03 19:31:44 -08:00
|
|
|
{
|
|
|
|
gCurRuntime->onStarted();
|
|
|
|
}
|
|
|
|
|
2012-03-15 16:53:55 -07:00
|
|
|
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
|
2009-03-03 19:31:44 -08:00
|
|
|
{
|
|
|
|
gCurRuntime->onZygoteInit();
|
|
|
|
}
|
|
|
|
|
2012-03-15 17:48:02 -07:00
|
|
|
static void com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup(JNIEnv* env,
|
|
|
|
jobject clazz, jboolean exitWithoutCleanup)
|
|
|
|
{
|
|
|
|
gCurRuntime->setExitWithoutCleanup(exitWithoutCleanup);
|
|
|
|
}
|
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
/*
|
|
|
|
* JNI registration.
|
|
|
|
*/
|
|
|
|
static JNINativeMethod gMethods[] = {
|
2012-03-15 16:53:55 -07:00
|
|
|
{ "nativeFinishInit", "()V",
|
|
|
|
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
|
|
|
|
{ "nativeZygoteInit", "()V",
|
|
|
|
(void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
|
2012-03-15 17:48:02 -07:00
|
|
|
{ "nativeSetExitWithoutCleanup", "(Z)V",
|
|
|
|
(void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
|
2009-03-03 19:31:44 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
|
|
|
|
{
|
|
|
|
return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
|
|
|
|
gMethods, NELEM(gMethods));
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
|
2014-02-13 17:22:33 +00:00
|
|
|
/*static*/ JavaVM* AndroidRuntime::mJavaVM = NULL;
|
|
|
|
|
2014-03-28 13:39:21 +00:00
|
|
|
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
|
|
|
|
mExitWithoutCleanup(false),
|
|
|
|
mArgBlockStart(argBlockStart),
|
|
|
|
mArgBlockLength(argBlockLength)
|
2009-03-03 19:31:44 -08:00
|
|
|
{
|
2009-03-11 12:11:56 -07:00
|
|
|
SkGraphics::Init();
|
2009-04-27 11:43:30 -04:00
|
|
|
// There is also a global font cache, but its budget is specified in code
|
|
|
|
// see SkFontHost_android.cpp
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
// Pre-allocate enough space to hold a fair number of options.
|
|
|
|
mOptions.setCapacity(20);
|
|
|
|
|
|
|
|
assert(gCurRuntime == NULL); // one per process
|
|
|
|
gCurRuntime = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidRuntime::~AndroidRuntime()
|
|
|
|
{
|
|
|
|
SkGraphics::Term();
|
|
|
|
}
|
|
|
|
|
2014-02-13 17:22:33 +00:00
|
|
|
/*
|
|
|
|
* Register native methods using JNI.
|
|
|
|
*/
|
|
|
|
/*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
|
|
|
|
const char* className, const JNINativeMethod* gMethods, int numMethods)
|
|
|
|
{
|
|
|
|
return jniRegisterNativeMethods(env, className, gMethods, numMethods);
|
|
|
|
}
|
|
|
|
|
2014-03-28 13:39:21 +00:00
|
|
|
void AndroidRuntime::setArgv0(const char* argv0) {
|
2014-09-10 16:48:46 -07:00
|
|
|
memset(mArgBlockStart, 0, mArgBlockLength);
|
2014-03-28 13:39:21 +00:00
|
|
|
strlcpy(mArgBlockStart, argv0, mArgBlockLength);
|
|
|
|
}
|
|
|
|
|
2014-04-07 12:44:58 +01:00
|
|
|
status_t AndroidRuntime::callMain(const String8& className, jclass clazz,
|
|
|
|
const Vector<String8>& args)
|
2009-03-03 19:31:44 -08:00
|
|
|
{
|
|
|
|
JNIEnv* env;
|
|
|
|
jmethodID methodId;
|
|
|
|
|
2014-04-07 12:44:58 +01:00
|
|
|
ALOGD("Calling main entry %s", className.string());
|
2010-09-01 18:17:17 -07:00
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
env = getJNIEnv();
|
2011-04-13 15:39:37 -07:00
|
|
|
if (clazz == NULL || env == NULL) {
|
2009-03-03 19:31:44 -08:00
|
|
|
return UNKNOWN_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
methodId = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
|
|
|
|
if (methodId == NULL) {
|
2014-04-07 12:44:58 +01:00
|
|
|
ALOGE("ERROR: could not find method %s.main(String[])\n", className.string());
|
2009-03-03 19:31:44 -08:00
|
|
|
return UNKNOWN_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We want to call main() with a String array with our arguments in it.
|
|
|
|
* Create an array and populate it.
|
|
|
|
*/
|
|
|
|
jclass stringClass;
|
|
|
|
jobjectArray strArray;
|
|
|
|
|
2014-04-07 12:44:58 +01:00
|
|
|
const size_t numArgs = args.size();
|
2009-03-03 19:31:44 -08:00
|
|
|
stringClass = env->FindClass("java/lang/String");
|
2014-04-07 12:44:58 +01:00
|
|
|
strArray = env->NewObjectArray(numArgs, stringClass, NULL);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
2014-04-07 12:44:58 +01:00
|
|
|
for (size_t i = 0; i < numArgs; i++) {
|
|
|
|
jstring argStr = env->NewStringUTF(args[i].string());
|
2009-03-03 19:31:44 -08:00
|
|
|
env->SetObjectArrayElement(strArray, i, argStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
env->CallStaticVoidMethod(clazz, methodId, strArray);
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The VM calls this through the "exit" hook.
|
|
|
|
*/
|
|
|
|
static void runtime_exit(int code)
|
|
|
|
{
|
2012-03-15 17:48:02 -07:00
|
|
|
gCurRuntime->exit(code);
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The VM calls this through the "vfprintf" hook.
|
|
|
|
*
|
|
|
|
* We ignore "fp" and just write the results to the log file.
|
|
|
|
*/
|
|
|
|
static void runtime_vfprintf(FILE* fp, const char* format, va_list ap)
|
|
|
|
{
|
|
|
|
LOG_PRI_VA(ANDROID_LOG_INFO, "vm-printf", format, ap);
|
|
|
|
}
|
|
|
|
|
2010-12-13 16:52:35 -08:00
|
|
|
/**
|
|
|
|
* The VM calls this when mutex contention debugging is enabled to
|
|
|
|
* determine whether or not the blocked thread was a "sensitive thread"
|
|
|
|
* for user responsiveness/smoothess.
|
|
|
|
*
|
|
|
|
* Our policy for this is whether or not we're tracing any StrictMode
|
|
|
|
* events on this thread (which we might've inherited via Binder calls
|
|
|
|
* into us)
|
|
|
|
*/
|
|
|
|
static bool runtime_isSensitiveThread() {
|
|
|
|
IPCThreadState* state = IPCThreadState::selfOrNull();
|
|
|
|
return state && state->getStrictModePolicy() != 0;
|
|
|
|
}
|
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
static int hasDir(const char* dir)
|
|
|
|
{
|
|
|
|
struct stat s;
|
|
|
|
int res = stat(dir, &s);
|
|
|
|
if (res == 0) {
|
|
|
|
return S_ISDIR(s.st_mode);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the persistent locale.
|
|
|
|
*/
|
|
|
|
static void readLocale(char* language, char* region)
|
|
|
|
{
|
|
|
|
char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX];
|
2010-08-24 21:27:52 -07:00
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
property_get("persist.sys.language", propLang, "");
|
|
|
|
property_get("persist.sys.country", propRegn, "");
|
|
|
|
if (*propLang == 0 && *propRegn == 0) {
|
|
|
|
/* Set to ro properties, default is en_US */
|
|
|
|
property_get("ro.product.locale.language", propLang, "en");
|
|
|
|
property_get("ro.product.locale.region", propRegn, "US");
|
|
|
|
}
|
2014-07-01 12:44:51 +01:00
|
|
|
strncat(language, propLang, 3);
|
|
|
|
strncat(region, propRegn, 3);
|
2011-12-20 16:23:08 +00:00
|
|
|
//ALOGD("language=%s region=%s\n", language, region);
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
|
2014-07-30 12:11:41 -07:00
|
|
|
void AndroidRuntime::addOption(const char* optionString, void* extraInfo)
|
|
|
|
{
|
|
|
|
JavaVMOption opt;
|
|
|
|
opt.optionString = optionString;
|
|
|
|
opt.extraInfo = extraInfo;
|
|
|
|
mOptions.add(opt);
|
|
|
|
}
|
|
|
|
|
2010-07-14 16:02:20 -07:00
|
|
|
/*
|
|
|
|
* Parse a property containing space-separated options that should be
|
|
|
|
* passed directly to the VM, e.g. "-Xmx32m -verbose:gc -Xregenmap".
|
|
|
|
*
|
|
|
|
* This will cut up "extraOptsBuf" as we chop it into individual options.
|
|
|
|
*
|
2014-02-28 23:27:22 -08:00
|
|
|
* If "quotingArg" is non-null, it is passed before each extra option in mOptions.
|
|
|
|
*
|
2010-07-14 16:02:20 -07:00
|
|
|
* Adds the strings, if any, to mOptions.
|
|
|
|
*/
|
2014-02-28 23:27:22 -08:00
|
|
|
void AndroidRuntime::parseExtraOpts(char* extraOptsBuf, const char* quotingArg)
|
2010-07-14 16:02:20 -07:00
|
|
|
{
|
2014-02-28 23:27:22 -08:00
|
|
|
char* start = extraOptsBuf;
|
|
|
|
char* end = NULL;
|
2010-07-14 16:02:20 -07:00
|
|
|
while (*start != '\0') {
|
|
|
|
while (*start == ' ') /* skip leading whitespace */
|
|
|
|
start++;
|
|
|
|
if (*start == '\0') /* was trailing ws, bail */
|
|
|
|
break;
|
|
|
|
|
|
|
|
end = start+1;
|
|
|
|
while (*end != ' ' && *end != '\0') /* find end of token */
|
|
|
|
end++;
|
|
|
|
if (*end == ' ')
|
|
|
|
*end++ = '\0'; /* mark end, advance to indicate more */
|
|
|
|
|
2014-02-28 23:27:22 -08:00
|
|
|
if (quotingArg != NULL) {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption(quotingArg);
|
2014-02-28 23:27:22 -08:00
|
|
|
}
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption(start);
|
2010-07-14 16:02:20 -07:00
|
|
|
start = end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-08 10:40:59 -07:00
|
|
|
/*
|
|
|
|
* Reads a "property" into "buffer" with a default of "defaultArg". If
|
|
|
|
* the property is non-empty, it is treated as a runtime option such
|
|
|
|
* as "-Xmx32m".
|
|
|
|
*
|
|
|
|
* The "runtimeArg" is a prefix for the option such as "-Xms" or "-Xmx".
|
|
|
|
*
|
|
|
|
* If an argument is found, it is added to mOptions.
|
|
|
|
*
|
|
|
|
* If an option is found, it is added to mOptions and true is
|
|
|
|
* returned. Otherwise false is returned.
|
|
|
|
*/
|
|
|
|
bool AndroidRuntime::parseRuntimeOption(const char* property,
|
|
|
|
char* buffer,
|
|
|
|
const char* runtimeArg,
|
|
|
|
const char* defaultArg)
|
|
|
|
{
|
|
|
|
strcpy(buffer, runtimeArg);
|
|
|
|
size_t runtimeArgLen = strlen(runtimeArg);
|
|
|
|
property_get(property, buffer+runtimeArgLen, defaultArg);
|
|
|
|
if (buffer[runtimeArgLen] == '\0') {
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption(buffer);
|
2014-07-08 10:40:59 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-28 19:13:28 -07:00
|
|
|
/*
|
|
|
|
* Reads a "property" into "buffer". If the property is non-empty, it
|
|
|
|
* is treated as a dex2oat compiler option that should be
|
|
|
|
* passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=verify-none".
|
|
|
|
*
|
|
|
|
* The "compilerArg" is a prefix for the option such as "--compiler-filter=".
|
|
|
|
*
|
|
|
|
* The "quotingArg" should be "-Ximage-compiler-option" or "-Xcompiler-option".
|
|
|
|
*
|
|
|
|
* If an option is found, it is added to mOptions and true is
|
|
|
|
* returned. Otherwise false is returned.
|
|
|
|
*/
|
|
|
|
bool AndroidRuntime::parseCompilerOption(const char* property,
|
|
|
|
char* buffer,
|
|
|
|
const char* compilerArg,
|
|
|
|
const char* quotingArg)
|
|
|
|
{
|
|
|
|
strcpy(buffer, compilerArg);
|
|
|
|
size_t compilerArgLen = strlen(compilerArg);
|
|
|
|
property_get(property, buffer+compilerArgLen, "");
|
|
|
|
if (buffer[compilerArgLen] == '\0') {
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption(quotingArg);
|
|
|
|
addOption(buffer);
|
2014-07-28 19:13:28 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-08 10:40:59 -07:00
|
|
|
/*
|
|
|
|
* Reads a "property" into "buffer". If the property is non-empty, it
|
|
|
|
* is treated as a dex2oat compiler runtime option that should be
|
|
|
|
* passed as a quoted option, e.g. "-Ximage-compiler-option
|
|
|
|
* --runtime-arg -Ximage-compiler-option -Xmx32m".
|
|
|
|
*
|
|
|
|
* The "runtimeArg" is a prefix for the option such as "-Xms" or "-Xmx".
|
|
|
|
*
|
|
|
|
* The "quotingArg" should be "-Ximage-compiler-option" or "-Xcompiler-option".
|
|
|
|
*
|
|
|
|
* If an option is found, it is added to mOptions and true is
|
|
|
|
* returned. Otherwise false is returned.
|
|
|
|
*/
|
|
|
|
bool AndroidRuntime::parseCompilerRuntimeOption(const char* property,
|
|
|
|
char* buffer,
|
|
|
|
const char* runtimeArg,
|
|
|
|
const char* quotingArg)
|
|
|
|
{
|
|
|
|
strcpy(buffer, runtimeArg);
|
|
|
|
size_t runtimeArgLen = strlen(runtimeArg);
|
|
|
|
property_get(property, buffer+runtimeArgLen, "");
|
|
|
|
if (buffer[runtimeArgLen] == '\0') {
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption(quotingArg);
|
|
|
|
addOption("--runtime-arg");
|
|
|
|
addOption(quotingArg);
|
|
|
|
addOption(buffer);
|
2014-07-08 10:40:59 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-03-31 15:52:13 -07:00
|
|
|
/*
|
|
|
|
* Start the Dalvik Virtual Machine.
|
|
|
|
*
|
|
|
|
* Various arguments, most determined by system properties, are passed in.
|
|
|
|
* The "mOptions" vector is updated.
|
|
|
|
*
|
2014-03-14 08:54:33 -07:00
|
|
|
* CAUTION: when adding options in here, be careful not to put the
|
|
|
|
* char buffer inside a nested scope. Adding the buffer to the
|
|
|
|
* options using mOptions.add() does not copy the buffer, so if the
|
|
|
|
* buffer goes out of scope the option may be overwritten. It's best
|
|
|
|
* to put the buffer at the top of the function so that it is more
|
|
|
|
* unlikely that someone will surround it in a scope at a later time
|
|
|
|
* and thus introduce a bug.
|
|
|
|
*
|
2009-03-31 15:52:13 -07:00
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
|
2009-03-03 19:31:44 -08:00
|
|
|
{
|
2009-03-31 15:52:13 -07:00
|
|
|
int result = -1;
|
2009-03-03 19:31:44 -08:00
|
|
|
JavaVMInitArgs initArgs;
|
|
|
|
char propBuf[PROPERTY_VALUE_MAX];
|
2014-07-08 10:40:59 -07:00
|
|
|
char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
|
2009-03-03 19:31:44 -08:00
|
|
|
char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
|
|
|
|
char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
|
2010-12-07 16:48:29 -08:00
|
|
|
char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
|
2009-08-18 19:15:36 -07:00
|
|
|
char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
|
2011-01-19 12:33:12 -08:00
|
|
|
char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
|
2012-09-23 16:38:03 -07:00
|
|
|
char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
|
2013-12-02 15:46:51 -08:00
|
|
|
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
|
2014-05-14 15:44:49 -07:00
|
|
|
char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
|
2012-09-23 16:38:03 -07:00
|
|
|
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
|
2013-05-24 13:14:08 -07:00
|
|
|
char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
|
2014-02-28 23:27:22 -08:00
|
|
|
char dalvikVmLibBuf[PROPERTY_VALUE_MAX];
|
2014-07-08 10:40:59 -07:00
|
|
|
char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
|
2014-07-28 19:13:28 -07:00
|
|
|
char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
|
2014-02-28 23:27:22 -08:00
|
|
|
char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
|
|
|
|
char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
|
2010-07-14 16:02:20 -07:00
|
|
|
char extraOptsBuf[PROPERTY_VALUE_MAX];
|
2014-07-30 12:11:41 -07:00
|
|
|
char voldDecryptBuf[PROPERTY_VALUE_MAX];
|
2009-06-19 13:31:12 -07:00
|
|
|
enum {
|
|
|
|
kEMDefault,
|
|
|
|
kEMIntPortable,
|
|
|
|
kEMIntFast,
|
|
|
|
kEMJitCompiler,
|
|
|
|
} executionMode = kEMDefault;
|
2014-07-08 10:40:59 -07:00
|
|
|
char profilePeriod[sizeof("-Xprofile-period:")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char profileDuration[sizeof("-Xprofile-duration:")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char profileInterval[sizeof("-Xprofile-interval:")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char profileBackoff[sizeof("-Xprofile-backoff:")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char profileTopKThreshold[sizeof("-Xprofile-top-k-threshold:")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char profileTopKChangeThreshold[sizeof("-Xprofile-top-k-change-threshold:")-1 +
|
|
|
|
PROPERTY_VALUE_MAX];
|
|
|
|
char profileType[sizeof("-Xprofile-type:")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char profileMaxStackDepth[sizeof("-Xprofile-max-stack-depth:")-1 + PROPERTY_VALUE_MAX];
|
2014-03-14 08:54:33 -07:00
|
|
|
char langOption[sizeof("-Duser.language=") + 3];
|
|
|
|
char regionOption[sizeof("-Duser.region=") + 3];
|
2014-07-08 10:40:59 -07:00
|
|
|
char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char jitOpBuf[sizeof("-Xjitop:")-1 + PROPERTY_VALUE_MAX];
|
|
|
|
char jitMethodBuf[sizeof("-Xjitmethod:")-1 + PROPERTY_VALUE_MAX];
|
2014-08-07 14:45:53 +01:00
|
|
|
char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
|
2009-03-03 19:31:44 -08:00
|
|
|
|
2014-07-08 10:40:59 -07:00
|
|
|
bool checkJni = false;
|
2009-03-03 19:31:44 -08:00
|
|
|
property_get("dalvik.vm.checkjni", propBuf, "");
|
|
|
|
if (strcmp(propBuf, "true") == 0) {
|
|
|
|
checkJni = true;
|
|
|
|
} else if (strcmp(propBuf, "false") != 0) {
|
|
|
|
/* property is neither true nor false; fall back on kernel parameter */
|
|
|
|
property_get("ro.kernel.android.checkjni", propBuf, "");
|
|
|
|
if (propBuf[0] == '1') {
|
|
|
|
checkJni = true;
|
|
|
|
}
|
|
|
|
}
|
2014-07-08 10:40:59 -07:00
|
|
|
ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
|
|
|
|
if (checkJni) {
|
|
|
|
/* extended JNI checking */
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xcheck:jni");
|
2014-07-08 10:40:59 -07:00
|
|
|
|
|
|
|
/* set a cap on JNI global references */
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xjnigreflimit:2000");
|
2014-07-08 10:40:59 -07:00
|
|
|
|
|
|
|
/* with -Xcheck:jni, this provides a JNI function call trace */
|
2014-07-30 12:11:41 -07:00
|
|
|
//addOption("-verbose:jni");
|
2014-07-08 10:40:59 -07:00
|
|
|
}
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
property_get("dalvik.vm.execution-mode", propBuf, "");
|
|
|
|
if (strcmp(propBuf, "int:portable") == 0) {
|
|
|
|
executionMode = kEMIntPortable;
|
|
|
|
} else if (strcmp(propBuf, "int:fast") == 0) {
|
|
|
|
executionMode = kEMIntFast;
|
2009-06-19 13:31:12 -07:00
|
|
|
} else if (strcmp(propBuf, "int:jit") == 0) {
|
|
|
|
executionMode = kEMJitCompiler;
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
|
2009-03-03 19:31:44 -08:00
|
|
|
|
2009-04-03 11:09:46 -07:00
|
|
|
property_get("dalvik.vm.check-dex-sum", propBuf, "");
|
|
|
|
if (strcmp(propBuf, "true") == 0) {
|
2014-07-08 10:40:59 -07:00
|
|
|
/* perform additional DEX checksum tests */
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xcheckdexsum");
|
2009-04-03 11:09:46 -07:00
|
|
|
}
|
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
property_get("log.redirect-stdio", propBuf, "");
|
|
|
|
if (strcmp(propBuf, "true") == 0) {
|
2014-07-08 10:40:59 -07:00
|
|
|
/* convert stdout/stderr to log messages */
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xlog-stdio");
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(enableAssertBuf, "-ea:");
|
2014-07-08 10:40:59 -07:00
|
|
|
property_get("dalvik.vm.enableassertions", enableAssertBuf+sizeof("-ea:")-1, "");
|
|
|
|
if (enableAssertBuf[sizeof("-ea:")-1] != '\0') {
|
|
|
|
/* accept "all" to mean "all classes and packages" */
|
|
|
|
if (strcmp(enableAssertBuf+sizeof("-ea:")-1, "all") == 0)
|
|
|
|
enableAssertBuf[3] = '\0'; // truncate to "-ea"
|
|
|
|
ALOGI("Assertions enabled: '%s'\n", enableAssertBuf);
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption(enableAssertBuf);
|
2014-07-08 10:40:59 -07:00
|
|
|
} else {
|
|
|
|
ALOGV("Assertions disabled\n");
|
|
|
|
}
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
strcpy(jniOptsBuf, "-Xjniopts:");
|
2014-07-08 10:40:59 -07:00
|
|
|
if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
|
|
|
|
ALOGI("JNI options: '%s'\n", jniOptsBuf);
|
|
|
|
}
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
/* route exit() to our handler */
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("exit", (void*) runtime_exit);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
/* route fprintf() to our handler */
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("vfprintf", (void*) runtime_vfprintf);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
2010-12-13 16:52:35 -08:00
|
|
|
/* register the framework-specific "is sensitive thread" hook */
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("sensitiveThread", (void*) runtime_isSensitiveThread);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
/* enable verbose; standard options are { jni, gc, class } */
|
2014-07-30 12:11:41 -07:00
|
|
|
//addOption("-verbose:jni");
|
|
|
|
addOption("-verbose:gc");
|
|
|
|
//addOption("-verbose:class");
|
2009-03-03 19:31:44 -08:00
|
|
|
|
2010-12-08 12:14:46 -08:00
|
|
|
/*
|
|
|
|
* The default starting and maximum size of the heap. Larger
|
|
|
|
* values should be specified in a product property override.
|
|
|
|
*/
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
|
|
|
|
parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
|
2009-03-03 19:31:44 -08:00
|
|
|
|
2012-04-12 16:02:56 -07:00
|
|
|
// Increase the main thread's interpreter stack size for bug 6315322.
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-XX:mainThreadStackSize=24K");
|
2012-04-12 16:02:56 -07:00
|
|
|
|
2013-05-24 13:14:08 -07:00
|
|
|
// Set the max jit code cache size. Note: size of 0 will disable the JIT.
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.jit.codecachesize",
|
|
|
|
jitcodecachesizeOptsBuf,
|
|
|
|
"-Xjitcodecachesize:");
|
2012-09-23 16:38:03 -07:00
|
|
|
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
|
|
|
|
parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
|
|
|
|
parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
|
|
|
|
parseRuntimeOption("dalvik.vm.heaptargetutilization",
|
|
|
|
heaptargetutilizationOptsBuf,
|
|
|
|
"-XX:HeapTargetUtilization=");
|
2012-09-23 16:38:03 -07:00
|
|
|
|
2013-08-20 17:16:03 -07:00
|
|
|
property_get("ro.config.low_ram", propBuf, "");
|
|
|
|
if (strcmp(propBuf, "true") == 0) {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-XX:LowMemoryMode");
|
2013-08-20 17:16:03 -07:00
|
|
|
}
|
|
|
|
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");
|
|
|
|
parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC=");
|
2014-05-14 15:44:49 -07:00
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
/*
|
|
|
|
* Enable or disable dexopt features, such as bytecode verification and
|
|
|
|
* calculation of register maps for precise GC.
|
|
|
|
*/
|
|
|
|
property_get("dalvik.vm.dexopt-flags", dexoptFlagsBuf, "");
|
|
|
|
if (dexoptFlagsBuf[0] != '\0') {
|
|
|
|
const char* opc;
|
|
|
|
const char* val;
|
|
|
|
|
|
|
|
opc = strstr(dexoptFlagsBuf, "v="); /* verification */
|
|
|
|
if (opc != NULL) {
|
|
|
|
switch (*(opc+2)) {
|
|
|
|
case 'n': val = "-Xverify:none"; break;
|
|
|
|
case 'r': val = "-Xverify:remote"; break;
|
|
|
|
case 'a': val = "-Xverify:all"; break;
|
|
|
|
default: val = NULL; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (val != NULL) {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption(val);
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
opc = strstr(dexoptFlagsBuf, "o="); /* optimization */
|
|
|
|
if (opc != NULL) {
|
|
|
|
switch (*(opc+2)) {
|
|
|
|
case 'n': val = "-Xdexopt:none"; break;
|
|
|
|
case 'v': val = "-Xdexopt:verified"; break;
|
|
|
|
case 'a': val = "-Xdexopt:all"; break;
|
2011-04-01 15:49:41 -07:00
|
|
|
case 'f': val = "-Xdexopt:full"; break;
|
2009-03-03 19:31:44 -08:00
|
|
|
default: val = NULL; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (val != NULL) {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption(val);
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
opc = strstr(dexoptFlagsBuf, "m=y"); /* register map */
|
|
|
|
if (opc != NULL) {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xgenregmap");
|
2009-03-18 22:20:26 -07:00
|
|
|
|
|
|
|
/* turn on precise GC while we're at it */
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xgc:precise");
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enable debugging; set suspend=y to pause during VM init */
|
|
|
|
/* use android ADB transport */
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y");
|
2009-03-03 19:31:44 -08:00
|
|
|
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.lockprof.threshold",
|
|
|
|
lockProfThresholdBuf,
|
|
|
|
"-Xlockprofthreshold:");
|
2010-04-12 16:31:59 -07:00
|
|
|
|
2009-06-19 13:31:12 -07:00
|
|
|
/* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.jit.op", jitOpBuf, "-Xjitop:");
|
2009-06-19 13:31:12 -07:00
|
|
|
|
|
|
|
/* Force interpreter-only mode for selected methods */
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.jit.method", jitMethodBuf, "-Xjitmethod:");
|
2009-06-19 13:31:12 -07:00
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
if (executionMode == kEMIntPortable) {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xint:portable");
|
2009-03-03 19:31:44 -08:00
|
|
|
} else if (executionMode == kEMIntFast) {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xint:fast");
|
2009-06-19 13:31:12 -07:00
|
|
|
} else if (executionMode == kEMJitCompiler) {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xint:jit");
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
2009-04-03 11:09:46 -07:00
|
|
|
|
2014-03-10 10:20:01 -07:00
|
|
|
// libart tolerates libdvm flags, but not vice versa, so only pass some options if libart.
|
2014-05-28 14:31:47 -07:00
|
|
|
property_get("persist.sys.dalvik.vm.lib.2", dalvikVmLibBuf, "libart.so");
|
2014-03-10 10:20:01 -07:00
|
|
|
bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0);
|
2014-02-28 23:27:22 -08:00
|
|
|
|
2014-03-10 10:20:01 -07:00
|
|
|
if (libart) {
|
2014-07-30 12:11:41 -07:00
|
|
|
// If we booting without the real /data, don't spend time compiling.
|
|
|
|
property_get("vold.decrypt", voldDecryptBuf, "");
|
|
|
|
bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
|
|
|
|
(strcmp(voldDecryptBuf, "1") == 0));
|
|
|
|
|
2014-02-28 23:27:22 -08:00
|
|
|
// Extra options for boot.art/boot.oat image generation.
|
2014-07-08 10:40:59 -07:00
|
|
|
parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
|
|
|
|
"-Xms", "-Ximage-compiler-option");
|
|
|
|
parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
|
|
|
|
"-Xmx", "-Ximage-compiler-option");
|
2014-07-30 12:11:41 -07:00
|
|
|
if (skip_compilation) {
|
|
|
|
addOption("-Ximage-compiler-option");
|
|
|
|
addOption("--compiler-filter=verify-none");
|
|
|
|
} else {
|
|
|
|
parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
|
|
|
|
"--compiler-filter=", "-Ximage-compiler-option");
|
|
|
|
}
|
2014-07-30 15:13:17 -07:00
|
|
|
addOption("-Ximage-compiler-option");
|
|
|
|
addOption("--image-classes-zip=/system/framework/framework.jar");
|
|
|
|
addOption("-Ximage-compiler-option");
|
|
|
|
addOption("--image-classes=preloaded-classes");
|
2014-02-28 23:27:22 -08:00
|
|
|
property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
|
|
|
|
parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
|
2014-07-08 10:40:59 -07:00
|
|
|
|
|
|
|
// Extra options for DexClassLoader.
|
|
|
|
parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xms", dex2oatXmsFlagsBuf,
|
|
|
|
"-Xms", "-Xcompiler-option");
|
|
|
|
parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf,
|
|
|
|
"-Xmx", "-Xcompiler-option");
|
2014-07-30 12:11:41 -07:00
|
|
|
if (skip_compilation) {
|
|
|
|
addOption("-Xcompiler-option");
|
2014-08-15 09:31:27 -07:00
|
|
|
addOption("--compiler-filter=verify-none");
|
2014-07-30 12:11:41 -07:00
|
|
|
} else {
|
|
|
|
parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
|
|
|
|
"--compiler-filter=", "-Xcompiler-option");
|
|
|
|
}
|
2014-07-08 10:40:59 -07:00
|
|
|
property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
|
|
|
|
parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
|
2014-07-30 12:11:41 -07:00
|
|
|
|
2014-02-28 23:27:22 -08:00
|
|
|
}
|
|
|
|
|
2010-07-14 16:02:20 -07:00
|
|
|
/* extra options; parse this late so it overrides others */
|
|
|
|
property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
|
2014-02-28 23:27:22 -08:00
|
|
|
parseExtraOpts(extraOptsBuf, NULL);
|
2010-07-14 16:02:20 -07:00
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
/* Set the properties for locale */
|
|
|
|
{
|
|
|
|
strcpy(langOption, "-Duser.language=");
|
|
|
|
strcpy(regionOption, "-Duser.region=");
|
|
|
|
readLocale(langOption, regionOption);
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption(langOption);
|
|
|
|
addOption(regionOption);
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
|
2014-01-30 14:19:51 -08:00
|
|
|
/*
|
|
|
|
* Set profiler options
|
|
|
|
*/
|
2014-03-10 10:20:01 -07:00
|
|
|
if (libart) {
|
2014-06-06 16:00:53 +01:00
|
|
|
// Whether or not the profiler should be enabled.
|
2014-06-02 16:45:13 +01:00
|
|
|
property_get("dalvik.vm.profiler", propBuf, "0");
|
|
|
|
if (propBuf[0] == '1') {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xenable-profiler");
|
2014-06-02 16:45:13 +01:00
|
|
|
}
|
2014-01-30 14:19:51 -08:00
|
|
|
|
2014-06-10 14:52:24 +01:00
|
|
|
// Whether the profile should start upon app startup or be delayed by some random offset
|
|
|
|
// (in seconds) that is bound between 0 and a fixed value.
|
2014-06-11 18:21:41 +01:00
|
|
|
property_get("dalvik.vm.profile.start-immed", propBuf, "0");
|
2014-06-02 16:45:13 +01:00
|
|
|
if (propBuf[0] == '1') {
|
2014-07-30 12:11:41 -07:00
|
|
|
addOption("-Xprofile-start-immediately");
|
2014-06-02 16:45:13 +01:00
|
|
|
}
|
2014-01-30 14:19:51 -08:00
|
|
|
|
2014-06-02 16:45:13 +01:00
|
|
|
// Number of seconds during profile runs.
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.profile.period-secs", profilePeriod, "-Xprofile-period:");
|
2014-01-30 14:19:51 -08:00
|
|
|
|
2014-06-02 16:45:13 +01:00
|
|
|
// Length of each profile run (seconds).
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.profile.duration-secs",
|
|
|
|
profileDuration,
|
|
|
|
"-Xprofile-duration:");
|
2014-01-30 14:19:51 -08:00
|
|
|
|
2014-06-02 16:45:13 +01:00
|
|
|
// Polling interval during profile run (microseconds).
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.profile.interval-us", profileInterval, "-Xprofile-interval:");
|
2014-06-02 16:45:13 +01:00
|
|
|
|
|
|
|
// Coefficient for period backoff. The the period is multiplied
|
|
|
|
// by this value after each profile run.
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.profile.backoff-coeff", profileBackoff, "-Xprofile-backoff:");
|
|
|
|
|
|
|
|
// Top K% of samples that are considered relevant when
|
|
|
|
// deciding if the app should be recompiled.
|
|
|
|
parseRuntimeOption("dalvik.vm.profile.top-k-thr",
|
|
|
|
profileTopKThreshold,
|
|
|
|
"-Xprofile-top-k-threshold:");
|
|
|
|
|
|
|
|
// The threshold after which a change in the structure of the
|
|
|
|
// top K% profiled samples becomes significant and triggers
|
|
|
|
// recompilation. A change in profile is considered
|
|
|
|
// significant if X% (top-k-change-threshold) of the top K%
|
|
|
|
// (top-k-threshold property) samples has changed.
|
|
|
|
parseRuntimeOption("dalvik.vm.profile.top-k-ch-thr",
|
|
|
|
profileTopKChangeThreshold,
|
|
|
|
"-Xprofile-top-k-change-threshold:");
|
2014-06-09 16:29:54 -07:00
|
|
|
|
|
|
|
// Type of profile data.
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.profiler.type", profileType, "-Xprofile-type:");
|
2014-06-09 16:29:54 -07:00
|
|
|
|
|
|
|
// Depth of bounded stack data
|
2014-07-08 10:40:59 -07:00
|
|
|
parseRuntimeOption("dalvik.vm.profile.max-stack-depth",
|
|
|
|
profileMaxStackDepth,
|
|
|
|
"-Xprofile-max-stack-depth:");
|
2014-01-30 14:19:51 -08:00
|
|
|
|
2014-08-26 23:00:11 +01:00
|
|
|
// Native bridge library. "0" means that native bridge is disabled.
|
|
|
|
property_get("ro.dalvik.vm.native.bridge", propBuf, "");
|
|
|
|
if (propBuf[0] == '\0') {
|
|
|
|
ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");
|
|
|
|
} else if (strcmp(propBuf, "0") != 0) {
|
|
|
|
snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,
|
|
|
|
"-XX:NativeBridge=%s", propBuf);
|
|
|
|
addOption(nativeBridgeLibrary);
|
|
|
|
}
|
|
|
|
}
|
2014-08-07 14:45:53 +01:00
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
initArgs.version = JNI_VERSION_1_4;
|
|
|
|
initArgs.options = mOptions.editArray();
|
|
|
|
initArgs.nOptions = mOptions.size();
|
|
|
|
initArgs.ignoreUnrecognized = JNI_FALSE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the VM.
|
|
|
|
*
|
|
|
|
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
|
|
|
|
* If this call succeeds, the VM is ready, and we can start issuing
|
|
|
|
* JNI calls.
|
|
|
|
*/
|
2009-03-31 15:52:13 -07:00
|
|
|
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("JNI_CreateJavaVM failed\n");
|
2009-03-03 19:31:44 -08:00
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
2009-03-31 15:52:13 -07:00
|
|
|
result = 0;
|
|
|
|
|
|
|
|
bail:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-04-13 15:39:37 -07:00
|
|
|
char* AndroidRuntime::toSlashClassName(const char* className)
|
|
|
|
{
|
|
|
|
char* result = strdup(className);
|
|
|
|
for (char* cp = result; *cp != '\0'; cp++) {
|
|
|
|
if (*cp == '.') {
|
|
|
|
*cp = '/';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-09-08 16:15:21 -07:00
|
|
|
/** Create a Java string from an ASCII or Latin-1 string */
|
|
|
|
jstring AndroidRuntime::NewStringLatin1(JNIEnv* env, const char* bytes) {
|
|
|
|
if (!bytes) return NULL;
|
|
|
|
int length = strlen(bytes);
|
|
|
|
jchar* buffer = (jchar *)alloca(length * sizeof(jchar));
|
|
|
|
if (!buffer) return NULL;
|
|
|
|
jchar* chp = buffer;
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
*chp++ = *bytes++;
|
|
|
|
}
|
|
|
|
return env->NewString(buffer, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-31 15:52:13 -07:00
|
|
|
/*
|
|
|
|
* Start the Android runtime. This involves starting the virtual machine
|
|
|
|
* and calling the "static void main(String[] args)" method in the class
|
|
|
|
* named by "className".
|
2011-05-16 17:08:42 -07:00
|
|
|
*
|
|
|
|
* Passes the main function two arguments, the class name and the specified
|
|
|
|
* options string.
|
2009-03-31 15:52:13 -07:00
|
|
|
*/
|
2014-04-07 12:44:58 +01:00
|
|
|
void AndroidRuntime::start(const char* className, const Vector<String8>& options)
|
2009-03-31 15:52:13 -07:00
|
|
|
{
|
2011-12-20 16:23:08 +00:00
|
|
|
ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
|
2010-09-01 18:17:17 -07:00
|
|
|
className != NULL ? className : "(unknown)");
|
2009-03-31 15:52:13 -07:00
|
|
|
|
2014-04-07 12:44:58 +01:00
|
|
|
static const String8 startSystemServer("start-system-server");
|
|
|
|
|
2011-04-13 15:39:37 -07:00
|
|
|
/*
|
|
|
|
* 'startSystemServer == true' means runtime is obsolete and not run from
|
2009-03-31 15:52:13 -07:00
|
|
|
* init.rc anymore, so we print out the boot start event here.
|
|
|
|
*/
|
2014-04-07 12:44:58 +01:00
|
|
|
for (size_t i = 0; i < options.size(); ++i) {
|
|
|
|
if (options[i] == startSystemServer) {
|
|
|
|
/* track our progress through the boot sequence */
|
|
|
|
const int LOG_BOOT_PROGRESS_START = 3000;
|
|
|
|
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
|
|
|
|
}
|
2009-03-31 15:52:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* rootDir = getenv("ANDROID_ROOT");
|
|
|
|
if (rootDir == NULL) {
|
|
|
|
rootDir = "/system";
|
|
|
|
if (!hasDir("/system")) {
|
|
|
|
LOG_FATAL("No root directory specified, and /android does not exist.");
|
2011-04-13 15:39:37 -07:00
|
|
|
return;
|
2009-03-31 15:52:13 -07:00
|
|
|
}
|
|
|
|
setenv("ANDROID_ROOT", rootDir, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
|
2011-12-20 16:23:08 +00:00
|
|
|
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
|
2009-03-31 15:52:13 -07:00
|
|
|
|
|
|
|
/* start the virtual machine */
|
2013-06-19 13:49:36 -07:00
|
|
|
JniInvocation jni_invocation;
|
|
|
|
jni_invocation.Init(NULL);
|
2011-04-13 15:39:37 -07:00
|
|
|
JNIEnv* env;
|
|
|
|
if (startVm(&mJavaVM, &env) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
onVmCreated(env);
|
2009-03-31 15:52:13 -07:00
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
/*
|
|
|
|
* Register android functions.
|
|
|
|
*/
|
|
|
|
if (startReg(env) < 0) {
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("Unable to register all android natives\n");
|
2011-04-13 15:39:37 -07:00
|
|
|
return;
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We want to call main() with a String array with arguments in it.
|
2011-05-16 17:08:42 -07:00
|
|
|
* At present we have two arguments, the class name and an option string.
|
|
|
|
* Create an array to hold them.
|
2009-03-03 19:31:44 -08:00
|
|
|
*/
|
|
|
|
jclass stringClass;
|
|
|
|
jobjectArray strArray;
|
|
|
|
jstring classNameStr;
|
|
|
|
|
|
|
|
stringClass = env->FindClass("java/lang/String");
|
|
|
|
assert(stringClass != NULL);
|
2014-04-07 12:44:58 +01:00
|
|
|
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
|
2009-03-03 19:31:44 -08:00
|
|
|
assert(strArray != NULL);
|
|
|
|
classNameStr = env->NewStringUTF(className);
|
|
|
|
assert(classNameStr != NULL);
|
|
|
|
env->SetObjectArrayElement(strArray, 0, classNameStr);
|
2014-04-07 12:44:58 +01:00
|
|
|
|
|
|
|
for (size_t i = 0; i < options.size(); ++i) {
|
|
|
|
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
|
|
|
|
assert(optionsStr != NULL);
|
|
|
|
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
|
|
|
|
}
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Start VM. This thread becomes the main thread of the VM, and will
|
|
|
|
* not return until the VM exits.
|
|
|
|
*/
|
2011-04-13 15:39:37 -07:00
|
|
|
char* slashClassName = toSlashClassName(className);
|
|
|
|
jclass startClass = env->FindClass(slashClassName);
|
2009-03-03 19:31:44 -08:00
|
|
|
if (startClass == NULL) {
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
|
2009-03-03 19:31:44 -08:00
|
|
|
/* keep going */
|
|
|
|
} else {
|
2011-04-13 15:39:37 -07:00
|
|
|
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
|
2009-03-03 19:31:44 -08:00
|
|
|
"([Ljava/lang/String;)V");
|
|
|
|
if (startMeth == NULL) {
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("JavaVM unable to find main() in '%s'\n", className);
|
2009-03-03 19:31:44 -08:00
|
|
|
/* keep going */
|
|
|
|
} else {
|
|
|
|
env->CallStaticVoidMethod(startClass, startMeth, strArray);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (env->ExceptionCheck())
|
|
|
|
threadExitUncaughtException(env);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2011-04-13 15:39:37 -07:00
|
|
|
free(slashClassName);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
2011-12-20 16:23:08 +00:00
|
|
|
ALOGD("Shutting down VM\n");
|
2009-03-03 19:31:44 -08:00
|
|
|
if (mJavaVM->DetachCurrentThread() != JNI_OK)
|
2012-01-05 23:22:43 +00:00
|
|
|
ALOGW("Warning: unable to detach main thread\n");
|
2009-03-03 19:31:44 -08:00
|
|
|
if (mJavaVM->DestroyJavaVM() != 0)
|
2012-01-05 23:22:43 +00:00
|
|
|
ALOGW("Warning: VM did not shut down cleanly\n");
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
|
2012-03-15 17:48:02 -07:00
|
|
|
void AndroidRuntime::exit(int code)
|
2009-03-03 19:31:44 -08:00
|
|
|
{
|
2012-03-15 17:48:02 -07:00
|
|
|
if (mExitWithoutCleanup) {
|
|
|
|
ALOGI("VM exiting with result code %d, cleanup skipped.", code);
|
|
|
|
::_exit(code);
|
|
|
|
} else {
|
|
|
|
ALOGI("VM exiting with result code %d.", code);
|
|
|
|
onExit(code);
|
|
|
|
::exit(code);
|
|
|
|
}
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
|
2011-04-13 15:39:37 -07:00
|
|
|
void AndroidRuntime::onVmCreated(JNIEnv* env)
|
|
|
|
{
|
|
|
|
// If AndroidRuntime had anything to do here, we'd have done it in 'start'.
|
|
|
|
}
|
|
|
|
|
2014-02-13 17:22:33 +00:00
|
|
|
/*
|
|
|
|
* Get the JNIEnv pointer for this thread.
|
|
|
|
*
|
|
|
|
* Returns NULL if the slot wasn't allocated or populated.
|
|
|
|
*/
|
|
|
|
/*static*/ JNIEnv* AndroidRuntime::getJNIEnv()
|
|
|
|
{
|
|
|
|
JNIEnv* env;
|
|
|
|
JavaVM* vm = AndroidRuntime::getJavaVM();
|
|
|
|
assert(vm != NULL);
|
|
|
|
|
|
|
|
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
|
|
|
|
return NULL;
|
|
|
|
return env;
|
|
|
|
}
|
|
|
|
|
2009-03-03 19:31:44 -08:00
|
|
|
/*
|
|
|
|
* Makes the current thread visible to the VM.
|
|
|
|
*
|
|
|
|
* The JNIEnv pointer returned is only valid for the current thread, and
|
|
|
|
* thus must be tucked into thread-local storage.
|
|
|
|
*/
|
|
|
|
static int javaAttachThread(const char* threadName, JNIEnv** pEnv)
|
|
|
|
{
|
|
|
|
JavaVMAttachArgs args;
|
|
|
|
JavaVM* vm;
|
|
|
|
jint result;
|
|
|
|
|
|
|
|
vm = AndroidRuntime::getJavaVM();
|
|
|
|
assert(vm != NULL);
|
|
|
|
|
|
|
|
args.version = JNI_VERSION_1_4;
|
|
|
|
args.name = (char*) threadName;
|
|
|
|
args.group = NULL;
|
|
|
|
|
|
|
|
result = vm->AttachCurrentThread(pEnv, (void*) &args);
|
|
|
|
if (result != JNI_OK)
|
2012-01-04 20:05:49 +00:00
|
|
|
ALOGI("NOTE: attach of thread '%s' failed\n", threadName);
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Detach the current thread from the set visible to the VM.
|
|
|
|
*/
|
|
|
|
static int javaDetachThread(void)
|
|
|
|
{
|
|
|
|
JavaVM* vm;
|
|
|
|
jint result;
|
|
|
|
|
|
|
|
vm = AndroidRuntime::getJavaVM();
|
|
|
|
assert(vm != NULL);
|
|
|
|
|
|
|
|
result = vm->DetachCurrentThread();
|
|
|
|
if (result != JNI_OK)
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("ERROR: thread detach failed\n");
|
2009-03-03 19:31:44 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When starting a native thread that will be visible from the VM, we
|
|
|
|
* bounce through this to get the right attach/detach action.
|
|
|
|
* Note that this function calls free(args)
|
|
|
|
*/
|
|
|
|
/*static*/ int AndroidRuntime::javaThreadShell(void* args) {
|
|
|
|
void* start = ((void**)args)[0];
|
|
|
|
void* userData = ((void **)args)[1];
|
|
|
|
char* name = (char*) ((void **)args)[2]; // we own this storage
|
|
|
|
free(args);
|
|
|
|
JNIEnv* env;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
/* hook us into the VM */
|
|
|
|
if (javaAttachThread(name, &env) != JNI_OK)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* start the thread running */
|
|
|
|
result = (*(android_thread_func_t)start)(userData);
|
|
|
|
|
|
|
|
/* unhook us */
|
|
|
|
javaDetachThread();
|
|
|
|
free(name);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is invoked from androidCreateThreadEtc() via the callback
|
|
|
|
* set with androidSetCreateThreadFunc().
|
|
|
|
*
|
|
|
|
* We need to create the new thread in such a way that it gets hooked
|
|
|
|
* into the VM before it really starts executing.
|
|
|
|
*/
|
|
|
|
/*static*/ int AndroidRuntime::javaCreateThreadEtc(
|
2011-04-13 15:39:37 -07:00
|
|
|
android_thread_func_t entryFunction,
|
2009-03-03 19:31:44 -08:00
|
|
|
void* userData,
|
|
|
|
const char* threadName,
|
|
|
|
int32_t threadPriority,
|
|
|
|
size_t threadStackSize,
|
|
|
|
android_thread_id_t* threadId)
|
|
|
|
{
|
|
|
|
void** args = (void**) malloc(3 * sizeof(void*)); // javaThreadShell must free
|
|
|
|
int result;
|
|
|
|
|
2013-10-10 10:11:27 -07:00
|
|
|
if (!threadName)
|
|
|
|
threadName = "unnamed thread";
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
args[0] = (void*) entryFunction;
|
|
|
|
args[1] = userData;
|
|
|
|
args[2] = (void*) strdup(threadName); // javaThreadShell must free
|
|
|
|
|
|
|
|
result = androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args,
|
|
|
|
threadName, threadPriority, threadStackSize, threadId);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a thread that is visible from the VM.
|
|
|
|
*
|
|
|
|
* This is called from elsewhere in the library.
|
|
|
|
*/
|
2010-06-20 14:28:16 -07:00
|
|
|
/*static*/ android_thread_id_t AndroidRuntime::createJavaThread(const char* name,
|
2009-03-03 19:31:44 -08:00
|
|
|
void (*start)(void *), void* arg)
|
|
|
|
{
|
2010-06-20 14:28:16 -07:00
|
|
|
android_thread_id_t threadId = 0;
|
2009-03-03 19:31:44 -08:00
|
|
|
javaCreateThreadEtc((android_thread_func_t) start, arg, name,
|
2010-06-20 14:28:16 -07:00
|
|
|
ANDROID_PRIORITY_DEFAULT, 0, &threadId);
|
|
|
|
return threadId;
|
2009-03-03 19:31:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static void quickTest(void* arg)
|
|
|
|
{
|
|
|
|
const char* str = (const char*) arg;
|
|
|
|
|
|
|
|
printf("In quickTest: %s\n", str);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef NDEBUG
|
|
|
|
#define REG_JNI(name) { name }
|
|
|
|
struct RegJNIRec {
|
|
|
|
int (*mProc)(JNIEnv*);
|
|
|
|
};
|
|
|
|
#else
|
|
|
|
#define REG_JNI(name) { name, #name }
|
|
|
|
struct RegJNIRec {
|
|
|
|
int (*mProc)(JNIEnv*);
|
|
|
|
const char* mName;
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef void (*RegJAMProc)();
|
|
|
|
|
|
|
|
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
if (array[i].mProc(env) < 0) {
|
|
|
|
#ifndef NDEBUG
|
2011-12-20 16:23:08 +00:00
|
|
|
ALOGD("----------!!! %s failed to load\n", array[i].mName);
|
2009-03-03 19:31:44 -08:00
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void register_jam_procs(const RegJAMProc array[], size_t count)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
array[i]();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const RegJNIRec gRegJNI[] = {
|
|
|
|
REG_JNI(register_com_android_internal_os_RuntimeInit),
|
|
|
|
REG_JNI(register_android_os_SystemClock),
|
|
|
|
REG_JNI(register_android_util_EventLog),
|
|
|
|
REG_JNI(register_android_util_Log),
|
|
|
|
REG_JNI(register_android_util_FloatMath),
|
|
|
|
REG_JNI(register_android_content_AssetManager),
|
|
|
|
REG_JNI(register_android_content_StringBlock),
|
|
|
|
REG_JNI(register_android_content_XmlBlock),
|
2009-03-09 11:52:12 -07:00
|
|
|
REG_JNI(register_android_emoji_EmojiFactory),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_text_AndroidCharacter),
|
2014-06-24 14:39:43 -07:00
|
|
|
REG_JNI(register_android_text_StaticLayout),
|
2010-02-24 14:33:15 -08:00
|
|
|
REG_JNI(register_android_text_AndroidBidi),
|
2012-04-10 14:30:49 -07:00
|
|
|
REG_JNI(register_android_view_InputDevice),
|
|
|
|
REG_JNI(register_android_view_KeyCharacterMap),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_os_Process),
|
2010-11-16 14:40:31 -08:00
|
|
|
REG_JNI(register_android_os_SystemProperties),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_os_Binder),
|
2012-03-06 18:26:19 -08:00
|
|
|
REG_JNI(register_android_os_Parcel),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_nio_utils),
|
|
|
|
REG_JNI(register_android_graphics_Graphics),
|
2013-12-20 13:28:11 -08:00
|
|
|
REG_JNI(register_android_view_DisplayEventReceiver),
|
2014-03-14 16:24:57 -07:00
|
|
|
REG_JNI(register_android_view_RenderNode),
|
2014-04-15 09:50:16 -07:00
|
|
|
REG_JNI(register_android_view_RenderNodeAnimator),
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
REG_JNI(register_android_view_GraphicBuffer),
|
2010-06-16 18:44:05 -07:00
|
|
|
REG_JNI(register_android_view_GLES20Canvas),
|
2014-02-05 16:38:25 -08:00
|
|
|
REG_JNI(register_android_view_HardwareLayer),
|
2013-11-05 13:27:50 -08:00
|
|
|
REG_JNI(register_android_view_ThreadedRenderer),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_view_Surface),
|
2013-02-11 22:08:48 -08:00
|
|
|
REG_JNI(register_android_view_SurfaceControl),
|
2012-08-26 02:47:39 -07:00
|
|
|
REG_JNI(register_android_view_SurfaceSession),
|
2011-05-02 17:24:22 -07:00
|
|
|
REG_JNI(register_android_view_TextureView),
|
2014-05-09 19:21:04 -07:00
|
|
|
REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
|
|
|
|
REG_JNI(register_com_google_android_gles_jni_GLImpl),
|
2012-07-03 13:37:35 -07:00
|
|
|
REG_JNI(register_android_opengl_jni_EGL14),
|
2013-05-06 11:36:57 -07:00
|
|
|
REG_JNI(register_android_opengl_jni_EGLExt),
|
Manually merge 129, 174, and 233 from donut
This adds a static OpenGL ES API.
Here are the three commit messages for the original changes:
Clean up trivial Eclipse warnings and fix whitespace.
Added @Override to overridden methods.
Removed unused imports.
Converted tabs to spaces.
Removed \r characters from end-of-lines.
Add .gitignore file to ignore the .class files that are
generated when the "gen" script is run.
This is the 2nd commit message:
Improve glgen
+ gen script is really a bash script rather than a sh script,
so declare that to be true. (For example, it uses pushd,
which is a part of bash, but not a part of sh. Not sure
how this worked until now. Possibly gen was only run in
environments where /bin/sh was really bash.
+ Check the results of the java compile of the code generator,
and abort the script if the compile fails.
+ Turn on the bash shell option that guards against using
uninitialized variables in the script.
+ Remove the generated class files.
Refactor JniCodeEmitter into two classes: a general-purpose
JniCodeEmitter and a specific Jsr239CodeEmitter. The hope is
to use JniCodeEmitter as a base for emitting static OpenGL ES
bindings.
This is the 3rd commit message:
Add an Android-specific static OpenGL ES 1.1 Java API.
This change adds four new public classes that expose a static OpenGL ES 1.1 API:
android.opengl.GLES10
android.opengl.GLES10Ext
android.opengl.GLES11
android.opengl.GLES11Ext
Benefits:
+ The static API is slightly faster (1% to 4%) than the existing Interface based JSR239 API.
+ The static API is similar to the C API, which should make it easier to import C-based
example code.
+ The static API provides a clear path for adding new OpenGL ES 1.1 extensions
and OpenGL ES 2.0 APIs, neither of which currently have a JSR standard.
Example:
import static android.opengl.GLES10.*;
...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Note that it is possible to mix-and-match calls to both the static and JSR239 APIs.
This works because neither API maintains state. They both call through to the same underlying
C OpenGL ES APIs.
Implementation details:
This change enhances the "glgen" "gen" script to generate both the original JSR239 and
new static OpenGL ES APIs. The contents of the generated JSR239 classes remained the same as before,
so there is no need to check in new versions of the generated JSR239 classes.
As part of this work the gen script was updated to be somewhat more robust, and to
work with git instead of perforce. The script prints out commands to git add the generated files,
but leaves it up to the script runner to actually execute those commands.
2009-04-13 16:22:25 -07:00
|
|
|
REG_JNI(register_android_opengl_jni_GLES10),
|
|
|
|
REG_JNI(register_android_opengl_jni_GLES10Ext),
|
|
|
|
REG_JNI(register_android_opengl_jni_GLES11),
|
|
|
|
REG_JNI(register_android_opengl_jni_GLES11Ext),
|
2009-11-19 16:34:55 +08:00
|
|
|
REG_JNI(register_android_opengl_jni_GLES20),
|
2013-04-29 15:59:35 -07:00
|
|
|
REG_JNI(register_android_opengl_jni_GLES30),
|
2014-05-19 15:13:41 -07:00
|
|
|
REG_JNI(register_android_opengl_jni_GLES31),
|
|
|
|
REG_JNI(register_android_opengl_jni_GLES31Ext),
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
REG_JNI(register_android_graphics_Bitmap),
|
|
|
|
REG_JNI(register_android_graphics_BitmapFactory),
|
2010-09-07 17:32:18 +08:00
|
|
|
REG_JNI(register_android_graphics_BitmapRegionDecoder),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_graphics_Camera),
|
2013-09-06 16:46:57 -04:00
|
|
|
REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_graphics_Canvas),
|
2014-05-01 21:27:37 -07:00
|
|
|
REG_JNI(register_android_graphics_CanvasProperty),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_graphics_ColorFilter),
|
|
|
|
REG_JNI(register_android_graphics_DrawFilter),
|
2014-01-30 16:06:28 -08:00
|
|
|
REG_JNI(register_android_graphics_FontFamily),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_graphics_Interpolator),
|
|
|
|
REG_JNI(register_android_graphics_LayerRasterizer),
|
|
|
|
REG_JNI(register_android_graphics_MaskFilter),
|
|
|
|
REG_JNI(register_android_graphics_Matrix),
|
|
|
|
REG_JNI(register_android_graphics_Movie),
|
|
|
|
REG_JNI(register_android_graphics_NinePatch),
|
|
|
|
REG_JNI(register_android_graphics_Paint),
|
|
|
|
REG_JNI(register_android_graphics_Path),
|
|
|
|
REG_JNI(register_android_graphics_PathMeasure),
|
|
|
|
REG_JNI(register_android_graphics_PathEffect),
|
|
|
|
REG_JNI(register_android_graphics_Picture),
|
|
|
|
REG_JNI(register_android_graphics_PorterDuff),
|
|
|
|
REG_JNI(register_android_graphics_Rasterizer),
|
|
|
|
REG_JNI(register_android_graphics_Region),
|
|
|
|
REG_JNI(register_android_graphics_Shader),
|
2011-01-06 17:04:26 -08:00
|
|
|
REG_JNI(register_android_graphics_SurfaceTexture),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_graphics_Typeface),
|
|
|
|
REG_JNI(register_android_graphics_Xfermode),
|
2009-11-30 17:52:05 +08:00
|
|
|
REG_JNI(register_android_graphics_YuvImage),
|
2013-09-18 15:58:28 -07:00
|
|
|
REG_JNI(register_android_graphics_pdf_PdfDocument),
|
2014-09-04 21:17:17 -07:00
|
|
|
REG_JNI(register_android_graphics_pdf_PdfEditor),
|
2014-04-24 18:40:42 -07:00
|
|
|
REG_JNI(register_android_graphics_pdf_PdfRenderer),
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
REG_JNI(register_android_database_CursorWindow),
|
Rewrite SQLite database wrappers.
The main theme of this change is encapsulation. This change
preserves all existing functionality but the implementation
is now much cleaner.
Instead of a "database lock", access to the database is treated
as a resource acquisition problem. If a thread's owns a database
connection, then it can access the database; otherwise, it must
acquire a database connection first, and potentially wait for other
threads to give up theirs. The SQLiteConnectionPool encapsulates
the details of how connections are created, configured, acquired,
released and disposed.
One new feature is that SQLiteConnectionPool can make scheduling
decisions about which thread should next acquire a database
connection when there is contention among threads. The factors
considered include wait queue ordering (fairness among peers),
whether the connection is needed for an interactive operation
(unfairness on behalf of the UI), and whether the primary connection
is needed or if any old connection will do. Thus one goal of the
new SQLiteConnectionPool is to improve the utilization of
database connections.
To emulate some quirks of the old "database lock," we introduce
the concept of the primary database connection. The primary
database connection is the one that is typically used to perform
write operations to the database. When a thread holds the primary
database connection, it effectively prevents other threads from
modifying the database (although they can still read). What's
more, those threads will block when they try to acquire the primary
connection, which provides the same kind of mutual exclusion
features that the old "database lock" had. (In truth, we
probably don't need to be requiring use of the primary database
connection in as many places as we do now, but we can seek to refine
that behavior in future patches.)
Another significant change is that native sqlite3_stmt objects
(prepared statements) are fully encapsulated by the SQLiteConnection
object that owns them. This ensures that the connection can
finalize (destroy) all extant statements that belong to a database
connection when the connection is closed. (In the original code,
this was very complicated because the sqlite3_stmt objects were
managed by SQLiteCompiledSql objects which had different lifetime
from the original SQLiteDatabase that created them. Worse, the
SQLiteCompiledSql finalizer method couldn't actually destroy the
sqlite3_stmt objects because it ran on the finalizer thread and
therefore could not guarantee that it could acquire the database
lock in order to do the work. This resulted in some rather
tortured logic involving a list of pending finalizable statements
and a high change of deadlocks or leaks.)
Because sqlite3_stmt objects never escape the confines of the
SQLiteConnection that owns them, we can also greatly simplify
the design of the SQLiteProgram, SQLiteQuery and SQLiteStatement
objects. They no longer have to wrangle a native sqlite3_stmt
object pointer and manage its lifecycle. So now all they do
is hold bind arguments and provide a fancy API.
All of the JNI glue related to managing database connections
and performing transactions is now bound to SQLiteConnection
(rather than being scattered everywhere). This makes sense because
SQLiteConnection owns the native sqlite3 object, so it is the
only class in the system that can interact with the native
SQLite database directly. Encapsulation for the win.
One particularly tricky part of this change is managing the
ownership of SQLiteConnection objects. At any given time,
a SQLiteConnection is either owned by a SQLiteConnectionPool
or by a SQLiteSession. SQLiteConnections should never be leaked,
but we handle that case too (and yell about it with CloseGuard).
A SQLiteSession object is responsible for acquiring and releasing
a SQLiteConnection object on behalf of a single thread as needed.
For example, the session acquires a connection when a transaction
begins and releases it when finished. If the session cannot
acquire a connection immediately, then the requested operation
blocks until a connection becomes available.
SQLiteSessions are thread-local. A SQLiteDatabase assigns a
distinct session to each thread that performs database operations.
This is very very important. First, it prevents two threads
from trying to use the same SQLiteConnection at the same time
(because two threads can't share the same session).
Second, it prevents a single thread from trying to acquire two
SQLiteConnections simultaneously from the same database (because
a single thread can't have two sessions for the same database which,
in addition to being greedy, could result in a deadlock).
There is strict layering between the various database objects,
objects at lower layers are not aware of objects at higher layers.
Moreover, objects at higher layers generally own objects at lower
layers and are responsible for ensuring they are properly disposed
when no longer needed (good for the environment).
API layer: SQLiteDatabase, SQLiteProgram, SQLiteQuery, SQLiteStatement.
Session layer: SQLiteSession.
Connection layer: SQLiteConnectionPool, SQLiteConnection.
Native layer: JNI glue.
By avoiding cyclic dependencies between layers, we make the
architecture much more intelligible, maintainable and robust.
Finally, this change adds a great deal of new debugging information.
It is now possible to view a list of the most recent database
operations including how long they took to run using
"adb shell dumpsys dbinfo". (Because most of the interesting
work happens in SQLiteConnection, it is easy to add debugging
instrumentation to track all database operations in one place.)
Change-Id: Iffb4ce72d8bcf20b4e087d911da6aa84d2f15297
2011-10-31 17:48:13 -07:00
|
|
|
REG_JNI(register_android_database_SQLiteConnection),
|
|
|
|
REG_JNI(register_android_database_SQLiteGlobal),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_database_SQLiteDebug),
|
|
|
|
REG_JNI(register_android_os_Debug),
|
|
|
|
REG_JNI(register_android_os_FileObserver),
|
2010-05-06 12:07:10 -07:00
|
|
|
REG_JNI(register_android_os_MessageQueue),
|
2012-01-13 08:31:39 -05:00
|
|
|
REG_JNI(register_android_os_SELinux),
|
2012-03-09 14:41:15 -08:00
|
|
|
REG_JNI(register_android_os_Trace),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_os_UEventObserver),
|
|
|
|
REG_JNI(register_android_net_LocalSocketImpl),
|
|
|
|
REG_JNI(register_android_net_NetworkUtils),
|
2010-04-07 17:30:50 -07:00
|
|
|
REG_JNI(register_android_net_TrafficStats),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_os_MemoryFile),
|
|
|
|
REG_JNI(register_com_android_internal_os_ZygoteInit),
|
2014-03-31 13:41:26 +01:00
|
|
|
REG_JNI(register_com_android_internal_os_Zygote),
|
2014-05-09 15:26:59 -07:00
|
|
|
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_hardware_Camera),
|
2013-07-25 17:12:05 -07:00
|
|
|
REG_JNI(register_android_hardware_camera2_CameraMetadata),
|
2014-05-09 19:58:49 -07:00
|
|
|
REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice),
|
2014-05-29 17:17:07 -07:00
|
|
|
REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement),
|
2014-05-22 12:33:54 -07:00
|
|
|
REG_JNI(register_android_hardware_camera2_DngCreator),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_hardware_SensorManager),
|
2011-08-29 20:11:07 -04:00
|
|
|
REG_JNI(register_android_hardware_SerialPort),
|
2014-04-18 17:50:49 -07:00
|
|
|
REG_JNI(register_android_hardware_SoundTrigger),
|
2010-12-30 13:39:37 -05:00
|
|
|
REG_JNI(register_android_hardware_UsbDevice),
|
2011-03-11 08:18:08 -05:00
|
|
|
REG_JNI(register_android_hardware_UsbDeviceConnection),
|
2010-12-30 13:39:37 -05:00
|
|
|
REG_JNI(register_android_hardware_UsbRequest),
|
2014-07-09 10:46:39 -07:00
|
|
|
REG_JNI(register_android_hardware_location_ActivityRecognitionHardware),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_media_AudioRecord),
|
|
|
|
REG_JNI(register_android_media_AudioSystem),
|
|
|
|
REG_JNI(register_android_media_AudioTrack),
|
|
|
|
REG_JNI(register_android_media_JetPlayer),
|
2012-09-04 21:57:59 -07:00
|
|
|
REG_JNI(register_android_media_RemoteDisplay),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_media_ToneGenerator),
|
|
|
|
|
|
|
|
REG_JNI(register_android_opengl_classes),
|
2011-09-02 15:36:33 -07:00
|
|
|
REG_JNI(register_android_server_NetworkManagementSocketTagger),
|
2009-03-03 19:31:44 -08:00
|
|
|
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
|
2009-06-12 11:06:24 -07:00
|
|
|
REG_JNI(register_android_backup_BackupDataInput),
|
2009-05-19 13:41:21 -07:00
|
|
|
REG_JNI(register_android_backup_BackupDataOutput),
|
2009-06-18 20:10:37 -07:00
|
|
|
REG_JNI(register_android_backup_FileBackupHelperBase),
|
2009-06-25 18:29:18 -04:00
|
|
|
REG_JNI(register_android_backup_BackupHelperDispatcher),
|
Full local backup infrastructure
This is the basic infrastructure for pulling a full(*) backup of the
device's data over an adb(**) connection to the local device. The
basic process consists of these interacting pieces:
1. The framework's BackupManagerService, which coordinates the
collection of app data and routing to the destination.
2. A new framework-provided BackupAgent implementation called
FullBackupAgent, which is instantiated in the target applications'
processes in turn, and knows how to emit a datastream that contains
all of the app's saved data files.
3. A new shell-level program called "bu" that is used to bridge from
adb to the framework's Backup Manager.
4. adb itself, which now knows how to use 'bu' to kick off a backup
operation and pull the resulting data stream to the desktop host.
5. A system-provided application that verifies with the user that
an attempted backup/restore operation is in fact expected and to
be allowed.
The full agent implementation is not used during normal operation of
the delta-based app-customized remote backup process. Instead it's
used during user-confirmed *full* backup of applications and all their
data to a local destination, e.g. via the adb connection.
The output format is 'tar'. This makes it very easy for the end
user to examine the resulting dataset, e.g. for purpose of extracting
files for debug purposes; as well as making it easy to contemplate
adding things like a direct gzip stage to the data pipeline during
backup/restore. It also makes it convenient to construct and maintain
synthetic backup datasets for testing purposes.
Within the tar format, certain artificial conventions are used.
All files are stored within top-level directories according to
their semantic origin:
apps/pkgname/a/ : Application .apk file itself
apps/pkgname/obb/: The application's associated .obb containers
apps/pkgname/f/ : The subtree rooted at the getFilesDir() location
apps/pkgname/db/ : The subtree rooted at the getDatabasePath() parent
apps/pkgname/sp/ : The subtree rooted at the getSharedPrefsFile() parent
apps/pkgname/r/ : Files stored relative to the root of the app's file tree
apps/pkgname/c/ : Reserved for the app's getCacheDir() tree; not stored.
For each package, the first entry in the tar stream is a file called
"_manifest", nominally rooted at apps/pkgname. This file contains some
metadata about the package whose data is stored in the archive.
The contents of shared storage can optionally be included in the tar
stream. It is placed in the synthetic location:
shared/...
uid/gid are ignored; app uids are assigned at install time, and the
app's data is handled from within its own execution environment, so
will automatically have the app's correct uid.
Forward-locked .apk files are never backed up. System-partition
.apk files are not backed up unless they have been overridden by a
post-factory upgrade, in which case the current .apk *is* backed up --
i.e. the .apk that matches the on-disk data. The manifest preceding
each application's portion of the tar stream provides version numbers
and signature blocks for version checking, as well as an indication
of whether the restore logic should expect to install the .apk before
extracting the data.
System packages can designate their own full backup agents. This is
to manage things like the settings provider which (a) cannot be shut
down on the fly in order to do a clean snapshot of their file trees,
and (b) manage data that is not only irrelevant but actively hostile
to non-identical devices -- CDMA telephony settings would seriously
mess up a GSM device if emplaced there blind, for example.
When a full backup or restore is initiated from adb, the system will
present a confirmation UI that the user must explicitly respond to
within a short [~ 30 seconds] timeout. This is to avoid the
possibility of malicious desktop-side software secretly grabbing a copy
of all the user's data for nefarious purposes.
(*) The backup is not strictly a full mirror. In particular, the
settings database is not cloned; it is handled the same way that
it is in cloud backup/restore. This is because some settings
are actively destructive if cloned onto a different (or
especially a different-model) device: telephony settings and
AndroidID are good examples of this.
(**) On the framework side it doesn't care that it's adb; it just
sends the tar stream to a file descriptor. This can easily be
retargeted around whatever transport we might decide to use
in the future.
KNOWN ISSUES:
* the security UI is desperately ugly; no proper designs have yet
been done for it
* restore is not yet implemented
* shared storage backup is not yet implemented
* symlinks aren't yet handled, though some infrastructure for
dealing with them has been put in place.
Change-Id: Ia8347611e23b398af36ea22c36dff0a276b1ce91
2011-04-01 14:43:32 -07:00
|
|
|
REG_JNI(register_android_app_backup_FullBackup),
|
2011-03-24 10:51:31 -07:00
|
|
|
REG_JNI(register_android_app_ActivityThread),
|
2010-05-04 11:40:40 -07:00
|
|
|
REG_JNI(register_android_app_NativeActivity),
|
Native input dispatch rewrite work in progress.
The old dispatch mechanism has been left in place and continues to
be used by default for now. To enable native input dispatch,
edit the ENABLE_NATIVE_DISPATCH constant in WindowManagerPolicy.
Includes part of the new input event NDK API. Some details TBD.
To wire up input dispatch, as the ViewRoot adds a window to the
window session it receives an InputChannel object as an output
argument. The InputChannel encapsulates the file descriptors for a
shared memory region and two pipe end-points. The ViewRoot then
provides the InputChannel to the InputQueue. Behind the
scenes, InputQueue simply attaches handlers to the native PollLoop object
that underlies the MessageQueue. This way MessageQueue doesn't need
to know anything about input dispatch per-se, it just exposes (in native
code) a PollLoop that other components can use to monitor file descriptor
state changes.
There can be zero or more targets for any given input event. Each
input target is specified by its input channel and some parameters
including flags, an X/Y coordinate offset, and the dispatch timeout.
An input target can request either synchronous dispatch (for foreground apps)
or asynchronous dispatch (fire-and-forget for wallpapers and "outside"
targets). Currently, finding the appropriate input targets for an event
requires a call back into the WindowManagerServer from native code.
In the future this will be refactored to avoid most of these callbacks
except as required to handle pending focus transitions.
End-to-end event dispatch mostly works!
To do: event injection, rate limiting, ANRs, testing, optimization, etc.
Change-Id: I8c36b2b9e0a2d27392040ecda0f51b636456de25
2010-04-22 18:58:52 -07:00
|
|
|
REG_JNI(register_android_view_InputChannel),
|
2011-12-01 14:01:49 -08:00
|
|
|
REG_JNI(register_android_view_InputEventReceiver),
|
2013-03-26 15:42:39 -07:00
|
|
|
REG_JNI(register_android_view_InputEventSender),
|
2013-04-10 21:12:00 -07:00
|
|
|
REG_JNI(register_android_view_InputQueue),
|
Native input dispatch rewrite work in progress.
The old dispatch mechanism has been left in place and continues to
be used by default for now. To enable native input dispatch,
edit the ENABLE_NATIVE_DISPATCH constant in WindowManagerPolicy.
Includes part of the new input event NDK API. Some details TBD.
To wire up input dispatch, as the ViewRoot adds a window to the
window session it receives an InputChannel object as an output
argument. The InputChannel encapsulates the file descriptors for a
shared memory region and two pipe end-points. The ViewRoot then
provides the InputChannel to the InputQueue. Behind the
scenes, InputQueue simply attaches handlers to the native PollLoop object
that underlies the MessageQueue. This way MessageQueue doesn't need
to know anything about input dispatch per-se, it just exposes (in native
code) a PollLoop that other components can use to monitor file descriptor
state changes.
There can be zero or more targets for any given input event. Each
input target is specified by its input channel and some parameters
including flags, an X/Y coordinate offset, and the dispatch timeout.
An input target can request either synchronous dispatch (for foreground apps)
or asynchronous dispatch (fire-and-forget for wallpapers and "outside"
targets). Currently, finding the appropriate input targets for an event
requires a call back into the WindowManagerServer from native code.
In the future this will be refactored to avoid most of these callbacks
except as required to handle pending focus transitions.
End-to-end event dispatch mostly works!
To do: event injection, rate limiting, ANRs, testing, optimization, etc.
Change-Id: I8c36b2b9e0a2d27392040ecda0f51b636456de25
2010-04-22 18:58:52 -07:00
|
|
|
REG_JNI(register_android_view_KeyEvent),
|
|
|
|
REG_JNI(register_android_view_MotionEvent),
|
2011-04-12 22:39:53 -07:00
|
|
|
REG_JNI(register_android_view_PointerIcon),
|
2011-03-14 19:39:54 -07:00
|
|
|
REG_JNI(register_android_view_VelocityTracker),
|
2010-07-01 08:10:18 -07:00
|
|
|
|
|
|
|
REG_JNI(register_android_content_res_ObbScanner),
|
2010-08-04 11:12:40 -07:00
|
|
|
REG_JNI(register_android_content_res_Configuration),
|
2010-11-03 19:41:18 -07:00
|
|
|
|
|
|
|
REG_JNI(register_android_animation_PropertyValuesHolder),
|
2011-07-12 14:14:01 -07:00
|
|
|
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
|
2013-01-14 16:48:51 -08:00
|
|
|
REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
|
2009-03-03 19:31:44 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Register android native functions with the VM.
|
|
|
|
*/
|
|
|
|
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This hook causes all future threads created in this process to be
|
|
|
|
* attached to the JavaVM. (This needs to go away in favor of JNI
|
|
|
|
* Attach calls.)
|
|
|
|
*/
|
|
|
|
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
|
|
|
|
|
2011-10-20 11:56:00 +01:00
|
|
|
ALOGV("--- registering native functions ---\n");
|
2009-03-03 19:31:44 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Every "register" function calls one or more things that return
|
|
|
|
* a local reference (e.g. FindClass). Because we haven't really
|
|
|
|
* started the VM yet, they're all getting stored in the base frame
|
|
|
|
* and never released. Use Push/Pop to manage the storage.
|
|
|
|
*/
|
|
|
|
env->PushLocalFrame(200);
|
|
|
|
|
|
|
|
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
|
|
|
|
env->PopLocalFrame(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
env->PopLocalFrame(NULL);
|
|
|
|
|
|
|
|
//createJavaThread("fubar", quickTest, (void*) "hello");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidRuntime* AndroidRuntime::getRuntime()
|
|
|
|
{
|
|
|
|
return gCurRuntime;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used by WithFramework to register native functions.
|
|
|
|
*/
|
|
|
|
extern "C"
|
|
|
|
jint Java_com_android_internal_util_WithFramework_registerNatives(
|
|
|
|
JNIEnv* env, jclass clazz) {
|
|
|
|
return register_jni_procs(gRegJNI, NELEM(gRegJNI), env);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used by LoadClass to register native functions.
|
|
|
|
*/
|
|
|
|
extern "C"
|
|
|
|
jint Java_LoadClass_registerNatives(JNIEnv* env, jclass clazz) {
|
|
|
|
return register_jni_procs(gRegJNI, NELEM(gRegJNI), env);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace android
|