summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/android/java/base.xml2
-rwxr-xr-xbuild/android/adb_install_content_shell2
-rwxr-xr-xbuild/android/envsetup.sh8
-rwxr-xr-xbuild/android/gdb_content_shell6
-rw-r--r--build/common.gypi9
-rw-r--r--build/java.gypi4
-rw-r--r--content/app/content_main_runner.cc29
-rw-r--r--content/browser/android/command_line.cc78
-rw-r--r--content/browser/android/command_line.h18
-rw-r--r--content/browser/android/content_jni_registrar.cc26
-rw-r--r--content/browser/android/content_jni_registrar.h19
-rw-r--r--content/browser/android/jni_helper.cc158
-rw-r--r--content/browser/android/jni_helper.h92
-rw-r--r--content/browser/android/library_loader_hooks.cc30
-rw-r--r--content/browser/android/trace_event_binding.cc93
-rw-r--r--content/browser/android/trace_event_binding.h13
-rw-r--r--content/content.gyp22
-rw-r--r--content/content_browser.gypi14
-rw-r--r--content/content_jni.gypi27
-rw-r--r--content/content_shell.gypi18
-rw-r--r--content/plugin/webplugin_proxy.cc10
-rw-r--r--content/ppapi_plugin/ppapi_webkitplatformsupport_impl.cc21
-rw-r--r--content/public/android/java/content.xml8
-rw-r--r--content/public/android/java/org/chromium/content/browser/CommandLine.java467
-rw-r--r--content/public/android/java/org/chromium/content/browser/JNIHelper.java71
-rw-r--r--content/public/android/java/org/chromium/content/browser/LibraryLoader.java239
-rw-r--r--content/public/android/java/org/chromium/content/browser/TraceEvent.java143
-rw-r--r--content/shell/android/content_shell_apk.xml7
-rw-r--r--content/shell/android/java/org/chromium/content_shell/ContentShellActivity.java32
-rw-r--r--content/shell/android/java/org/chromium/content_shell/ContentShellApplication.java8
-rw-r--r--content/shell/android/shell_library_loader.cc38
-rw-r--r--media/base/android/java/media.xml18
-rw-r--r--media/media.gyp12
-rw-r--r--net/android/java/net.xml2
34 files changed, 1669 insertions, 75 deletions
diff --git a/base/android/java/base.xml b/base/android/java/base.xml
index 2da1441..4bb3387 100644
--- a/base/android/java/base.xml
+++ b/base/android/java/base.xml
@@ -10,7 +10,7 @@
<property name="sdk.version" value="${env.ANDROID_SDK_VERSION}"/>
<property name="src" location="."/>
<property name="dist" location="dist"/>
- <property name="out.dir" location="${PRODUCT_DIR}"/>
+ <property name="out.dir" location="${PRODUCT_DIR}/lib.java"/>
<!-- TODO(jrg): establish a standard for the intermediate java
directories. Settle on a standard once ant/jar build files
like this are androidified -->
diff --git a/build/android/adb_install_content_shell b/build/android/adb_install_content_shell
index b4d8052..d1a8ee9 100755
--- a/build/android/adb_install_content_shell
+++ b/build/android/adb_install_content_shell
@@ -4,4 +4,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+# install -r doesn't always work? Try uninstalling first.
+adb uninstall org.chromium.content_shell
adb install -r ${CHROME_SRC}/out/Release/content_shell/ContentShell-debug.apk
diff --git a/build/android/envsetup.sh b/build/android/envsetup.sh
index ead8fdf..dcf51ee 100755
--- a/build/android/envsetup.sh
+++ b/build/android/envsetup.sh
@@ -62,6 +62,14 @@ case "${TARGET_PRODUCT-full}" in
return 1
esac
+# If we are building NDK/SDK, and in the upstream (open source) tree,
+# define a special variable for bringup purposes.
+case "${ANDROID_BUILD_TOP-undefined}" in
+ "undefined")
+ DEFINES+=" android_upstream_bringup=1"
+ ;;
+esac
+
toolchain_path="${ANDROID_NDK_ROOT}/toolchains/${toolchain_arch}/prebuilt/"
export ANDROID_TOOLCHAIN="${toolchain_path}/${toolchain_dir}/bin/"
diff --git a/build/android/gdb_content_shell b/build/android/gdb_content_shell
index 54a705d..94c0962 100755
--- a/build/android/gdb_content_shell
+++ b/build/android/gdb_content_shell
@@ -72,8 +72,9 @@ fi
# gdb commands
cmdfile=$(mktemp /tmp/gdb_android_XXXXXXXX)
cat >$cmdfile<<EOF
-set solib-absolute-prefix null
+# set solib-absolute-prefix null
set solib-search-path ${shared_lib_dir}
+file ${app_process}
target remote :4321
EOF
@@ -85,5 +86,6 @@ else
echo Using $gdb
fi
-${gdb} -x $cmdfile $* $app_process
+# ${gdb} -x $cmdfile $* $app_process
+${gdb} -x $cmdfile $*
rm $cmdfile
diff --git a/build/common.gypi b/build/common.gypi
index 7e999a7..b79ae1b 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -47,6 +47,11 @@
# Enable inclusion of touch-optimized resources.
# TODO(joi): Rename to enable_touch_assets.
'enable_metro%': 0,
+
+ # Is this change part of the android upstream bringup?
+ # Allows us to *temporarily* disable certain things for
+ # staging. Only set to 1 in a GYP_DEFINES.
+ 'android_upstream_bringup%': 0,
},
# Copy conditionally-set variables out one scope.
'chromeos%': '<(chromeos)',
@@ -58,6 +63,7 @@
'enable_hidpi%': '<(enable_hidpi)',
'enable_touch_ui%': '<(enable_touch_ui)',
'enable_metro%': '<(enable_metro)',
+ 'android_upstream_bringup%': '<(android_upstream_bringup)',
# Compute the architecture that we're building on.
'conditions': [
@@ -2387,6 +2393,9 @@
'-lm',
],
'conditions': [
+ ['android_upstream_bringup==1', {
+ 'defines': ['ANDROID_UPSTREAM_BRINGUP=1',],
+ }],
['android_build_type==0', {
'ldflags': [
'--sysroot=<(android_ndk_sysroot)',
diff --git a/build/java.gypi b/build/java.gypi
index bb60a8f..c05981d 100644
--- a/build/java.gypi
+++ b/build/java.gypi
@@ -25,7 +25,7 @@
# base/android/java/org/chromium/base/Bar.java
#
# Finally, the generated jar-file will be:
-# <(PRODUCT_DIR)/chromium_base.jar
+# <(PRODUCT_DIR)/lib.java/chromium_base.jar
#
# TODO(yfriedman): The "finally" statement isn't entirely true yet, as we don't
# auto-generate the ant file yet.
@@ -40,7 +40,7 @@
'<!@(find <(java_in_dir) -name "*.java")'
],
'outputs': [
- '<(PRODUCT_DIR)/chromium_<(package_name).jar',
+ '<(PRODUCT_DIR)/lib.java/chromium_<(package_name).jar',
],
'action': [
'ant',
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index f87bac4..02d9b44 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -79,7 +79,7 @@ extern int PpapiBrokerMain(const content::MainFunctionParams&);
extern int RendererMain(const content::MainFunctionParams&);
extern int WorkerMain(const content::MainFunctionParams&);
extern int UtilityMain(const content::MainFunctionParams&);
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
namespace content {
extern int ZygoteMain(const content::MainFunctionParams&,
content::ZygoteForkDelegate* forkdelegate);
@@ -194,7 +194,7 @@ struct MainFunction {
int (*function)(const content::MainFunctionParams&);
};
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
// On platforms that use the zygote, we have a special subset of
// subprocesses that are launched via the zygote. This function
// fills in some process-launching bits around ZygoteMain().
@@ -293,7 +293,7 @@ int RunNamedProcessTypeMain(
}
}
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
// Zygote startup is special -- see RunZygote comments above
// for why we don't use ZygoteMain directly.
if (process_type == switches::kZygoteProcess)
@@ -352,6 +352,7 @@ static void ReleaseFreeMemoryThunk() {
virtual int Initialize(int argc,
const char** argv,
content::ContentMainDelegate* delegate) OVERRIDE {
+
// NOTE(willchan): One might ask why this call is done here rather than in
// process_util_linux.cc with the definition of
// EnableTerminationOnOutOfMemory(). That's because base shouldn't have a
@@ -367,17 +368,24 @@ static void ReleaseFreeMemoryThunk() {
base::allocator::SetReleaseFreeMemoryFunction(ReleaseFreeMemoryThunk);
#endif
+ // On Android,
+ // - setlocale() is not supported.
+ // - We do not override the signal handlers so that we can get
+ // stack trace when crashing.
+ // - The ipc_fd is passed through the Java service.
+ // Thus, these are all disabled.
#if !defined(OS_ANDROID)
// Set C library locale to make sure CommandLine can parse argument values
// in correct encoding.
setlocale(LC_ALL, "");
-#endif
SetupSignalHandlers();
base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance();
g_fds->Set(kPrimaryIPCChannel,
kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
+#endif
+
#if defined(OS_LINUX) || defined(OS_OPENBSD)
g_fds->Set(kCrashDumpSignal,
kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor);
@@ -391,8 +399,11 @@ static void ReleaseFreeMemoryThunk() {
base::EnableTerminationOnHeapCorruption();
base::EnableTerminationOnOutOfMemory();
+ // On Android, AtExitManager is set up when library is loaded.
+#if !defined(OS_ANDROID)
// The exit manager is in charge of calling the dtors of singleton objects.
exit_manager_.reset(new base::AtExitManager);
+#endif
#if defined(OS_MACOSX)
// We need this pool for all the objects created before we get to the
@@ -402,7 +413,11 @@ static void ReleaseFreeMemoryThunk() {
autorelease_pool_.reset(new base::mac::ScopedNSAutoreleasePool());
#endif
+ // On Android, the command line is initialized when library is loaded.
+ // (But *is* initialized here for content shell bringup)
+#if !defined(OS_ANDROID) || defined(ANDROID_UPSTREAM_BRINGUP)
CommandLine::Init(argc, argv);
+#endif
int exit_code;
if (delegate && delegate->BasicStartupComplete(&exit_code))
@@ -473,6 +488,12 @@ static void ReleaseFreeMemoryThunk() {
ui::RegisterPathProvider();
content::RegisterPathProvider();
+
+ // TODO(jrg): "up to here" is how far we get without crashing on
+ // content shell bringup.
+#if defined(ANDROID_UPSTREAM_BRINGUP)
+ return 0;
+#endif
content::RegisterContentSchemes(true);
CHECK(icu_util::Initialize());
diff --git a/content/browser/android/command_line.cc b/content/browser/android/command_line.cc
new file mode 100644
index 0000000..1883b07f
--- /dev/null
+++ b/content/browser/android/command_line.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/command_line.h"
+
+#include "base/android/jni_string.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "jni/command_line_jni.h"
+#include "content/browser/android/jni_helper.h"
+
+using base::android::ConvertJavaStringToUTF8;
+
+namespace {
+
+void AppendJavaStringArrayToCommandLine(JNIEnv* env,
+ jobjectArray array,
+ bool includes_program) {
+ CommandLine::StringVector vec;
+ if (array)
+ ConvertJavaArrayOfStringsToVectorOfStrings(env, array, &vec);
+ if (!includes_program)
+ vec.insert(vec.begin(), "");
+ CommandLine extra_command_line(vec);
+ CommandLine::ForCurrentProcess()->AppendArguments(extra_command_line,
+ includes_program);
+}
+
+} // namespace
+
+static void Reset(JNIEnv* env, jclass clazz) {
+ CommandLine::Reset();
+}
+
+static jboolean HasSwitch(JNIEnv* env, jclass clazz, jstring jswitch) {
+ std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+ return CommandLine::ForCurrentProcess()->HasSwitch(switch_string);
+}
+
+static jstring GetSwitchValue(JNIEnv* env, jclass clazz, jstring jswitch) {
+ std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+ std::string value(CommandLine::ForCurrentProcess()->GetSwitchValueNative(
+ switch_string));
+ if (value.empty())
+ return 0;
+ // OK to release, JNI binding.
+ return base::android::ConvertUTF8ToJavaString(env, value).Release();
+}
+
+static void AppendSwitch(JNIEnv* env, jclass clazz, jstring jswitch) {
+ std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+ CommandLine::ForCurrentProcess()->AppendSwitch(switch_string);
+}
+
+static void AppendSwitchWithValue(JNIEnv* env, jclass clazz,
+ jstring jswitch, jstring jvalue) {
+ std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+ std::string value_string (ConvertJavaStringToUTF8(env, jvalue));
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(switch_string,
+ value_string);
+}
+
+static void AppendSwitchesAndArguments(JNIEnv* env, jclass clazz,
+ jobjectArray array) {
+ AppendJavaStringArrayToCommandLine(env, array, false);
+}
+
+void InitNativeCommandLineFromJavaArray(JNIEnv* env, jobjectArray array) {
+ // TODO(port): Make an overload of Init() that takes StringVector rather than
+ // have to round-trip via AppendArguments.
+ CommandLine::Init(0, NULL);
+ AppendJavaStringArrayToCommandLine(env, array, true);
+}
+
+bool RegisterCommandLine(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
diff --git a/content/browser/android/command_line.h b/content/browser/android/command_line.h
new file mode 100644
index 0000000..5e44080
--- /dev/null
+++ b/content/browser/android/command_line.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_COMMAND_LINE_H_
+#define CONTENT_BROWSER_ANDROID_COMMAND_LINE_H_
+#pragma once
+
+#include <jni.h>
+
+// Appends all strings in the given array as flags to the Chrome command line.
+void InitNativeCommandLineFromJavaArray(JNIEnv* env,
+ jobjectArray init_command_line);
+
+// JNI registration boilerplate.
+bool RegisterCommandLine(JNIEnv* env);
+
+#endif // CONTENT_BROWSER_ANDROID_COMMAND_LINE_H_
diff --git a/content/browser/android/content_jni_registrar.cc b/content/browser/android/content_jni_registrar.cc
new file mode 100644
index 0000000..c32cc50
--- /dev/null
+++ b/content/browser/android/content_jni_registrar.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/content_jni_registrar.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_registrar.h"
+#include "content/browser/android/command_line.h"
+#include "content/browser/android/trace_event_binding.h"
+
+namespace content {
+namespace android {
+
+base::android::RegistrationMethod kContentRegisteredMethods[] = {
+ { "CommandLine", RegisterCommandLine },
+ { "TraceEvent", RegisterTraceEvent },
+};
+
+bool RegisterJni(JNIEnv* env) {
+ return RegisterNativeMethods(env, kContentRegisteredMethods,
+ arraysize(kContentRegisteredMethods));
+}
+
+} // namespace android
+} // namespace content
diff --git a/content/browser/android/content_jni_registrar.h b/content/browser/android/content_jni_registrar.h
new file mode 100644
index 0000000..ce41c63
--- /dev/null
+++ b/content/browser/android/content_jni_registrar.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_CONTENT_JNI_REGISTRAR_H_
+#define CONTENT_BROWSER_ANDROID_CONTENT_JNI_REGISTRAR_H_
+
+#include <jni.h>
+
+namespace content {
+namespace android {
+
+// Register all JNI bindings necessary for content.
+bool RegisterJni(JNIEnv* env);
+
+} // namespace android
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_CONTENT_JNI_REGISTRAR_H_
diff --git a/content/browser/android/jni_helper.cc b/content/browser/android/jni_helper.cc
new file mode 100644
index 0000000..bd7bce6
--- /dev/null
+++ b/content/browser/android/jni_helper.cc
@@ -0,0 +1,158 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/jni_helper.h"
+
+#include <android/bitmap.h>
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_helper.h"
+#include "base/android/jni_string.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "jni/jni_helper_jni.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+using base::android::AttachCurrentThread;
+using base::android::CheckException;
+using base::android::GetStaticMethodID;
+using base::android::GetClass;
+using base::android::GetMethodID;
+using base::android::ScopedJavaLocalRef;
+
+AutoLocalFrame::AutoLocalFrame(int capacity) {
+ AttachCurrentThread()->PushLocalFrame(capacity);
+}
+
+AutoLocalFrame::~AutoLocalFrame() {
+ AttachCurrentThread()->PopLocalFrame(NULL);
+}
+
+AutoLockJavaBitmap::AutoLockJavaBitmap(jobject bitmap) :
+ bitmap_(bitmap),
+ pixels_(NULL) {
+ int err = AndroidBitmap_lockPixels(AttachCurrentThread(), bitmap_, &pixels_);
+ DCHECK(!err);
+ DCHECK(pixels_);
+}
+
+AutoLockJavaBitmap::~AutoLockJavaBitmap() {
+ // TODO(aelias): Add AndroidBitmap_notifyPixelsChanged() call here
+ // once it's added to the NDK. Using hardware bitmaps will
+ // be broken until this is fixed.
+ int err = AndroidBitmap_unlockPixels(AttachCurrentThread(), bitmap_);
+ DCHECK(!err);
+}
+
+gfx::Size AutoLockJavaBitmap::size() const {
+ AndroidBitmapInfo info;
+ int err = AndroidBitmap_getInfo(AttachCurrentThread(), bitmap_, &info);
+ DCHECK(!err);
+ return gfx::Size(info.width, info.height);
+}
+
+int AutoLockJavaBitmap::format() const {
+ AndroidBitmapInfo info;
+ int err = AndroidBitmap_getInfo(AttachCurrentThread(), bitmap_, &info);
+ DCHECK(!err);
+ return info.format;
+}
+
+uint32_t AutoLockJavaBitmap::stride() const {
+ AndroidBitmapInfo info;
+ int err = AndroidBitmap_getInfo(AttachCurrentThread(), bitmap_, &info);
+ DCHECK(!err);
+ return info.stride;
+}
+
+void PrintJavaStackTrace() {
+ JNIEnv* env = AttachCurrentThread();
+
+ ScopedJavaLocalRef<jclass> throwable_clazz =
+ GetClass(env, "java/lang/Throwable");
+ jmethodID throwable_constructor =
+ GetMethodID(env, throwable_clazz, "<init>", "()V");
+
+ ScopedJavaLocalRef<jobject> throwable_object(env,
+ env->NewObject(throwable_clazz.obj(), throwable_constructor));
+ DCHECK(!throwable_object.is_null());
+ jmethodID printstacktrace =
+ GetMethodID(env, throwable_clazz, "printStackTrace", "()V");
+
+ env->CallVoidMethod(throwable_object.obj(), printstacktrace);
+ CheckException(env);
+}
+
+void ConvertJavaArrayOfStringsToVectorOfStrings(
+ JNIEnv* env,
+ jobjectArray jstrings,
+ std::vector<std::string>* vec) {
+ vec->clear();
+ jsize length = env->GetArrayLength(jstrings);
+ for (jsize i = 0; i < length; ++i) {
+ jstring item = static_cast<jstring>(
+ env->GetObjectArrayElement(jstrings, i));
+ vec->push_back(base::android::ConvertJavaStringToUTF8(env, item));
+ env->DeleteLocalRef(item);
+ }
+}
+
+ScopedJavaLocalRef<jobject> CreateJavaBitmap(const gfx::Size& size, bool keep) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> bitmap =
+ Java_JNIHelper_createJavaBitmap(env, size.width(), size.height(), keep);
+ CheckException(env);
+ return bitmap;
+}
+
+void DeleteJavaBitmap(jobject bitmap) {
+ JNIEnv* env = AttachCurrentThread();
+ Java_JNIHelper_deleteJavaBitmap(env, bitmap);
+ CheckException(env);
+}
+
+void PaintJavaBitmapToJavaBitmap(jobject source_bitmap,
+ const gfx::Rect& source_rect,
+ jobject dest_bitmap,
+ const gfx::Rect& dest_rect) {
+ TRACE_EVENT0("jni", "PaintJavaBitmapToJavaBitmap");
+ JNIEnv* env = AttachCurrentThread();
+
+ Java_JNIHelper_paintJavaBitmapToJavaBitmap(env,
+ source_bitmap,
+ source_rect.x(),
+ source_rect.y(),
+ source_rect.right(),
+ source_rect.bottom(),
+ dest_bitmap,
+ dest_rect.x(),
+ dest_rect.y(),
+ dest_rect.right(),
+ dest_rect.bottom());
+ CheckException(env);
+}
+
+ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap* skbitmap) {
+ TRACE_EVENT0("jni", "ConvertToJavaBitmap");
+ DCHECK(skbitmap);
+ DCHECK_EQ(skbitmap->bytesPerPixel(), 4);
+
+ // Create a temporary java bitmap.
+ ScopedJavaLocalRef<jobject> jbitmap =
+ CreateJavaBitmap(gfx::Size(skbitmap->width(), skbitmap->height()), false);
+
+ // Lock and copy the pixels from the skbitmap.
+ SkAutoLockPixels src_lock(*skbitmap);
+ AutoLockJavaBitmap dst_lock(jbitmap.obj());
+ void* src_pixels = skbitmap->getPixels();
+ void* dst_pixels = dst_lock.pixels();
+ memcpy(dst_pixels, src_pixels, skbitmap->getSize());
+
+ return jbitmap;
+}
+
+bool RegisterJniHelper(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
diff --git a/content/browser/android/jni_helper.h b/content/browser/android/jni_helper.h
new file mode 100644
index 0000000..c7fa569
--- /dev/null
+++ b/content/browser/android/jni_helper.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_JNI_HELPER_H_
+#define CONTENT_BROWSER_ANDROID_JNI_HELPER_H_
+
+#include <jni.h>
+#include <string>
+#include <vector>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/string16.h"
+#include "ui/gfx/rect.h"
+
+class SkBitmap;
+namespace gfx {
+class Size;
+}
+
+// Auto creator/destructor for a JNI frame for local references. This allows
+// safely having more than 16 local references, and avoids calls to
+// DeleteLocalRef.
+// This should be created on the stack.
+class AutoLocalFrame {
+ public:
+ AutoLocalFrame(int capacity);
+ ~AutoLocalFrame();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutoLocalFrame);
+};
+
+// Create this object on the stack to obtain the pixels of a Java Bitmap and
+// automatically release them on destruction.
+// Similar to SkAutoLockPixels, except that it operates on a Java Bitmap
+// object via the Android NDK.
+class AutoLockJavaBitmap {
+ public:
+ AutoLockJavaBitmap(jobject bitmap);
+ ~AutoLockJavaBitmap();
+
+ void* pixels() const { return pixels_; }
+ gfx::Size size() const;
+ // Formats are in android/bitmap.h; e.g. ANDROID_BITMAP_FORMAT_RGBA_8888 */
+ int format() const;
+ uint32_t stride() const;
+
+ private:
+ jobject bitmap_;
+ void* pixels_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutoLockJavaBitmap);
+};
+
+// Tell Java to write its current stack trace into Android logs. Note that the
+// trace will stop at the entry point into C++ code.
+void PrintJavaStackTrace();
+
+// Fills in the given vector<string> from a java String[].
+void ConvertJavaArrayOfStringsToVectorOfStrings(
+ JNIEnv* env,
+ jobjectArray jstrings,
+ std::vector<std::string>* vec);
+
+// Helper method to create an Android Java Bitmap object. You can use the
+// AutoLockJavaBitmap class to manipulate its pixels, and pass it back up
+// to Java code for drawing. Returns a JNI local reference to the bitmap.
+// If 'keep' is true, then a reference will be kept in a static Java data
+// structure to prevent GC. In that case, you must call DeleteJavaBitmap() to
+// garbage collect it.
+base::android::ScopedJavaLocalRef<jobject> CreateJavaBitmap(
+ const gfx::Size& size, bool keep);
+void DeleteJavaBitmap(jobject bitmap);
+
+// Paint one java bitmap into another. Scale if needed.
+void PaintJavaBitmapToJavaBitmap(jobject sourceBitmap,
+ const gfx::Rect& sourceRect,
+ jobject destBitmap,
+ const gfx::Rect& destRect);
+
+// Copy the Chromium Skia bitmap into a new Java bitmap. Useful for small UI
+// bitmaps originating from WebKit that we want to manipulate in Java (such as
+// favicons). Due to the extra copy, should be avoided for large or frequently
+// used bitmaps. Returns a local reference to the new bitmap.
+base::android::ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(
+ const SkBitmap* skbitmap);
+
+// Registers our JNI methods.
+bool RegisterJniHelper(JNIEnv* env);
+
+#endif // CONTENT_BROWSER_ANDROID_JNI_HELPER_H_
diff --git a/content/browser/android/library_loader_hooks.cc b/content/browser/android/library_loader_hooks.cc
index 3f2315e..17ebbd4 100644
--- a/content/browser/android/library_loader_hooks.cc
+++ b/content/browser/android/library_loader_hooks.cc
@@ -5,8 +5,10 @@
#include "content/public/browser/android_library_loader_hooks.h"
#include "base/android/base_jni_registrar.h"
+#include "base/android/jni_registrar.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
+#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/file_path.h"
@@ -16,14 +18,21 @@
#include "base/string_util.h"
#include "base/tracked_objects.h"
#include "content/public/common/content_switches.h"
+#include "content/browser/android/command_line.h"
+#include "content/browser/android/content_jni_registrar.h"
#include "media/base/android/media_jni_registrar.h"
#include "net/android/net_jni_registrar.h"
+namespace {
+base::AtExitManager* g_at_exit_manager = NULL;
+}
+
jboolean LibraryLoaderEntryHook(JNIEnv* env, jclass clazz,
jobjectArray init_command_line) {
-
- // TODO(tedchoc): Initialize the native command line from the java array
- // passed in.
+ // We need the Chrome AtExitManager to be created before we do any tracing or
+ // logging.
+ g_at_exit_manager = new base::AtExitManager();
+ InitNativeCommandLineFromJavaArray(env, init_command_line);
CommandLine* command_line = CommandLine::ForCurrentProcess();
@@ -54,12 +63,22 @@ jboolean LibraryLoaderEntryHook(JNIEnv* env, jclass clazz,
if (!net::android::RegisterJni(env))
return JNI_FALSE;
+ if (!content::android::RegisterJni(env))
+ return JNI_FALSE;
+
if (!media::RegisterJni(env))
return JNI_FALSE;
return JNI_TRUE;
}
+void LibraryLoaderExitHook() {
+ if (g_at_exit_manager) {
+ delete g_at_exit_manager;
+ g_at_exit_manager = NULL;
+ }
+}
+
bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
// TODO(bulach): use the jni generator once we move jni_helper methods here.
const JNINativeMethod kMethods[] = {
@@ -67,9 +86,8 @@ bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
reinterpret_cast<void*>(LibraryLoaderEntryHook) },
};
const int kMethodsSize = arraysize(kMethods);
- // TODO(tedchoc): Upstream LibraryLoader.java and replace path to make this
- // work.
- const char kLibraryLoaderPath[] = "";
+ const char kLibraryLoaderPath[] =
+ "org/chromium/content/browser/LibraryLoader";
base::android::ScopedJavaLocalRef<jclass> clazz =
base::android::GetClass(env, kLibraryLoaderPath);
diff --git a/content/browser/android/trace_event_binding.cc b/content/browser/android/trace_event_binding.cc
new file mode 100644
index 0000000..7129946
--- /dev/null
+++ b/content/browser/android/trace_event_binding.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/trace_event_binding.h"
+
+#include <jni.h>
+
+#include <set>
+
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "jni/trace_event_jni.h"
+
+namespace {
+
+const char kJavaCategory[] = "Java";
+
+// Boilerplate for safely converting Java data to TRACE_EVENT data.
+class TraceEventDataConverter {
+ public:
+ TraceEventDataConverter(JNIEnv* env,
+ jstring jname,
+ jstring jarg)
+ : env_(env),
+ jname_(jname),
+ jarg_(jarg),
+ name_(env->GetStringUTFChars(jname, NULL)),
+ arg_(jarg ? env->GetStringUTFChars(jarg, NULL) : NULL) {
+ }
+ ~TraceEventDataConverter() {
+ env_->ReleaseStringUTFChars(jname_, name_);
+ if (jarg_)
+ env_->ReleaseStringUTFChars(jarg_, arg_);
+ }
+
+ // Return saves values to pass to TRACE_EVENT macros.
+ const char* name() { return name_; }
+ const char* arg_name() { return arg_ ? "arg" : NULL; }
+ const char* arg() { return arg_; }
+
+ private:
+ JNIEnv* env_;
+ jstring jname_;
+ jstring jarg_;
+ const char* name_;
+ const char* arg_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceEventDataConverter);
+};
+
+} // namespace
+
+static jboolean TraceEnabled(JNIEnv* env, jclass clazz) {
+ return base::debug::TraceLog::GetInstance()->IsEnabled();
+}
+
+static void Instant(JNIEnv* env, jclass clazz,
+ jstring jname, jstring jarg) {
+ TraceEventDataConverter converter(env, jname, jarg);
+ if (converter.arg()) {
+ TRACE_EVENT_COPY_INSTANT1(kJavaCategory, converter.name(),
+ converter.arg_name(), converter.arg());
+ } else {
+ TRACE_EVENT_COPY_INSTANT0(kJavaCategory, converter.name());
+ }
+}
+
+static void Begin(JNIEnv* env, jclass clazz,
+ jstring jname, jstring jarg) {
+ TraceEventDataConverter converter(env, jname, jarg);
+ if (converter.arg()) {
+ TRACE_EVENT_COPY_BEGIN1(kJavaCategory, converter.name(),
+ converter.arg_name(), converter.arg());
+ } else {
+ TRACE_EVENT_COPY_BEGIN0(kJavaCategory, converter.name());
+ }
+}
+
+static void End(JNIEnv* env, jclass clazz,
+ jstring jname, jstring jarg) {
+ TraceEventDataConverter converter(env, jname, jarg);
+ if (converter.arg()) {
+ TRACE_EVENT_COPY_END1(kJavaCategory, converter.name(),
+ converter.arg_name(), converter.arg());
+ } else {
+ TRACE_EVENT_COPY_END0(kJavaCategory, converter.name());
+ }
+}
+
+bool RegisterTraceEvent(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
diff --git a/content/browser/android/trace_event_binding.h b/content/browser/android/trace_event_binding.h
new file mode 100644
index 0000000..3d54e92
--- /dev/null
+++ b/content/browser/android/trace_event_binding.h
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_TRACE_EVENT_H_
+#define CONTENT_BROWSER_ANDROID_TRACE_EVENT_H_
+#pragma once
+
+#include <jni.h>
+
+extern bool RegisterTraceEvent(JNIEnv* env);
+
+#endif // CONTENT_BROWSER_ANDROID_TRACE_EVENT_H_
diff --git a/content/content.gyp b/content/content.gyp
index b05a6e7..ce006f1 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -200,30 +200,20 @@
['OS == "android"', {
'targets': [
{
- 'target_name': 'content_jni_headers',
- 'type': 'none',
- 'variables': {
- 'java_sources': [
- '../content/public/android/java/org/chromium/content/browser/LocationProvider.java',
- ],
- 'jni_headers': [
- '<(SHARED_INTERMEDIATE_DIR)/content/jni/location_provider_jni.h',
- ],
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
'target_name': 'content_java',
'type': 'none',
+ 'dependencies': ['../base/base.gyp:base_java'],
'variables': {
'package_name': 'content',
'java_in_dir': '../content/public/android/java',
},
- 'dependencies': [
- '../base/base.gyp:base_java',
- ],
'includes': [ '../build/java.gypi' ],
},
+ {
+ 'target_name': 'content_jni_headers',
+ 'type': 'none',
+ 'includes': [ 'content_jni.gypi' ],
+ },
],
}], # OS == "android"
],
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index bc44c69..a6df267 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -182,7 +182,15 @@
'browser/accessibility/browser_accessibility_state_impl.h',
'browser/accessibility/browser_accessibility_win.cc',
'browser/accessibility/browser_accessibility_win.h',
+ 'browser/android/command_line.cc',
+ 'browser/android/command_line.h',
+ 'browser/android/content_jni_registrar.cc',
+ 'browser/android/content_jni_registrar.h',
+ 'browser/android/jni_helper.cc',
+ 'browser/android/jni_helper.h',
'browser/android/library_loader_hooks.cc',
+ 'browser/android/trace_event_binding.cc',
+ 'browser/android/trace_event_binding.h',
'browser/appcache/appcache_dispatcher_host.cc',
'browser/appcache/appcache_dispatcher_host.h',
'browser/appcache/appcache_frontend_proxy.cc',
@@ -821,15 +829,15 @@
'content.gyp:content_jni_headers',
'content.gyp:content_java',
],
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)/content',
+ ],
'sources!': [
'browser/geolocation/network_location_provider.cc',
'browser/geolocation/network_location_provider.h',
'browser/geolocation/network_location_request.cc',
'browser/geolocation/network_location_request.h',
],
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/content',
- ],
}],
['OS=="mac"', {
'sources': [
diff --git a/content/content_jni.gypi b/content/content_jni.gypi
new file mode 100644
index 0000000..dc6849b
--- /dev/null
+++ b/content/content_jni.gypi
@@ -0,0 +1,27 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ # TODO(jrg): Update this action and other jni generators to only
+ # require specifying the java directory and generate the rest.
+ # TODO(jrg): when doing the above, make sure we support multiple
+ # output directories (e.g. browser/jni and common/jni if needed).
+ 'variables': {
+ 'java_sources': [
+ 'public/android/java/org/chromium/content/browser/CommandLine.java',
+ 'public/android/java/org/chromium/content/browser/JNIHelper.java',
+ 'public/android/java/org/chromium/content/browser/LibraryLoader.java',
+ 'public/android/java/org/chromium/content/browser/LocationProvider.java',
+ 'public/android/java/org/chromium/content/browser/TraceEvent.java',
+ ],
+ 'jni_headers': [
+ '<(SHARED_INTERMEDIATE_DIR)/content/jni/command_line_jni.h',
+ '<(SHARED_INTERMEDIATE_DIR)/content/jni/jni_helper_jni.h',
+ '<(SHARED_INTERMEDIATE_DIR)/content/jni/library_loader_jni.h',
+ '<(SHARED_INTERMEDIATE_DIR)/content/jni/location_provider_jni.h',
+ '<(SHARED_INTERMEDIATE_DIR)/content/jni/trace_event_jni.h',
+ ],
+ },
+ 'includes': [ '../build/jni_generator.gypi' ],
+}
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index a33508b..4a67c23 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -523,13 +523,25 @@
'actions': [
{
'action_name': 'copy_base_jar',
- 'inputs': ['<(PRODUCT_DIR)/chromium_base.jar'],
+ 'inputs': ['<(PRODUCT_DIR)/lib.java/chromium_base.jar'],
'outputs': ['<(PRODUCT_DIR)/content_shell/java/libs/chromium_base.jar'],
'action': ['cp', '<@(_inputs)', '<@(_outputs)'],
},
{
+ 'action_name': 'copy_net_jar',
+ 'inputs': ['<(PRODUCT_DIR)/lib.java/chromium_net.jar'],
+ 'outputs': ['<(PRODUCT_DIR)/content_shell/java/libs/chromium_net.jar'],
+ 'action': ['cp', '<@(_inputs)', '<@(_outputs)'],
+ },
+ {
+ 'action_name': 'copy_media_jar',
+ 'inputs': ['<(PRODUCT_DIR)/lib.java/chromium_media.jar'],
+ 'outputs': ['<(PRODUCT_DIR)/content_shell/java/libs/chromium_media.jar'],
+ 'action': ['cp', '<@(_inputs)', '<@(_outputs)'],
+ },
+ {
'action_name': 'copy_content_jar',
- 'inputs': ['<(PRODUCT_DIR)/chromium_content.jar'],
+ 'inputs': ['<(PRODUCT_DIR)/lib.java/chromium_content.jar'],
'outputs': ['<(PRODUCT_DIR)/content_shell/java/libs/chromium_content.jar'],
'action': ['cp', '<@(_inputs)', '<@(_outputs)'],
},
@@ -553,6 +565,8 @@
'<!@(find shell/android/java -name "*.java")',
'<!@(find shell/android/res -name "*")',
'<(PRODUCT_DIR)/content_shell/java/libs/chromium_base.jar',
+ '<(PRODUCT_DIR)/content_shell/java/libs/chromium_net.jar',
+ '<(PRODUCT_DIR)/content_shell/java/libs/chromium_media.jar',
'<(PRODUCT_DIR)/content_shell/java/libs/chromium_content.jar',
'<(PRODUCT_DIR)/content_shell/libs/armeabi/libcontent_shell_content_view.so',
],
diff --git a/content/plugin/webplugin_proxy.cc b/content/plugin/webplugin_proxy.cc
index ee1c721..5a60afc9 100644
--- a/content/plugin/webplugin_proxy.cc
+++ b/content/plugin/webplugin_proxy.cc
@@ -636,6 +636,16 @@ void WebPluginProxy::SetWindowlessBuffers(
}
}
+#elif defined(OS_ANDROID)
+
+void WebPluginProxy::SetWindowlessBuffers(
+ const TransportDIB::Handle& windowless_buffer0,
+ const TransportDIB::Handle& windowless_buffer1,
+ const TransportDIB::Handle& background_buffer,
+ const gfx::Rect& window_rect) {
+ NOTIMPLEMENTED();
+}
+
#endif
void WebPluginProxy::CancelDocumentLoad() {
diff --git a/content/ppapi_plugin/ppapi_webkitplatformsupport_impl.cc b/content/ppapi_plugin/ppapi_webkitplatformsupport_impl.cc
index 56ee6a5..2f526fd 100644
--- a/content/ppapi_plugin/ppapi_webkitplatformsupport_impl.cc
+++ b/content/ppapi_plugin/ppapi_webkitplatformsupport_impl.cc
@@ -20,9 +20,12 @@
#elif defined(OS_MACOSX)
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/mac/WebSandboxSupport.h"
#elif defined(OS_POSIX)
+#if !defined(OS_ANDROID)
#include "content/common/child_process_sandbox_support_impl_linux.h"
+#endif
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/linux/WebFontFamily.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/linux/WebSandboxSupport.h"
+
#endif
using WebKit::WebSandboxSupport;
@@ -82,6 +85,24 @@ bool PpapiWebKitPlatformSupportImpl::SandboxSupport::loadFont(
return false;
}
+#elif defined(OS_ANDROID)
+
+// TODO(jrg): resolve (and implement?) PPAPI SandboxSupport for Android.
+
+void
+PpapiWebKitPlatformSupportImpl::SandboxSupport::getFontFamilyForCharacters(
+ const WebUChar* characters,
+ size_t num_characters,
+ const char* preferred_locale,
+ WebKit::WebFontFamily* family) {
+ NOTIMPLEMENTED();
+}
+
+void PpapiWebKitPlatformSupportImpl::SandboxSupport::getRenderStyleForStrike(
+ const char* family, int sizeAndStyle, WebKit::WebFontRenderStyle* out) {
+ NOTIMPLEMENTED();
+}
+
#elif defined(OS_POSIX)
void
diff --git a/content/public/android/java/content.xml b/content/public/android/java/content.xml
index 435cbab..533accd 100644
--- a/content/public/android/java/content.xml
+++ b/content/public/android/java/content.xml
@@ -12,10 +12,8 @@
<property name="sdk.dir" location="${env.ANDROID_SDK_ROOT}"/>
<property name="sdk.version" value="${env.ANDROID_SDK_VERSION}"/>
<property name="src" location="."/>
- <property name="out.dir" location="${PRODUCT_DIR}"/>
+ <property name="out.dir" location="${PRODUCT_DIR}/lib.java"/>
<property name="classes.dir" location="${out.dir}/java/${PACKAGE_NAME}"/>
- <!-- TODO(tedchoc): Move out of the main out/ dir ... needs to sync with
- java.gypi output -->
<property name="jar.dir" location="${out.dir}"/>
<condition property="location.base"
@@ -39,8 +37,8 @@
<!-- Compile the java code from ${src} into ${classes.dir} -->
<javac srcdir="${src}" destdir="${classes.dir}">
<classpath>
- <path location="${location.base}/android.jar"/>
- <path location="${PRODUCT_DIR}/chromium_base.jar"/>
+ <pathelement path="${location.base}/android.jar" />
+ <pathelement path="${jar.dir}/chromium_base.jar" />
</classpath>
</javac>
</target>
diff --git a/content/public/android/java/org/chromium/content/browser/CommandLine.java b/content/public/android/java/org/chromium/content/browser/CommandLine.java
new file mode 100644
index 0000000..932fd25
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/browser/CommandLine.java
@@ -0,0 +1,467 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+// Java mirror of Chrome command-line utilities (e.g. class CommandLine from base/command_line.h).
+// Command line program adb_command_line can be used to set the Chrome command line:
+// adb shell "echo chrome --my-param > /data/local/chrome-command-line"
+
+// TODO(jrg), TODO(tedchoc): some of these command line options are
+// specific to chrome, not content. transition them to a different
+// location.
+
+public abstract class CommandLine {
+ // Switches used from Java. Please continue switch style used Chrome where options-have-hypens
+ // and are_not_split_with_underscores.
+
+ // Block onCreate() of Chrome until a Java debugger is attached.
+ public static final String WAIT_FOR_JAVA_DEBUGGER = "wait-for-java-debugger";
+
+ // Disable instant?
+ public static final String DISABLE_INSTANT = "disable-instant";
+
+ // Should we force-enable the "hardware acceleration" preference?
+ public static final String HARDWARE_ACCELERATION = "hardware-acceleration";
+
+ // Give an extra account name for the x-auto-login spinner, for testing.
+ public static final String AUTO_LOGIN_EXTRA_ACCOUNT = "auto-login-extra-account";
+
+ // Enable exact match x-auto-login? Disabled for now (see
+ // AccountManagerContainer.java).
+ public static final String EXACT_MATCH_AUTO_LOGIN = "exact-match-auto-login";
+
+ // Should we show the NTP cache menu items?
+ public static final String CACHED_NTP_MENU = "cached-ntp-menu";
+
+ // Should we use a preload web view container for the ntp?
+ public static final String PRELOAD_WEBVIEW_CONTAINER = "preload-webview-container";
+
+ // Should thumbnail bitmaps for the thumbnail cache be full size?
+ public static final String FULL_SIZE_THUMBNAILS = "full-size-thumbnails";
+
+ // Should thumbnail bitmaps for the thumbnail cache be a compromise size?
+ public static final String COMPROMISE_SIZE_THUMBNAILS = "compromise-size-thumbnails";
+
+ // Should thumbnail bitmaps for the thumbnail cache be small (1/4 size)?
+ // Uses less memory and is faster but has a significant quality reduction.
+ public static final String SMALL_SIZE_THUMBNAILS = "small-size-thumbnails";
+
+ // Should thumbnail bitmaps be generated at 16-bit? 32-bit?
+ public static final String SIXTEEN_BIT_THUMBNAILS = "sixteen-bit-thumbnails";
+ public static final String THIRTYTWO_BIT_THUMBNAILS = "thirtytwo-bit-thumbnails";
+
+ // How many thumbnails should we allow in the cache (per tab stack)?
+ public static final String THUMBNAILS = "thumbnails";
+
+ // How many "approximated" thumbnails should we allow in the cache
+ // (per tab stack)? These take very low memory but have poor quality.
+ public static final String APPROXIMATION_THUMBNAILS = "approximation-thumbnails";
+
+ // What scaling to use for the approximation? Integer.
+ public static final String APPROXIMATION_SCALE = "approximation-scale";
+
+ // Tell Java to use the official command line, loaded from the
+ // official-command-line.xml files. WARNING this is not done
+ // immediately on startup, so early running Java code will not see
+ // these flags.
+ public static final String ADD_OFFICIAL_COMMAND_LINE = "add-official-command-line";
+
+ // If specified, enables notification center verbose logging.
+ public static final String NOTIFICATION_CENTER_LOGGING = "notification-center-logging";
+
+ // Enables test intent handling.
+ public static final String ENABLE_TEST_INTENTS = "enable-test-intents";
+
+ // Override the system fling friction (0.015f). This can make it easier to see scrolling bugs.
+ public static final String FLING_FRICTION = "fling-friction";
+
+ // Enables StrictMode violation detection. By default this logs violations to logcat.
+ public static final String STRICT_MODE = "strict-mode";
+
+ // Enable the First Run Experience
+ // TODO(dtrainor): This should be removed eventually, as it is only used for development and
+ // debugging.
+ public static final String ENABLE_FIRST_RUN_EXPERIENCE = "enable-fre";
+
+ // Disable the First Run Experience
+ // TODO(dtrainor): This should be removed eventually, as it is only used for development and
+ // debugging.
+ public static final String DISABLE_FIRST_RUN_EXPERIENCE = "disable-fre";
+
+ // Force the First Run Experience to show.
+ public static final String FORCE_FIRST_RUN_EXPERIENCE = "force-fre";
+
+ // Default country code to be used for search engine localization.
+ public static final String DEFAULT_COUNTRY_CODE_AT_INSTALL = "default-country-code";
+
+ // Sets the max number of sandboxed service processes to use.
+ // Unlike renderer-process-limit, this is a hard limit on the number of
+ // concurrent sandboxed processes.
+ public static final String SANDBOXED_SERVICE_LIMIT = "sandboxed-service-limit";
+
+ // Mirrors of switches defined in native code. It is up to you,
+ // the developer, to keep these strings in sync with
+ // base/base_switches.h, or content/public/common/content_switches.h, or
+ // wherever.
+
+ // Don't restore persistent state from saved files on startup.
+ public static final String NO_RESTORE_STATE = "no-restore-state";
+
+ // Specifies which page will be displayed on startup.
+ public static final String HOME_PAGE = "homepage";
+
+ // Dump frames-per-second to the log
+ public static final String LOG_FPS = "log-fps";
+
+ // Override the default server used for profile sync.
+ public static final String SYNC_URL = "sync-url";
+
+ // Sets the max number of render processes to use.
+ public static final String RENDER_PROCESS_LIMIT = "renderer-process-limit";
+
+ // Enable to swap the overview mode between different implementation.
+ // TODO(jscholler): This should be removed eventually, as it is only used for development and
+ // debugging.
+ public static final String ENABLE_OVERVIEW_SWAP = "enable-overview-swap";
+
+ // DO NOT ADD YOUR NEW SWITCH HERE unless it is a mirror of a native switch. Otherwise, see
+ // the "Switches used from Java" section above.
+
+ // Public abstract interface, implemented in derived classes.
+ // All these methods reflect their native-side counterparts.
+ /**
+ * Returns true if this command line contains the given switch.
+ * (Switch names ARE case-sensitive).
+ */
+ public abstract boolean hasSwitch(String switchString);
+
+ /**
+ * Return the value associated with the given switch, or null.
+ * @param switchString The switch key to lookup. It should NOT start with '--' !
+ * @return switch value, or null if the switch is not set or set to empty.
+ */
+ public abstract String getSwitchValue(String switchString);
+
+ /**
+ * Append a switch to the command line. There is no guarantee
+ * this action happens before the switch is needed.
+ * @param switchString the switch to add. It should NOT start with '--' !
+ */
+ public abstract void appendSwitch(String switchString);
+
+ /**
+ * Append a switch and value to the command line. There is no
+ * guarantee this action happens before the switch is needed.
+ * @param switchString the switch to add. It should NOT start with '--' !
+ * @param value the value for this switch.
+ * For example, --foo=bar becomes 'foo', 'bar'.
+ */
+ public abstract void appendSwitchWithValue(String switchString, String value);
+
+ /**
+ * Append switch/value items in "command line" format (excluding argv[0] program name).
+ * E.g. { '--gofast', '--username=fred' }
+ * @param array an array of switch or switch/value items in command line format.
+ * Unlike the other append routines, these switches SHOULD start with '--' .
+ * Unlike init(), this does not include the program name in array[0].
+ */
+ public abstract void appendSwitchesAndArguments(String[] array);
+
+ /**
+ * Determine if the command line is bound to the native (JNI) implementation.
+ * @return true if the underlying implementation is delegating to the native command line.
+ */
+ public boolean isNativeImplementation() {
+ return false;
+ }
+
+ private static final AtomicReference<CommandLine> sCommandLine =
+ new AtomicReference<CommandLine>();
+
+ /**
+ * @returns true if the command line has already been initialized.
+ */
+ public static boolean isInitialized() {
+ return sCommandLine.get() != null;
+ }
+
+ // Equivalent to CommandLine::ForCurrentProcess in C++.
+ public static CommandLine getInstance() {
+ assert sCommandLine.get() != null;
+ return sCommandLine.get();
+ }
+
+ /**
+ * Initialize the singleton instance, must be called exactly once (either directly or
+ * via one of the convenience wrappers below) before using the static singleton instance.
+ * @param args command line flags in 'argv' format: args[0] is the program name.
+ */
+ public static void init(String[] args) {
+ assert sCommandLine.get() == null;
+ sCommandLine.compareAndSet(null, new JavaCommandLine(args));
+ }
+
+ /**
+ * Initialize the command line from the command-line file.
+ *
+ * @param file The fully qualified command line file.
+ */
+ public static void initFromFile(String file) {
+ char[] buffer = new char[0];
+ try {
+ // Arbitrary clamp of 8k on the amount of file we read in.
+ buffer = readUtf8FileFully(file, 8 * 1024);
+ } catch (FileNotFoundException e) {
+ // Ignore: having a command line file is optional.
+ } catch (IOException e) {
+ Log.w(TAG, "error reading command line file " + file + e);
+ }
+ init(tokenizeQuotedAruments(buffer));
+ }
+
+ /**
+ * Resets both the java proxy and the native command lines. This allows the entire
+ * command line initialization to be re-run including the call to onJniLoaded.
+ */
+ public static void reset() {
+ if (sCommandLine.get() != null && sCommandLine.get().isNativeImplementation()) {
+ nativeReset();
+ }
+ sCommandLine.set(null);
+ }
+
+ /**
+ * Public for testing (TODO: why are the tests in a different package?)
+ * Parse command line flags from a flat buffer, supporting double-quote enclosed strings
+ * containing whitespace. argv elements are derived by splitting the buffer on whitepace;
+ * double quote characters may enclose tokens containing whitespace; a double-quote literal
+ * may be escaped with back-slash. (Otherwise backslash is taken as a literal).
+ * @param buffer A command line in command line file format as described above.
+ * @return the tokenized arguments, suitable for passing to init().
+ */
+ public static String[] tokenizeQuotedAruments(char[] buffer) {
+ boolean inQuotes = false;
+ ArrayList<String> args = new ArrayList<String>();
+ StringBuilder arg = null;
+ for (char c : buffer) {
+ if (c == '\"') {
+ if (arg != null && arg.length() > 0 && arg.charAt(arg.length() - 1) == '\\') {
+ // Last char was a backslash; pop it, and treat this " as a literal.
+ arg.setCharAt(arg.length() - 1, c);
+ } else {
+ inQuotes = !inQuotes;
+ }
+ } else if (!inQuotes && Character.isWhitespace(c)) {
+ if (arg != null) {
+ args.add(arg.toString());
+ arg = null;
+ }
+ } else {
+ if (arg == null) arg = new StringBuilder();
+ arg.append(c);
+ }
+ }
+ if (arg != null) {
+ if (inQuotes) {
+ Log.w(TAG, "Unterminated quoted string: " + arg);
+ }
+ args.add(arg.toString());
+ }
+ return args.toArray(new String[args.size()]);
+ }
+
+ private static final String TAG = "CommandLine";
+ private static final String SWITCH_PREFIX = "--";
+ private static final String SWITCH_TERMINATOR = SWITCH_PREFIX;
+ private static final String SWITCH_VALUE_SEPARATOR = "=";
+
+ static void enableNativeProxy() {
+ // Make a best-effort to ensure we make a clean (atomic) switch over from the old to
+ // the new command line implementation. If another thread is modifying the command line
+ // when this happens, all bets are off. (As per the native CommandLine).
+ sCommandLine.set(new NativeCommandLine());
+ }
+
+ static String[] getJavaSwitchesOrNull() {
+ CommandLine commandLine = sCommandLine.get();
+ if (commandLine != null) {
+ assert !commandLine.isNativeImplementation();
+ return ((JavaCommandLine) commandLine).getCommandLineArguments();
+ }
+ return null;
+ }
+
+ /**
+ * @param fileName the file to read in.
+ * @param sizeLimit cap on the file size: will throw an exception if exceeded
+ * @return Array of chars read from the file
+ * @throws FileNotFoundException file does not exceed
+ * @throws IOException error encountered accessing the file
+ */
+ private static char[] readUtf8FileFully(String fileName, int sizeLimit) throws
+ FileNotFoundException, IOException {
+ Reader reader = null;
+ try {
+ File f = new File(fileName);
+ if (f.length() > sizeLimit) {
+ throw new IOException("File " + fileName + " length " + f.length() +
+ " exceeds limit " + sizeLimit);
+ }
+ char[] buffer = new char[(int) f.length()];
+ reader = new InputStreamReader(new FileInputStream(f), "UTF-8");
+ int charsRead = reader.read(buffer);
+ // Debug check that we've exhausted the input stream (will fail e.g. if the
+ // file grew after we inspected its length).
+ assert !reader.ready();
+ return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, charsRead) : buffer;
+ } finally {
+ if (reader != null) reader.close();
+ }
+ }
+
+ private CommandLine() {}
+
+ private static class JavaCommandLine extends CommandLine {
+ private HashMap<String, String> mSwitches = new HashMap<String, String>();
+ private ArrayList<String> mArgs = new ArrayList<String>();
+
+ // The arguments begin at index 1, since index 0 contains the executable name.
+ private int mArgsBegin = 1;
+
+ JavaCommandLine(String[] args) {
+ if (args == null || args.length == 0 || args[0] == null) {
+ mArgs.add("");
+ } else {
+ mArgs.add(args[0]);
+ appendSwitchesInternal(args, 1);
+ }
+ // Invariant: we always have the argv[0] program name element.
+ assert mArgs.size() > 0;
+ }
+
+ /**
+ * Returns the switches and arguments passed into the program, with switches and their
+ * values coming before all of the arguments.
+ */
+ private String[] getCommandLineArguments() {
+ return mArgs.toArray(new String[mArgs.size()]);
+ }
+
+ @Override
+ public boolean hasSwitch(String switchString) {
+ return mSwitches.containsKey(switchString);
+ }
+
+ @Override
+ public String getSwitchValue(String switchString) {
+ // This is slightly round about, but needed for consistency with the NativeCommandLine
+ // version which does not distinguish empty values from key not present.
+ String value = mSwitches.get(switchString);
+ return value == null || value.isEmpty() ? null : value;
+ }
+
+ @Override
+ public void appendSwitch(String switchString) {
+ appendSwitchWithValue(switchString, null);
+ }
+
+ /**
+ * Appends a switch to the current list.
+ * @param switchString the switch to add. It should NOT start with '--' !
+ * @param value the value for this switch.
+ */
+ @Override
+ public void appendSwitchWithValue(String switchString, String value) {
+ mSwitches.put(switchString, value == null ? "" : value);
+
+ // Append the switch and update the switches/arguments divider mArgsBegin.
+ String combinedSwitchString = SWITCH_PREFIX + switchString;
+ if (value != null && !value.isEmpty())
+ combinedSwitchString += SWITCH_VALUE_SEPARATOR + value;
+
+ mArgs.add(mArgsBegin++, combinedSwitchString);
+ }
+
+ @Override
+ public void appendSwitchesAndArguments(String[] array) {
+ appendSwitchesInternal(array, 0);
+ }
+
+ // Add the specified arguments, but skipping the first |skipCount| elements.
+ private void appendSwitchesInternal(String[] array, int skipCount) {
+ boolean parseSwitches = true;
+ for (String arg : array) {
+ if (skipCount > 0) {
+ --skipCount;
+ continue;
+ }
+
+ if (arg.equals(SWITCH_TERMINATOR)) {
+ parseSwitches = false;
+ }
+
+ if (parseSwitches && arg.startsWith(SWITCH_PREFIX)) {
+ String[] parts = arg.split(SWITCH_VALUE_SEPARATOR, 2);
+ String value = parts.length > 1 ? parts[1] : null;
+ appendSwitchWithValue(parts[0].substring(SWITCH_PREFIX.length()), value);
+ } else {
+ mArgs.add(arg);
+ }
+ }
+ }
+ }
+
+ private static class NativeCommandLine extends CommandLine {
+ @Override
+ public boolean hasSwitch(String switchString) {
+ return nativeHasSwitch(switchString);
+ }
+
+ @Override
+ public String getSwitchValue(String switchString) {
+ return nativeGetSwitchValue(switchString);
+ }
+
+ @Override
+ public void appendSwitch(String switchString) {
+ nativeAppendSwitch(switchString);
+ }
+
+ @Override
+ public void appendSwitchWithValue(String switchString, String value) {
+ nativeAppendSwitchWithValue(switchString, value);
+ }
+
+ @Override
+ public void appendSwitchesAndArguments(String[] array) {
+ nativeAppendSwitchesAndArguments(array);
+ }
+
+ @Override
+ public boolean isNativeImplementation() {
+ return true;
+ }
+ }
+
+ private static native void nativeReset();
+ private static native boolean nativeHasSwitch(String switchString);
+ private static native String nativeGetSwitchValue(String switchString);
+ private static native void nativeAppendSwitch(String switchString);
+ private static native void nativeAppendSwitchWithValue(String switchString, String value);
+ private static native void nativeAppendSwitchesAndArguments(String[] array);
+};
diff --git a/content/public/android/java/org/chromium/content/browser/JNIHelper.java b/content/public/android/java/org/chromium/content/browser/JNIHelper.java
new file mode 100644
index 0000000..e1d3673
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/browser/JNIHelper.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Bitmap;
+import android.graphics.RectF;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.chromium.base.CalledByNative;
+
+class JNIHelper {
+ // Holder for content backing store bitmaps of all ChromeViews. Note that
+ // when in software mode, this will be one of the main consumers of RAM in
+ // the Java code. This data structure exists solely to prevent garbage
+ // collection and expose the allocations to the DDMS tool. The backing
+ // stores are actually used in C++ with weak global references.
+ private static final Set<Bitmap> mBitmapHolder = new HashSet<Bitmap>();
+
+ @CalledByNative
+ private static Bitmap createJavaBitmap(int w, int h, boolean keep) {
+ Bitmap newBitmap =
+ Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+
+ if (keep) {
+ mBitmapHolder.add(newBitmap);
+ }
+
+ return newBitmap;
+ }
+
+ @CalledByNative
+ private static void deleteJavaBitmap(Bitmap b) {
+ mBitmapHolder.remove(b);
+ b.recycle();
+ }
+
+ // Statics used transiently in paintJavaBitmapToJavaBitmap, but retained to reduce
+ // heap churn on each call to that method.
+ static private Rect sSourceRect;
+ static private RectF sDestRect;
+ static private Canvas sCanvas;
+ static private Bitmap sNullBitmap;
+ static private Paint sPaint;
+
+ @CalledByNative
+ public static void paintJavaBitmapToJavaBitmap(
+ Bitmap sourceBitmap,
+ int sourceX, int sourceY, int sourceBottom, int sourceRight,
+ Bitmap destBitmap,
+ float destX, float destY, float destBottom, float destRight) {
+ if (sCanvas == null) {
+ sSourceRect = new Rect();
+ sDestRect = new RectF();
+ sCanvas = new Canvas();
+ sNullBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+ sPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+ }
+ sSourceRect.set(sourceX, sourceY, sourceRight, sourceBottom);
+ sDestRect.set(destX, destY, destRight, destBottom);
+ sCanvas.setBitmap(destBitmap);
+ sCanvas.drawBitmap(sourceBitmap, sSourceRect, sDestRect, sPaint);
+ sCanvas.setBitmap(sNullBitmap); // To release |destBitmap| reference.
+ }
+}
diff --git a/content/public/android/java/org/chromium/content/browser/LibraryLoader.java b/content/public/android/java/org/chromium/content/browser/LibraryLoader.java
new file mode 100644
index 0000000..ee9b358
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/browser/LibraryLoader.java
@@ -0,0 +1,239 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.Log;
+
+// This class provides functionality to:
+// - synchronously load and register the native library. This is used by callers
+// that can't do anything useful without the native side.
+// - asynchronously load and register the native library. This is used by callers
+// that can do more work in the java-side, and let a separate thread do all the
+// file IO and library loading.
+public class LibraryLoader {
+ private static final String TAG = "LibraryLoader";
+
+ /* TODO(jrg): resolve up and downstream discrepancy; there is no
+ * upstream libchromeview.so */
+ private static String sLibrary = "chromeview";
+
+ private static boolean sLoaded = false;
+
+ private static boolean sInitialized = false;
+
+ private static AsyncTask<Void, Void, Boolean> sAsyncLoader;
+
+ /**
+ * Callback for handling loading of the native library.
+ *
+ * <p> The callback methods will always be triggered on the UI thread.
+ */
+ public static interface Callback {
+ /**
+ * Called when loading the native library is successful.
+ */
+ void onSuccess();
+
+ /**
+ * Called when loading the native library fails.
+ */
+ void onFailure();
+ }
+
+ /**
+ * Sets the library name that is to be loaded. This must be called prior to the library being
+ * loaded the first time.
+ *
+ * @param library The name of the library to be loaded (without the lib prefix).
+ */
+ public static void setLibraryToLoad(String library) {
+ if (TextUtils.equals(sLibrary, library)) return;
+
+ assert !sLoaded : "Setting the library must happen before load is called.";
+ sLibrary = library;
+ }
+
+ /**
+ * This method blocks until the library is fully loaded and initialized;
+ * must be called on the thread that the native will call its "main" thread.
+ */
+ public static void loadAndInitSync() {
+ checkThreadUsage();
+ if (sInitialized) {
+ // Already initialized, nothing to do.
+ return;
+ }
+ if (sAsyncLoader != null) {
+ // Async initialization in progress, wait.
+ waitForAsyncInitialized();
+ return;
+ }
+ loadNow();
+ initializeOnMainThread();
+ }
+
+ /**
+ * Block until the library is fully initialized.
+ * Must be called on the thread that the native will call its "main" thread.
+ */
+ private static void waitForAsyncInitialized() {
+ checkThreadUsage();
+ if (sInitialized) {
+ // Already initialized.
+ return;
+ }
+ synchronized(LibraryLoader.class) {
+ try {
+ while (!sLoaded) {
+ LibraryLoader.class.wait();
+ }
+ // If the UI thread blocked waiting for the task it will already
+ // have handled the library load completion, so don't duplicate that work here.
+ } catch (InterruptedException e) {
+ }
+ }
+ initializeOnMainThread();
+ }
+
+ /**
+ * Kicks off an asynchronous library load, and will asynchronously initialize the
+ * library when that completes.
+ * Must be called on the thread that the native will call its "main" thread.
+ */
+ public static void loadAndInitAsync(final Callback onLoadedListener) {
+ checkThreadUsage();
+ if (sInitialized) {
+ // Already initialized, post our Runnable if needed.
+ if (onLoadedListener != null) {
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ onLoadedListener.onSuccess();
+ }
+ });
+ }
+ return;
+ }
+ sAsyncLoader = new AsyncTask<Void, Void, Boolean>() {
+ @Override
+ public Boolean doInBackground(Void... voids) {
+ // We're loading the .so in a background thread. Potentially, this
+ // can break native code that relies on static initializers using
+ // thread local storage, as the library would normally load in the
+ // main thread. If do we hit such cases we should remove those static
+ // initializers, as we chrome has banned them.
+ // (Worst case, we can go back to just warming up the file in the system
+ // cache here and do the actual loading in onPostExecute().)
+ return loadNow();
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (result) {
+ initializeOnMainThread();
+ if (onLoadedListener != null) onLoadedListener.onSuccess();
+ } else {
+ if (onLoadedListener != null) onLoadedListener.onFailure();
+ }
+
+ }
+ };
+ sAsyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ /**
+ * @throws UnsatisfiedLinkError if the library is not yet initialized.
+ */
+ public static void checkIsReady() {
+ if (!sInitialized) {
+ throw new UnsatisfiedLinkError(sLibrary + " is not initialized");
+ }
+ }
+
+ /**
+ * Loads the library and blocks until the load completes. The caller is responsible
+ * for subsequently calling initialize().
+ * May be called on any thread, but should only be called once. Note the thread
+ * this is called on will be the thread that runs the native code's static initializers.
+ * See the comment in doInBackground() for more considerations on this.
+ *
+ * @return Whether the native library was successfully loaded.
+ */
+ static boolean loadNow() {
+ assert !sInitialized;
+ try {
+ Log.i(TAG, "loading: " + sLibrary);
+ System.loadLibrary(sLibrary);
+ Log.i(TAG, "loaded: " + sLibrary);
+ synchronized(LibraryLoader.class) {
+ sLoaded = true;
+ LibraryLoader.class.notifyAll();
+ }
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "error loading: " + sLibrary, e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * initializes the library here and now: must be called on the thread that the
+ * native will call its "main" thread. The library must have previously been
+ * loaded with loadNow.
+ * @param initCommandLine The command line arguments that native command line will
+ * be initialized with.
+ */
+ static void initializeOnMainThread(String[] initCommandLine) {
+ checkThreadUsage();
+ if (sInitialized) {
+ return;
+ }
+ if (!nativeLibraryLoadedOnMainThread(initCommandLine)) {
+ Log.e(TAG, "error calling nativeLibraryLoadedOnMainThread");
+ throw new UnsatisfiedLinkError();
+ }
+ // From this point on, native code is ready to use and checkIsReady()
+ // shouldn't complain from now on (and in fact, it's used by the
+ // following calls).
+ sInitialized = true;
+ CommandLine.enableNativeProxy();
+ TraceEvent.setEnabledToMatchNative();
+ }
+
+ static private void initializeOnMainThread() {
+ checkThreadUsage();
+ if (!sInitialized) {
+ initializeOnMainThread(CommandLine.getJavaSwitchesOrNull());
+ }
+ }
+
+ private LibraryLoader() {
+ }
+
+ // The public API of this class is meant to be used from a single
+ // thread. Internally, we may bounce to a separate thread to actually
+ // load the library.
+ private static Thread sMyThread;
+ private static void checkThreadUsage() {
+ Thread currentThread = java.lang.Thread.currentThread();
+ if (sMyThread == null) {
+ sMyThread = currentThread;
+ } else {
+ if (sMyThread != currentThread) {
+ Log.e(TAG, "Threading violation detected. My thread=" + sMyThread +
+ " but I'm being accessed from thread=" + currentThread);
+ assert false;
+ }
+ }
+ }
+
+ // This is the only method that is registered during System.loadLibrary, as it
+ // happens on a different thread. We then call it on the main thread to register
+ // everything else.
+ private static native boolean nativeLibraryLoadedOnMainThread(String[] initCommandLine);
+}
diff --git a/content/public/android/java/org/chromium/content/browser/TraceEvent.java b/content/public/android/java/org/chromium/content/browser/TraceEvent.java
new file mode 100644
index 0000000..b1ad95f
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/browser/TraceEvent.java
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import android.os.Looper;
+import android.util.Printer;
+
+// Java mirror of Chrome trace event API. See
+// base/debug/trace_event.h. Unlike the native version, Java does not
+// have stack objects, so a TRACE_EVENT() which does both
+// TRACE_EVENT_BEGIN() and TRACE_EVENT_END() in ctor/dtor is not
+// possible.
+// It is OK to use tracing before the native library has loaded, but such traces will
+// be ignored. (Perhaps we could devise to buffer them up in future?).
+public class TraceEvent {
+
+ private static boolean sEnabled = false;
+
+ private static class LooperTracePrinter implements Printer {
+ private static final String NAME = "Looper.dispatchMessage";
+ @Override
+ public void println(String line) {
+ if (line.startsWith(">>>>>")) {
+ TraceEvent.begin(NAME, line);
+ } else {
+ assert line.startsWith("<<<<<");
+ TraceEvent.end(NAME);
+ }
+ }
+ }
+
+ /**
+ * Calling this will cause enabled() to be updated to match that set on the native side.
+ * The native library must be loaded before calling this method.
+ */
+ public static void setEnabledToMatchNative() {
+ setEnabled(nativeTraceEnabled());
+ }
+
+ /**
+ * Enables or disables tracing.
+ * The native library must be loaded before the first call with enabled == true.
+ */
+ public static synchronized void setEnabled(boolean enabled) {
+ if (enabled) {
+ LibraryLoader.checkIsReady();
+ }
+ if (sEnabled == enabled) {
+ return;
+ }
+ sEnabled = enabled;
+ Looper.getMainLooper().setMessageLogging(enabled ? new LooperTracePrinter() : null);
+ }
+
+ /**
+ * @return True if tracing is enabled, false otherwise.
+ * It is safe to call trace methods without checking if TraceEvent
+ * is enabled.
+ */
+ public static boolean enabled() {
+ return sEnabled;
+ }
+
+ public static void instant(String name) {
+ if (sEnabled) {
+ nativeInstant(name, null);
+ }
+ }
+
+ public static void instant(String name, String arg) {
+ if (sEnabled) {
+ nativeInstant(name, arg);
+ }
+ }
+
+ /**
+ * Convenience wrapper around the versions of begin() that take string parameters.
+ * The name of the event will be derived from the class and function name that call this.
+ * IMPORTANT: if using this version, ensure end() (no parameters) is always called from the
+ * same calling context.
+ */
+ public static void begin() {
+ if (sEnabled) {
+ nativeBegin(getCallerName(), null);
+ }
+ }
+
+ public static void begin(String name) {
+ if (sEnabled) {
+ nativeBegin(name, null);
+ }
+ }
+
+ public static void begin(String name, String arg) {
+ if (sEnabled) {
+ nativeBegin(name, arg);
+ }
+ }
+
+ /**
+ * Convenience wrapper around the versions of end() that take string parameters. See begin()
+ * for more information.
+ */
+ public static void end() {
+ if (sEnabled) {
+ nativeEnd(getCallerName(), null);
+ }
+ }
+
+ public static void end(String name) {
+ if (sEnabled) {
+ nativeEnd(name, null);
+ }
+ }
+
+ public static void end(String name, String arg) {
+ if (sEnabled) {
+ nativeEnd(name, arg);
+ }
+ }
+
+ private static String getCallerName() {
+ // This was measured to take about 1ms on Trygon device.
+ StackTraceElement[] stack = java.lang.Thread.currentThread().getStackTrace();
+
+ // Commented out to avoid excess call overhead, but these lines can be useful to debug
+ // exactly where the TraceEvent's client is on the callstack.
+ // int index = 0;
+ // while (!stack[index].getClassName().equals(TraceEvent.class.getName())) ++index;
+ // while (stack[index].getClassName().equals(TraceEvent.class.getName())) ++index;
+ // System.logW("TraceEvent caller is at stack index " + index);
+
+ // '4' Was derived using the above commented out code snippet.
+ return stack[4].getClassName() + "." + stack[4].getMethodName();
+ }
+
+ private static native boolean nativeTraceEnabled();
+ private static native void nativeInstant(String name, String arg);
+ private static native void nativeBegin(String name, String arg);
+ private static native void nativeEnd(String name, String arg);
+}
diff --git a/content/shell/android/content_shell_apk.xml b/content/shell/android/content_shell_apk.xml
index 3e89773b..003380b 100644
--- a/content/shell/android/content_shell_apk.xml
+++ b/content/shell/android/content_shell_apk.xml
@@ -23,6 +23,13 @@
<fileset file="${toolchain.dir}/../../gdbserver"/>
</path>
<property name="native.libs.absolute.dir" location="${out.dir}/libs" />
+ <!-- If your app crashes when referencing java from a different .jar
+ (e.g. java.lang.NoClassDefFoundError:
+ org.chromium.content.browser.CommandLine), And if
+ chromium_content.jar is in fact in your java/libs directory (as
+ placed by a gyp 'cp'), the following line will make sure it
+ gets added to the classes.dex file. -->
+ <property name="out.classes.absolute.dir" location="${jar.libs.dir}" />
<!-- We expect PRODUCT_DIR to be set like the gyp var
(e.g. $ROOT/out/Debug) -->
diff --git a/content/shell/android/java/org/chromium/content_shell/ContentShellActivity.java b/content/shell/android/java/org/chromium/content_shell/ContentShellActivity.java
index a3a1028..ce6ca88 100644
--- a/content/shell/android/java/org/chromium/content_shell/ContentShellActivity.java
+++ b/content/shell/android/java/org/chromium/content_shell/ContentShellActivity.java
@@ -7,11 +7,14 @@ package org.chromium.content_shell;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Debug;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
+import org.chromium.content.browser.CommandLine;
import org.chromium.content.browser.ContentView;
+import org.chromium.content.browser.LibraryLoader;
/**
* Activity for managing the Content Shell.
@@ -20,6 +23,7 @@ public class ContentShellActivity extends Activity {
private static final String COMMAND_LINE_FILE = "/data/local/content-shell-command-line";
private static final String TAG = "ContentShellActivity";
+ private static final String NATIVE_LIBRARY = "content_shell_content_view";
private ShellManager mShellManager;
@@ -28,17 +32,17 @@ public class ContentShellActivity extends Activity {
super.onCreate(savedInstanceState);
// Initializing the command line must occur before loading the library.
- // TODO(tedchoc): Initialize command line from file.
+ CommandLine.initFromFile(COMMAND_LINE_FILE);
String startupUrl = getUrlFromIntent(getIntent());
if (!TextUtils.isEmpty(startupUrl)) {
- // TODO(tedchoc): Append URL to command line.
+ CommandLine.getInstance().appendSwitchesAndArguments(
+ new String[] {ShellView.sanitizeUrl(startupUrl)});
}
- // TODO(jrg,tedchoc): upstream the async library loader, then
- // make this call look like this:
- // LibraryLoader.loadAndInitSync();
- loadNativeLibrary();
-
+ // TODO(jrg): once command line support is addef (for
+ // --wait-for-debugger), remove this.
+ // Debug.waitForDebugger();
+ LibraryLoader.loadAndInitSync();
initializeContentViewResources();
setContentView(R.layout.content_shell_activity);
@@ -93,18 +97,4 @@ public class ContentShellActivity extends Activity {
ContentView.registerPopupOverlayCornerRadius(0);
ContentView.registerPopupOverlayResourceId(R.drawable.popup_zoomer_overlay);
}
-
-
- private static final String NATIVE_LIBRARY = "content_shell_content_view";
-
- private void loadNativeLibrary() throws UnsatisfiedLinkError {
- Log.i(TAG, "loading: " + NATIVE_LIBRARY);
- try {
- System.loadLibrary(NATIVE_LIBRARY);
- } catch (UnsatisfiedLinkError e) {
- Log.e(TAG, "Unable to load lib" + NATIVE_LIBRARY + ".so: " + e);
- throw e;
- }
- Log.i(TAG, "loaded: " + NATIVE_LIBRARY);
- }
}
diff --git a/content/shell/android/java/org/chromium/content_shell/ContentShellApplication.java b/content/shell/android/java/org/chromium/content_shell/ContentShellApplication.java
index 9f2a0de..56b4cf5 100644
--- a/content/shell/android/java/org/chromium/content_shell/ContentShellApplication.java
+++ b/content/shell/android/java/org/chromium/content_shell/ContentShellApplication.java
@@ -5,16 +5,22 @@
package org.chromium.content_shell;
import android.app.Application;
+import org.chromium.content.browser.LibraryLoader;
/**
* Entry point for the content shell application. Handles initialization of information that needs
* to be shared across the main activity and the sandbox services created.
*/
public class ContentShellApplication extends Application {
+
+ // TODO(jrg): do not downstream this filename!
+ private static final String NATIVE_LIBRARY = "content_shell_content_view";
+
@Override
public void onCreate() {
super.onCreate();
- // TODO(tedchoc): Initialize the .pak files to load and the native library name.
+ // TODO(tedchoc): Initialize the .pak files to load
+ LibraryLoader.setLibraryToLoad(NATIVE_LIBRARY);
}
}
diff --git a/content/shell/android/shell_library_loader.cc b/content/shell/android/shell_library_loader.cc
index e447d7e7..3b6757e 100644
--- a/content/shell/android/shell_library_loader.cc
+++ b/content/shell/android/shell_library_loader.cc
@@ -3,8 +3,11 @@
// found in the LICENSE file.
#include "base/basictypes.h"
+#include "base/debug/debugger.h"
+#include "base/logging.h"
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
+#include "content/public/app/content_main_runner.h"
#include "content/public/browser/android_library_loader_hooks.h"
#include "content/shell/shell_main_delegate.h"
#include "content/shell/android/shell_manager.h"
@@ -15,8 +18,32 @@ static base::android::RegistrationMethod kRegistrationMethods[] = {
{ "ShellView", content::ShellView::Register },
};
+namespace {
+ content::ContentMainRunner* g_content_main_runner = NULL;
+}
+
// This is called by the VM when the shared library is first loaded.
JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+
+ // Don't call anything in base without initializing it.
+ // ContentMainRunner will do what we need.
+ g_content_main_runner = content::ContentMainRunner::Create();
+
+ // TODO(tedchoc): Set this to the main delegate once the Android specific
+ // browser process initialization gets checked in.
+ ShellMainDelegate* delegate = new ShellMainDelegate();
+
+ // We use a ShellContentClient, created as a member of
+ // ShellMainDelegate and set with a call to
+ // content::SetContentClient() in PreSandboxStartup().
+ // That must be done before ContentMainRunner::Initialize().
+ // TODO(jrg): resolve the upstream/downstream discrepancy; we
+ // shouldn't need to do this.
+ delegate->PreSandboxStartup();
+
+ // TODO(jrg): find command line info from java; pass down in here.
+ g_content_main_runner->Initialize(0, NULL, NULL);
+
base::android::InitVM(vm);
JNIEnv* env = base::android::AttachCurrentThread();
if (!RegisterLibraryLoaderEntryHook(env)) {
@@ -29,9 +56,12 @@ JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
arraysize(kRegistrationMethods)))
return -1;
- // TODO(tedchoc): Set this to the main delegate once the Android specific
- // browser process initialization gets checked in.
- new ShellMainDelegate();
-
return JNI_VERSION_1_4;
}
+
+
+JNI_EXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {
+ delete g_content_main_runner;
+ g_content_main_runner = NULL;
+}
+
diff --git a/media/base/android/java/media.xml b/media/base/android/java/media.xml
index 28a8ef1..8516e3e 100644
--- a/media/base/android/java/media.xml
+++ b/media/base/android/java/media.xml
@@ -14,6 +14,8 @@
<property name="src" location="."/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
+ <property name="out.dir" location="${PRODUCT_DIR}/lib.java"/>
+ <property name="dest.dir" location="${PRODUCT_DIR}/java/media"/>
<condition property="location.base"
value="${sdk.dir}"
@@ -25,15 +27,17 @@
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
- <mkdir dir="${build}"/>
+ <mkdir dir="${out.dir}"/>
+ <mkdir dir="${dest.dir}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
- <!-- Compile the java code from ${src} into ${build} -->
- <javac srcdir="${src}" destdir="${build}">
+ <!-- Compile the java code from ${src} into ${dest.dir} -->
+ <javac srcdir="${src}" destdir="${dest.dir}">
<classpath>
- <path location="${location.base}/android.jar"/>
+ <pathelement path="${location.base}/android.jar" />
+ <pathelement path="${out.dir}/chromium_base.jar" />
</classpath>
</javac>
</target>
@@ -44,13 +48,13 @@
<mkdir dir="${dist}/lib"/>
<!-- Put everything in ${build} into the chromium_media.jar file -->
- <jar jarfile="${dist}/lib/chromium_media.jar" basedir="${build}"/>
+ <jar jarfile="${out.dir}/chromium_media.jar" basedir="${dest.dir}"/>
</target>
<target name="clean"
description="clean up" >
- <!-- Delete the ${build} and ${dist} directory trees -->
- <delete dir="${build}"/>
+ <!-- Delete the appropriate directory trees -->
+ <delete dir="${dest.dir}"/>
<delete dir="${dist}"/>
</target>
</project>
diff --git a/media/media.gyp b/media/media.gyp
index 619c188..65fd702 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -939,6 +939,7 @@
],
'dependencies': [
'../base/base.gyp:base',
+ 'media_java',
],
'include_dirs': [
'<(SHARED_INTERMEDIATE_DIR)/media',
@@ -963,6 +964,17 @@
},
],
},
+ {
+ 'target_name': 'media_java',
+ 'type': 'none',
+ 'dependencies': [ '../base/base.gyp:base_java' ],
+ 'variables': {
+ 'package_name': 'media',
+ 'java_in_dir': 'base/android/java',
+ },
+ 'includes': [ '../build/java.gypi' ],
+ },
+
],
}, { # OS != "android"'
# Android does not use ffmpeg, so disable the targets which require it.
diff --git a/net/android/java/net.xml b/net/android/java/net.xml
index 76dddcc..29c9b02 100644
--- a/net/android/java/net.xml
+++ b/net/android/java/net.xml
@@ -38,7 +38,7 @@
<javac srcdir="${src}" destdir="${dest.dir}">
<classpath>
<path location="${location.base}/android.jar"/>
- <path location="${PRODUCT_DIR}/chromium_base.jar"/>
+ <path location="${out.dir}/chromium_base.jar"/>
</classpath>
</javac>
</target>