diff options
author | wangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-01 17:20:04 +0000 |
---|---|---|
committer | wangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-01 17:20:04 +0000 |
commit | 7ed054dbdb861d45a06055483d18d739234efbb1 (patch) | |
tree | 9b384ffd0ebde8890350e1f24f01c491a1e37bab | |
parent | 3b2b45c0276a8238d1f83e01764d32c5f56cba73 (diff) | |
download | chromium_src-7ed054dbdb861d45a06055483d18d739234efbb1.zip chromium_src-7ed054dbdb861d45a06055483d18d739234efbb1.tar.gz chromium_src-7ed054dbdb861d45a06055483d18d739234efbb1.tar.bz2 |
Chromium support of running DumpRenderTree as an apk on Android
This is an upstream of chromium-android.
The WebKit part is https://bugs.webkit.org/show_bug.cgi?id=86862.
TBR=darin (for base/base.gyp)
BUG=none
TEST=build and run current native tests without error
Review URL: https://chromiumcodereview.appspot.com/10408091
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140046 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/base.gyp | 3 | ||||
-rw-r--r-- | base/test/test_stub_android.h | 14 | ||||
-rw-r--r-- | base/test/test_suite.cc | 17 | ||||
-rw-r--r-- | base/test/test_support_android.cc (renamed from base/test/test_stub_android.cc) | 55 | ||||
-rw-r--r-- | base/test/test_support_android.h | 20 | ||||
-rwxr-xr-x | testing/android/generate_native_test.py | 29 | ||||
-rw-r--r-- | testing/android/native_test.gyp | 10 | ||||
-rw-r--r-- | testing/android/native_test_launcher.cc | 64 | ||||
-rw-r--r-- | webkit/support/DEPS | 1 | ||||
-rw-r--r-- | webkit/support/platform_support_android.cc | 31 | ||||
-rw-r--r-- | webkit/support/webkit_support.cc | 13 |
11 files changed, 151 insertions, 106 deletions
diff --git a/base/base.gyp b/base/base.gyp index 72bfdc6..4aa3de7 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -458,7 +458,8 @@ 'test/test_reg_util_win.h', 'test/test_suite.cc', 'test/test_suite.h', - 'test/test_stub_android.cc', + 'test/test_support_android.cc', + 'test/test_support_android.h', 'test/test_switches.cc', 'test/test_switches.h', 'test/test_timeouts.cc', diff --git a/base/test/test_stub_android.h b/base/test/test_stub_android.h deleted file mode 100644 index fa897d9..0000000 --- a/base/test/test_stub_android.h +++ /dev/null @@ -1,14 +0,0 @@ -// 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 BASE_TEST_TEST_STUB_ANDROID_H_ -#define BASE_TEST_TEST_STUB_ANDROID_H_ - -// Initialize the Android test environment. -void InitAndroidTestStub(); - -// Register path providers for tests. -void InitAndroidOSPathStub(); - -#endif // BASE_TEST_TEST_STUB_ANDROID_H_ diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc index 75e9ff5..83a2549 100644 --- a/base/test/test_suite.cc +++ b/base/test/test_suite.cc @@ -28,7 +28,7 @@ #endif #if defined(OS_ANDROID) -#include "base/test/test_stub_android.h" +#include "base/test/test_support_android.h" #endif #if defined(TOOLKIT_GTK) @@ -101,8 +101,13 @@ void TestSuite::PreInitialize(int argc, char** argv, #elif defined(TOOLKIT_GTK) gtk_init_check(&argc, &argv); #endif // defined(TOOLKIT_GTK) + + // On Android when building tests as apks, AtExitManager is created in + // testing/android/native_test_wrapper.cc before main() is called. +#if !defined(ANDROID_APK_TEST_TARGET) if (create_at_exit_manager) at_exit_manager_.reset(new base::AtExitManager); +#endif // Don't add additional code to this function. Instead add it to // Initialize(). See bug 6436. @@ -237,9 +242,8 @@ void TestSuite::Initialize() { #endif #if defined(OS_ANDROID) - InitAndroidTestStub(); -#endif - + InitAndroidTest(); +#else // Initialize logging. FilePath exe; PathService::Get(base::FILE_EXE, &exe); @@ -253,6 +257,7 @@ void TestSuite::Initialize() { // We want process and thread IDs because we may have multiple processes. // Note: temporarily enabled timestamps in an effort to catch bug 6361. logging::SetLogItems(true, true, true, true); +#endif // else defined(OS_ANDROID) CHECK(base::EnableInProcessStackDumping()); #if defined(OS_WIN) @@ -269,11 +274,7 @@ void TestSuite::Initialize() { logging::SetLogAssertHandler(UnitTestAssertHandler); } -#if !defined(OS_ANDROID) - // TODO(michaelbai): The icu can not be compiled in Android now, this should - // be enabled once icu is ready. http://b/5406077. icu_util::Initialize(); -#endif CatchMaybeTests(); ResetCommandLine(); diff --git a/base/test/test_stub_android.cc b/base/test/test_support_android.cc index aaf952e..5e5a8ae 100644 --- a/base/test/test_stub_android.cc +++ b/base/test/test_support_android.cc @@ -68,16 +68,18 @@ class Waitable { } base::WaitableEvent waitable_event_; + + DISALLOW_COPY_AND_ASSIGN(Waitable); }; // The MessagePumpForUI implementation for test purpose. class MessagePumpForUIStub : public base::MessagePumpForUI { - void Start(base::MessagePump::Delegate* delegate) { + virtual void Start(base::MessagePump::Delegate* delegate) OVERRIDE { NOTREACHED() << "The Start() method shouldn't be called in test, using" " Run() method should be used."; } - void Run(base::MessagePump::Delegate* delegate) { + virtual void Run(base::MessagePump::Delegate* delegate) OVERRIDE { // The following was based on message_pump_glib.cc, except we're using a // WaitableEvent since there are no native message loop to use. RunState state(delegate, g_state ? g_state->run_depth + 1 : 1); @@ -117,21 +119,26 @@ class MessagePumpForUIStub : public base::MessagePumpForUI { g_state = previous_state; } - void Quit() { + virtual void Quit() OVERRIDE { Waitable::GetInstance()->Quit(); } - void ScheduleWork() { + virtual void ScheduleWork() OVERRIDE { Waitable::GetInstance()->Signal(); } - void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) { + virtual void ScheduleDelayedWork( + const base::TimeTicks& delayed_work_time) OVERRIDE { Waitable::GetInstance()->Signal(); } }; +base::MessagePump* CreateMessagePumpForUIStub() { + return new MessagePumpForUIStub(); +}; + // Provides the test path for DIR_MODULE, DIR_CACHE and DIR_ANDROID_APP_DATA. -bool PathTestProviderAndroid(int key, FilePath* result) { +bool GetTestProviderPath(int key, FilePath* result) { switch (key) { case base::DIR_MODULE: { *result = FilePath(kAndroidTestTempDirectory); @@ -154,21 +161,16 @@ bool PathTestProviderAndroid(int key, FilePath* result) { } } -// The factory method to create a MessagePumpForUI. -base::MessagePump* CreateMessagePumpForUIStub() { - return new MessagePumpForUIStub(); +void InitPathProvider(int key) { + FilePath path; + // If failed to override the key, that means the way has not been registered. + if (GetTestProviderPath(key, &path) && !PathService::Override(key, path)) + PathService::RegisterProvider(&GetTestProviderPath, key, key + 1); } } // namespace -void InitAndroidOSPathStub() { - PathService::Override(base::DIR_MODULE, FilePath(kAndroidTestTempDirectory)); - PathService::Override(base::DIR_CACHE, FilePath(kAndroidTestTempDirectory)); - PathService::Override(base::DIR_ANDROID_APP_DATA, - FilePath(kAndroidTestTempDirectory)); -} - -void InitAndroidTestStub() { +void InitAndroidTestLogging() { logging::InitLogging(NULL, logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, logging::DONT_LOCK_LOG_FILE, @@ -179,13 +181,20 @@ void InitAndroidTestStub() { false, // Thread ID false, // Timestamp false); // Tick count +} - PathService::RegisterProvider(&PathTestProviderAndroid, base::DIR_MODULE, - base::DIR_MODULE + 1); - PathService::RegisterProvider(&PathTestProviderAndroid, base::DIR_CACHE, - base::DIR_CACHE + 1); - PathService::RegisterProvider(&PathTestProviderAndroid, - base::DIR_ANDROID_APP_DATA, base::DIR_ANDROID_APP_DATA + 1); +void InitAndroidTestPaths() { + InitPathProvider(base::DIR_MODULE); + InitPathProvider(base::DIR_CACHE); + InitPathProvider(base::DIR_ANDROID_APP_DATA); +} +void InitAndroidTestMessageLoop() { MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub); } + +void InitAndroidTest() { + InitAndroidTestLogging(); + InitAndroidTestPaths(); + InitAndroidTestMessageLoop(); +} diff --git a/base/test/test_support_android.h b/base/test/test_support_android.h new file mode 100644 index 0000000..09b188c --- /dev/null +++ b/base/test/test_support_android.h @@ -0,0 +1,20 @@ +// 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 BASE_TEST_TEST_SUPPORT_ANDROID_H_ +#define BASE_TEST_TEST_SUPPORT_ANDROID_H_ + +// Init logging for tests on Android. Logs will be output into Android's logcat. +void InitAndroidTestLogging(); + +// Init path providers for tests on Android. +void InitAndroidTestPaths(); + +// Init the message loop for tests on Android. +void InitAndroidTestMessageLoop(); + +// Do all of the initializations above. +void InitAndroidTest(); + +#endif // BASE_TEST_TEST_SUPPORT_ANDROID_H_ diff --git a/testing/android/generate_native_test.py b/testing/android/generate_native_test.py index 5fe664a..658a13a 100755 --- a/testing/android/generate_native_test.py +++ b/testing/android/generate_native_test.py @@ -137,8 +137,11 @@ class NativeTestApkGenerator(object): logging.warn('%s --> %s' % (jar, dest)) shutil.copyfile(jar, dest) - def CreateBundle(self): + def CreateBundle(self, ant_compile): """Create the apk bundle source and assemble components.""" + if not ant_compile: + self._SOURCE_FILES.append('Android.mk') + self._REPLACEME_FILES.append('Android.mk') self._CopyTemplateFiles() self._ReplaceStrings() self._CopyLibraryAndJars() @@ -162,6 +165,16 @@ class NativeTestApkGenerator(object): logging.error('Ant return code %d' % p.returncode) sys.exit(p.returncode) + def CompileAndroidMk(self): + """Build the generated apk within Android source tree using Android.mk.""" + try: + import compile_android_mk # pylint: disable=F0401 + except: + raise AssertionError('Not in Android source tree. ' + 'Please use --ant-compile.') + compile_android_mk.CompileAndroidMk(self._native_library, + self._output_directory) + def main(argv): parser = optparse.OptionParser() @@ -176,7 +189,9 @@ def main(argv): parser.add_option('--app_abi', default='armeabi', help='ABI for native shared library') parser.add_option('--ant-compile', action='store_true', - help='If specified, build the generated apk with ant') + help='If specified, build the generated apk with ant. ' + 'Otherwise assume compiling within the Android ' + 'source tree using Android.mk.') parser.add_option('--ant-args', help='extra args for ant') @@ -195,13 +210,21 @@ def main(argv): jar_list = [] if options.jars: jar_list = options.jars.replace('"', '').split() + + # Ignore --ant-compile when building with Android source. + if 'ANDROID_BUILD_TOP' in os.environ: + options.ant_compile = False + ntag = NativeTestApkGenerator(native_library=options.native_library, jars=jar_list, output_directory=options.output, target_abi=options.app_abi) - ntag.CreateBundle() + ntag.CreateBundle(options.ant_compile) + if options.ant_compile: ntag.Compile(options.ant_args) + else: + ntag.CompileAndroidMk() logging.warn('COMPLETE.') diff --git a/testing/android/native_test.gyp b/testing/android/native_test.gyp index 4b25f7c..3718907 100644 --- a/testing/android/native_test.gyp +++ b/testing/android/native_test.gyp @@ -42,9 +42,9 @@ 'target_name': 'native_test_native_code', 'message': 'building native pieces of native test package', 'type': 'static_library', - 'sources': [ - 'native_test_launcher.cc', - ], + 'sources': [ + 'native_test_launcher.cc', + ], 'direct_dependent_settings': { 'ldflags!': [ # JNI_OnLoad is implemented in a .a and we need to @@ -53,14 +53,14 @@ ], }, 'dependencies': [ - 'jni_headers', '../../base/base.gyp:base', '../../base/base.gyp:test_support_base', '../gtest.gyp:gtest', + 'native_test_jni_headers', ], }, { - 'target_name': 'jni_headers', + 'target_name': 'native_test_jni_headers', 'type': 'none', 'actions': [ { diff --git a/testing/android/native_test_launcher.cc b/testing/android/native_test_launcher.cc index d8caaaa..06ecd18 100644 --- a/testing/android/native_test_launcher.cc +++ b/testing/android/native_test_launcher.cc @@ -26,11 +26,11 @@ #include "base/stringprintf.h" #include "base/string_tokenizer.h" #include "base/string_util.h" -#include "base/test/test_suite.h" -#include "testing/android/jni/chrome_native_test_activity_jni.h" +#include "base/test/test_support_android.h" #include "gtest/gtest.h" +#include "testing/android/jni/chrome_native_test_activity_jni.h" -// GTest's main function. +// The main function of the program to be wrapped as a test apk. extern int main(int argc, char** argv); namespace { @@ -74,7 +74,8 @@ void ParseArgsFromString(const std::string& command_line, } void ParseArgsFromCommandLineFile(std::vector<std::string>* args) { - // The test runner script can write to "/data/local/tmp". + // The test runner script writes the command line file in + // "/data/local/tmp". static const char kCommandLineFilePath[] = "/data/local/tmp/chrome-native-tests-command-line"; FilePath command_line(kCommandLineFilePath); @@ -158,39 +159,6 @@ void AndroidLogPrinter::OnTestProgramEnd( LOG(ERROR) << msg; } -void LibraryLoadedOnMainThread(JNIEnv* env) { - static const char* const kInitialArgv[] = { "ChromeTestActivity" }; - - { - // We need a test suite to be created before we do any tracing or - // logging: it creates a global at_exit_manager and initializes - // internal gtest data structures based on the command line. - // It needs to be scoped as it also resets the CommandLine. - std::vector<std::string> args; - ParseArgsFromCommandLineFile(&args); - std::vector<char*> argv; - ArgsToArgv(args, &argv); - base::TestSuite test_suite(argv.size(), &argv[0]); - } - - CommandLine::Init(arraysize(kInitialArgv), kInitialArgv); - - logging::InitLogging(NULL, - logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, - logging::DONT_LOCK_LOG_FILE, - logging::DELETE_OLD_LOG_FILE, - logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); - // To view log output with IDs and timestamps use "adb logcat -v threadtime". - logging::SetLogItems(false, // Process ID - false, // Thread ID - false, // Timestamp - false); // Tick count - VLOG(0) << "Chromium logging enabled: level = " << logging::GetMinLogLevel() - << ", default verbosity = " << logging::GetVlogVerbosity(); - base::android::RegisterLocaleUtils(env); - base::android::RegisterPathUtils(env); -} - } // namespace // This method is called on a separate java thread so that we won't trigger @@ -199,6 +167,21 @@ static void RunTests(JNIEnv* env, jobject obj, jstring jfiles_dir, jobject app_context) { + base::AtExitManager exit_manager; + + static const char* const kInitialArgv[] = { "ChromeTestActivity" }; + CommandLine::Init(arraysize(kInitialArgv), kInitialArgv); + + // Set the application context in base. + base::android::ScopedJavaLocalRef<jobject> scoped_context( + env, env->NewLocalRef(app_context)); + base::android::InitApplicationContext(scoped_context); + + base::android::RegisterLocaleUtils(env); + base::android::RegisterPathUtils(env); + + InitAndroidTest(); + FilePath files_dir(base::android::ConvertJavaStringToUTF8(env, jfiles_dir)); // A few options, such "--gtest_list_tests", will just use printf directly // and won't use the "AndroidLogPrinter". Redirect stdout to a known file. @@ -217,17 +200,11 @@ static void RunTests(JNIEnv* env, AndroidLogPrinter* log = new AndroidLogPrinter(); log->Init(&argc, &argv[0]); - // Set the application context in base. - base::android::ScopedJavaLocalRef<jobject> scoped_context( - env, env->NewLocalRef(app_context)); - base::android::InitApplicationContext(scoped_context); - main(argc, &argv[0]); } // This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - // Install signal handlers to detect crashes. InstallHandlers(); @@ -236,7 +213,6 @@ JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { if (!RegisterNativesImpl(env)) { return -1; } - LibraryLoadedOnMainThread(env); return JNI_VERSION_1_4; } diff --git a/webkit/support/DEPS b/webkit/support/DEPS index 29ea35e..c110041 100644 --- a/webkit/support/DEPS +++ b/webkit/support/DEPS @@ -1,5 +1,6 @@ include_rules = [ "+media", + "+net", "+ui", "+third_party/libpng", "+third_party/zlib", diff --git a/webkit/support/platform_support_android.cc b/webkit/support/platform_support_android.cc index dd6c914..7298b81 100644 --- a/webkit/support/platform_support_android.cc +++ b/webkit/support/platform_support_android.cc @@ -4,34 +4,50 @@ #include "webkit/support/platform_support.h" +#include "base/android/jni_android.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/logging.h" #include "base/path_service.h" #include "base/string16.h" #include "base/string_piece.h" -#include "base/test/test_stub_android.h" +#include "base/test/test_support_android.h" #include "googleurl/src/gurl.h" #include "grit/webkit_resources.h" +#include "net/android/network_library.h" #include "ui/base/resource/resource_bundle.h" #include "webkit/support/test_webkit_platform_support.h" #include "webkit/tools/test_shell/simple_resource_loader_bridge.h" +namespace { + +// The place where the Android layout test script will put the required tools +// and resources. Must keep consistent with DEVICE_DRT_DIR in +// WebKit/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py. +// TODO(wangxianzhu): Allow running DRT on non-rooted device by putting +// the tools and resources into the apk or under /data/local/tmp. +const char kDumpRenderTreeDir[] = "/data/drt"; + +} + namespace webkit_support { void BeforeInitialize(bool unit_test_mode) { - InitAndroidOSPathStub(); + InitAndroidTestPaths(); + // Set XML_CATALOG_FILES environment variable to blank to prevent libxml from // loading and complaining the non-exsistent /etc/xml/catalog file. setenv("XML_CATALOG_FILES", "", 0); + + JNIEnv* env = base::android::AttachCurrentThread(); + net::android::RegisterNetworkLibrary(env); } void AfterInitialize(bool unit_test_mode) { if (unit_test_mode) return; // We don't have a resource pack when running the unit-tests. - FilePath data_path; - PathService::Get(base::DIR_EXE, &data_path); + FilePath data_path(kDumpRenderTreeDir); data_path = data_path.Append("DumpRenderTree.pak"); ResourceBundle::InitSharedInstanceWithPakFile(data_path); @@ -64,12 +80,11 @@ string16 TestWebKitPlatformSupport::GetLocalizedString(int message_id) { base::StringPiece TestWebKitPlatformSupport::GetDataResource( int resource_id, ui::ScaleFactor scale_factor) { - FilePath resources_path; - PathService::Get(base::DIR_EXE, &resources_path); + FilePath resources_path(kDumpRenderTreeDir); resources_path = resources_path.Append("DumpRenderTree_resources"); switch (resource_id) { case IDR_BROKENIMAGE: { - static std::string broken_image_data; + CR_DEFINE_STATIC_LOCAL(std::string, broken_image_data, ()); if (broken_image_data.empty()) { FilePath path = resources_path.Append("missingImage.gif"); bool success = file_util::ReadFileToString(path, &broken_image_data); @@ -79,7 +94,7 @@ base::StringPiece TestWebKitPlatformSupport::GetDataResource( return broken_image_data; } case IDR_TEXTAREA_RESIZER: { - static std::string resize_corner_data; + CR_DEFINE_STATIC_LOCAL(std::string, resize_corner_data, ()); if (resize_corner_data.empty()) { FilePath path = resources_path.Append("textAreaResizeCorner.png"); bool success = file_util::ReadFileToString(path, &resize_corner_data); diff --git a/webkit/support/webkit_support.cc b/webkit/support/webkit_support.cc index 282ac86..ff3fd40 100644 --- a/webkit/support/webkit_support.cc +++ b/webkit/support/webkit_support.cc @@ -71,6 +71,10 @@ #include "webkit/tools/test_shell/simple_file_system.h" #include "webkit/tools/test_shell/simple_resource_loader_bridge.h" +#if defined(OS_ANDROID) +#include "base/test/test_support_android.h" +#endif + using WebKit::WebCString; using WebKit::WebDevToolsAgentClient; using WebKit::WebFileSystem; @@ -104,6 +108,10 @@ void InitLogging() { } #endif +#if defined(OS_ANDROID) + // On Android we expect the log to appear in logcat. + InitAndroidTestLogging(); +#else FilePath log_filename; PathService::Get(base::DIR_EXE, &log_filename); log_filename = log_filename.AppendASCII("DumpRenderTree.log"); @@ -123,6 +131,7 @@ void InitLogging() { const bool kTimestamp = true; const bool kTickcount = true; logging::SetLogItems(kProcessId, kThreadId, !kTimestamp, kTickcount); +#endif // else defined(OS_ANDROID) } class TestEnvironment { @@ -272,11 +281,15 @@ void SetUpTestEnvironmentImpl(bool unit_test_mode) { // at same time. url_util::Initialize(); base::AtExitManager* at_exit_manager = NULL; + // In Android DumpRenderTree, AtExitManager is created in + // testing/android/native_test_wrapper.cc before main() is called. +#if !defined(OS_ANDROID) // Some initialization code may use a AtExitManager before initializing // TestEnvironment, so we create a AtExitManager early and pass its ownership // to TestEnvironment. if (!unit_test_mode) at_exit_manager = new base::AtExitManager; +#endif webkit_support::BeforeInitialize(unit_test_mode); test_environment = new TestEnvironment(unit_test_mode, at_exit_manager); webkit_support::AfterInitialize(unit_test_mode); |