Skip to content

Commit e83ebb0

Browse files
committed
Initial commit of working Android app embedded with v8, with prebuilt library included
1 parent c64090d commit e83ebb0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+14928
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.DS_Store

README.md

+69
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,71 @@
11
# v8-android
22
Example Android Studio project that embeds v8 (plus some notes on compiling v8 for android)
3+
4+
The intention is to embed v8 inside an Android app, and this project is an example of getting "Hello World" from Javascript to show up on the Android app (using v8).
5+
6+
## How to use:
7+
1. Clone this repository, and open the `jni-test` directory as a project in your Android Studio.
8+
2. Run the project after connecting your phone via USB.
9+
10+
Incase it has issues, try renaming the `app/libs/armeabi-v7a` directory to your phone's ABI format, like `app/libs/arm64-v8a` or something. Or maybe just edit the `app/CMakeLists.txt` file and remove the `${ANDROID_ABI}` parameter.
11+
12+
This uses a prebuilt v8 library for Android, compiled from the 6.8 branch of v8 on July 22, 2018 (5b8126a8d6fa0c58c89c2d618264ee087d6795a1 (HEAD -> 6.8, tag: lkgr/6.8, tag: 6.8.275.2)). You may want to create a new binary.
13+
14+
## Here's what was done broadly:
15+
1. Compile v8 for android_arm target
16+
2. Manually generate the ".a" static libraries from the ".o" files using the 'ar' command. The build-generated versions weren't working for some reason.
17+
3. Create an Android NDK project from Android Studio.
18+
4. Copy the `include` directory from v8, and the static libraries created previously and paste into an Android project's `app/libs/armeabi-v7a/` directory.
19+
5. Specify these libraries and include directory path in the Android project's `CMakesLists.txt` file.
20+
6. Use v8 in the native C++ file, which gets called from the Java Android Activity via JNI.
21+
22+
## For compiling v8:
23+
0. Build on Ubuntu (or some Linux with ELF and glibc). I was on a Mac, so I created a Virtual Machine and used Ubuntu Server for a minimal distro. Give it atleast 40 GB of disk (can use dynamic resize).
24+
1. Follow https://github.com/v8/v8/wiki/Building-from-Source
25+
2. But before running `v8gen.py`, first run `echo "target_os = ['android']" >> /path/to/workingDir/.gclient && gclient sync`
26+
3. Then run `tools/dev/v8gen.py gen -m client.v8.ports -b "V8 Android Arm - builder" android_arm.release`
27+
4. Next, run `gn args out.gn/android_arm.release` and use these flags:
28+
```
29+
is_component_build = false
30+
is_debug = false
31+
symbol_level = 1
32+
target_cpu = "arm"
33+
target_os = "android"
34+
use_goma = false
35+
v8_android_log_stdout = true
36+
v8_static_library = true
37+
use_custom_libcxx = false
38+
use_custom_libcxx_for_host = false
39+
v8_use_external_startup_data = false
40+
```
41+
5. Next, run `ninja -C out.gn/android_arm.release`
42+
6. Then create the `libv8_base.a` and `libv8_snapshot.a` static libraries manually (the built ones don't seem to work for some reason):
43+
```
44+
mkdir libs
45+
cd libs
46+
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/v8_base/*.o
47+
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/v8_libbase/*.o
48+
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/v8_libsampler/*.o
49+
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/v8_libplatform/*.o
50+
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/src/inspector/inspector/*.o
51+
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/third_party/icu/icuuc/*.o
52+
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/third_party/icu/icui18n/*.o
53+
ar -rcsD libv8_snapshot.a /path/to/v8/out.gn/android_arm.release/obj/v8_snapshot/*.o
54+
```
55+
6. Then copy the includes using `cp -R /path/to/v8/include .`
56+
7. Now you can use these in your Android NDK project
57+
58+
## Using the compiled v8 binaries in an Android NDK project
59+
1. Either create a new Android NDK project in your Android Studio, or use one that's already set up with CMake
60+
2. Copy the `include` directory from v8, and the static libraries created previously and paste into an Android project's `app/libs/armeabi-v7a/` directory.
61+
3. Specify these libraries and include directory path in the Android project's `CMakesLists.txt` file.
62+
4. Use v8 in the native C++ file, which gets called from the Java Android Activity via JNI.
63+
64+
Use the example project for the example `CMakeLists.txt` and C++ file.
65+
66+
## Random note
67+
The key gotcha was that the `.a` files created by the build didn't seem to work for some reason, or maybe I was messing the order. So what worked was manually combining the relevant `.o` files (base, libbase, platform, sampler, inspector, icui18n, icuuc) into libv8_base.a, and the v8_snapshot `.o` files into libv8_snapshot.a.
68+
69+
Then the order in CMakeList was important: v8_base followed by v8_snapshot.
70+
71+
Another thing to remember: this process will probably take 30 GB of disk space, and download probably 15 GB of stuff. This could be because it downloaded stuff a few times, mostly because of my sheer incompetence at compiling v8. But size your VM disk, time and patience accordingly.

jni-test/.gitignore

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea/libraries
5+
/.idea/modules.xml
6+
/.idea/workspace.xml
7+
.DS_Store
8+
/build
9+
/captures
10+
.externalNativeBuild
585 Bytes
Binary file not shown.

jni-test/.idea/codeStyles/Project.xml

+29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jni-test/.idea/compiler.xml

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jni-test/.idea/gradle.xml

+18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jni-test/.idea/misc.xml

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jni-test/.idea/runConfigurations.xml

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jni-test/app/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

jni-test/app/CMakeLists.txt

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
cmake_minimum_required(VERSION 3.4.1)
2+
3+
add_library( v8_base STATIC IMPORTED )
4+
set_target_properties( v8_base PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libv8_base.a )
5+
6+
add_library( v8_snapshot STATIC IMPORTED )
7+
set_target_properties( v8_snapshot PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libv8_snapshot.a )
8+
9+
add_library( native-lib SHARED src/main/cpp/native-lib.cpp )
10+
target_include_directories( native-lib PRIVATE ${CMAKE_SOURCE_DIR}/libs/include )
11+
12+
target_link_libraries( native-lib v8_base v8_snapshot log )

jni-test/app/build.gradle

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
apply plugin: 'com.android.application'
2+
3+
android {
4+
compileSdkVersion 26
5+
defaultConfig {
6+
applicationId "org.cmdr2.jnitest"
7+
minSdkVersion 19
8+
targetSdkVersion 26
9+
versionCode 1
10+
versionName "1.0"
11+
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12+
externalNativeBuild {
13+
cmake {
14+
cppFlags "-std=c++0x"
15+
}
16+
}
17+
}
18+
buildTypes {
19+
release {
20+
minifyEnabled false
21+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22+
}
23+
}
24+
externalNativeBuild {
25+
cmake {
26+
path "CMakeLists.txt"
27+
}
28+
}
29+
}
30+
31+
dependencies {
32+
implementation fileTree(dir: 'libs', include: ['*.jar'])
33+
implementation 'com.android.support:appcompat-v7:26.1.0'
34+
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
35+
testImplementation 'junit:junit:4.12'
36+
androidTestImplementation 'com.android.support.test:runner:1.0.2'
37+
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
38+
}
98.1 MB
Binary file not shown.
1.52 MB
Binary file not shown.
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# The V8 public C++ API
2+
3+
# Overview
4+
5+
The V8 public C++ API aims to support four use cases:
6+
7+
1. Enable applications that embed V8 (called the embedder) to configure and run
8+
one or more instances of V8.
9+
2. Expose ECMAScript-like capabilities to the embedder.
10+
3. Enable the embedder to interact with ECMAScript by exposing API objects.
11+
4. Provide access to the V8 debugger (inspector).
12+
13+
# Configuring and running an instance of V8
14+
15+
V8 requires access to certain OS-level primitives such as the ability to
16+
schedule work on threads, or allocate memory.
17+
18+
The embedder can define how to access those primitives via the v8::Platform
19+
interface. While V8 bundles a basic implementation, embedders are highly
20+
encouraged to implement v8::Platform themselves.
21+
22+
Currently, the v8::ArrayBuffer::Allocator is passed to the v8::Isolate factory
23+
method, however, conceptually it should also be part of the v8::Platform since
24+
all instances of V8 should share one allocator.
25+
26+
Once the v8::Platform is configured, an v8::Isolate can be created. All
27+
further interactions with V8 should explicitly reference the v8::Isolate they
28+
refer to. All API methods should eventually take an v8::Isolate parameter.
29+
30+
When a given instance of V8 is no longer needed, it can be destroyed by
31+
disposing the respective v8::Isolate. If the embedder wishes to free all memory
32+
associated with the v8::Isolate, it has to first clear all global handles
33+
associated with that v8::Isolate.
34+
35+
# ECMAScript-like capabilities
36+
37+
In general, the C++ API shouldn't enable capabilities that aren't available to
38+
scripts running in V8. Experience has shown that it's not possible to maintain
39+
such API methods in the long term. However, capabilities also available to
40+
scripts, i.e., ones that are defined in the ECMAScript standard are there to
41+
stay, and we can safely expose them to embedders.
42+
43+
The C++ API should also be pleasant to use, and not require learning new
44+
paradigms. Similarly to how the API exposed to scripts aims to provide good
45+
ergonomics, we should aim to provide a reasonable developer experience for this
46+
API surface.
47+
48+
ECMAScript makes heavy use of exceptions, however, V8's C++ code doesn't use
49+
C++ exceptions. Therefore, all API methods that can throw exceptions should
50+
indicate so by returning a v8::Maybe<> or v8::MaybeLocal<> result,
51+
and by taking a v8::Local<v8::Context> parameter that indicates in which
52+
context a possible exception should be thrown.
53+
54+
# API objects
55+
56+
V8 allows embedders to define special objects that expose additional
57+
capabilities and APIs to scripts. The most prominent example is exposing the
58+
HTML DOM in Blink. Other examples are e.g. node.js. It is less clear what kind
59+
of capabilities we want to expose via this API surface. As a rule of thumb, we
60+
want to expose operations as defined in the WebIDL and HTML spec: we
61+
assume that those requirements are somewhat stable, and that they are a
62+
superset of the requirements of other embedders including node.js.
63+
64+
Ideally, the API surfaces defined in those specs hook into the ECMAScript spec
65+
which in turn guarantees long-term stability of the API.
66+
67+
# The V8 inspector
68+
69+
All debugging capabilities of V8 should be exposed via the inspector protocol.

jni-test/app/libs/include/DEPS

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include_rules = [
2+
# v8-inspector-protocol.h depends on generated files under include/inspector.
3+
"+inspector",
4+
]

jni-test/app/libs/include/OWNERS

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
set noparent
2+
3+
4+
5+
6+
7+
8+
9+
10+
11+
12+
13+
# COMPONENT: Blink>JavaScript>API
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright 2017 the V8 project authors. All rights reserved.')
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
"""Presubmit script for //v8/include
6+
7+
See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
8+
for more details about the presubmit API built into depot_tools.
9+
"""
10+
11+
import os
12+
13+
14+
def PostUploadHook(cl, change, output_api):
15+
"""git cl upload will call this hook after the issue is created/modified.
16+
17+
This hook adds extra try bots to the CL description in order to run layout
18+
tests in addition to CQ try bots.
19+
"""
20+
def header_filter(f):
21+
return '.h' in os.path.split(f.LocalPath())[1]
22+
if not change.AffectedFiles(file_filter=header_filter):
23+
return []
24+
return output_api.EnsureCQIncludeTrybotsAreAdded(
25+
cl,
26+
[
27+
'luci.chromium.try:linux_chromium_rel_ng'
28+
],
29+
'Automatically added layout test trybots to run tests on CQ.')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
include_rules = [
2+
"+libplatform/libplatform-export.h",
3+
]
4+
5+
specific_include_rules = {
6+
"libplatform\.h": [
7+
"+libplatform/v8-tracing.h",
8+
],
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2016 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_
6+
#define V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_
7+
8+
#if defined(_WIN32)
9+
10+
#ifdef BUILDING_V8_PLATFORM_SHARED
11+
#define V8_PLATFORM_EXPORT __declspec(dllexport)
12+
#elif USING_V8_PLATFORM_SHARED
13+
#define V8_PLATFORM_EXPORT __declspec(dllimport)
14+
#else
15+
#define V8_PLATFORM_EXPORT
16+
#endif // BUILDING_V8_PLATFORM_SHARED
17+
18+
#else // defined(_WIN32)
19+
20+
// Setup for Linux shared library export.
21+
#ifdef BUILDING_V8_PLATFORM_SHARED
22+
#define V8_PLATFORM_EXPORT __attribute__((visibility("default")))
23+
#else
24+
#define V8_PLATFORM_EXPORT
25+
#endif
26+
27+
#endif // defined(_WIN32)
28+
29+
#endif // V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_

0 commit comments

Comments
 (0)