app, bind: separate the app package from gobind

Historically, the app package implemented Go runtime initialization.
This was convoluted, so the package was used both by all-Go apps
(currently based on Android's NativeActivity) and bind-based apps.

With Go 1.5 we have -buildmode=c-shared, which does a lot of the work
of the old app package. That code was removed a while back, but both
all-Go and gobind-based apps still used package app. The intermingled
initialization processes led to some strange states.

This CL separates gobind-based apps completely from the app package.
As part of that users are now expected to use System.loadLibrary
themselves. (A future CL may want to make the loadLibrary call part
of the .aar generated by gomobile bind.)

Delete the libhello example, which has been replaced by gomobile bind,
which could do with its own example at some point. Also delete the
libhellojni example, which now has nothing to do with the x/mobile
repository.

Change-Id: I444397f246dbafe81e5c53532eb482c197d26f70
Reviewed-on: https://go-review.googlesource.com/11654
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
David Crawshaw 2015-06-27 18:35:21 -04:00
parent 20f0df5da5
commit 8144405762
26 changed files with 22 additions and 538 deletions

View File

@ -1,37 +0,0 @@
package go;
import android.content.Context;
import android.os.Looper;
import android.util.Log;
// Go is an entry point for libraries compiled in Go.
// In an app's Application.onCreate, call:
//
// Go.init(getApplicationContext());
//
// When the function returns, it is safe to start calling
// Go code.
public final class Go {
// init loads libgojni.so and starts the runtime.
public static void init(final Context ctx) {
if (Looper.myLooper() != Looper.getMainLooper()) {
Log.wtf("Go", "Go.init must be called from main thread (looper="+Looper.myLooper().toString()+")");
}
if (running) {
return;
}
running = true;
// TODO(crawshaw): context.registerComponentCallbacks for runtime.GC
System.loadLibrary("gojni");
Go.run(ctx);
new Thread("GoReceive") {
public void run() { Seq.receive(); }
}.start();
}
private static boolean running = false;
private static native void run(Context ctx);
}

View File

@ -45,7 +45,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
current_vm = vm;
current_ctx = NULL;
current_native_activity = NULL;
return JNI_VERSION_1_6;
}
@ -121,15 +120,15 @@ static void* call_main_and_wait() {
callMain(mainPC);
}
// Runtime entry point when using NativeActivity.
// Entry point from NativeActivity.
//
// By here, the Go runtime has been initialized (as we are running in
// -buildmode=c-shared) but main.main hasn't been called yet.
void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_t savedStateSize) {
current_native_activity = activity;
if (current_ctx == NULL) {
// Note that activity->clazz is mis-named.
current_vm = activity->vm;
current_ctx = (*activity->env)->NewGlobalRef(activity->env, activity->clazz);
call_main_and_wait();
}
// Note that activity->clazz is mis-named.
current_vm = activity->vm;
current_ctx = (*activity->env)->NewGlobalRef(activity->env, activity->clazz);
call_main_and_wait();
// These functions match the methods on Activity, described at
// http://developer.android.com/reference/android/app/Activity.html
@ -153,23 +152,3 @@ void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_
onCreate(activity);
}
// Runtime entry point when embedding Go in a Java App.
JNIEXPORT void JNICALL
Java_go_Go_run(JNIEnv* env, jclass clazz, jobject ctx) {
current_ctx = (*env)->NewGlobalRef(env, ctx);
if (current_ctx != NULL) {
// Init asset_manager.
jclass context_clazz = find_class(env, "android/content/Context");
jmethodID getassets = find_method(
env, context_clazz, "getAssets", "()Landroid/content/res/AssetManager;");
// Prevent the java AssetManager from being GC'd
jobject asset_manager_ref = (*env)->NewGlobalRef(
env, (*env)->CallObjectMethod(env, current_ctx, getassets));
asset_manager = AAssetManager_fromJava(env, asset_manager_ref);
}
call_main_and_wait();
}

View File

@ -14,11 +14,9 @@ until this is complete. Next JNI_OnLoad is called. When that is
complete, one of two entry points is called.
All-Go apps built using NativeActivity enter at ANativeActivity_onCreate.
Go libraries, such as those built with gomobild bind, enter from Java at
Java_go_Go_run.
Both entry points make a cgo call that calls the Go main and blocks
until app.Run is called.
Go libraries (for example, those built with gomobile bind) do not use
the app package initialization.
*/
package app
@ -49,9 +47,6 @@ jobject current_ctx;
jclass app_find_class(JNIEnv* env, const char* name);
// current_native_activity is the Android ANativeActivity. May be NULL.
ANativeActivity* current_native_activity;
// asset_manager is the asset manager of the app.
// For all-Go app, this is initialized in onCreate.
// For go library app, this is set from the context passed to Go.run.
@ -291,10 +286,6 @@ func main(f func(App)) {
close(donec)
}()
if C.current_native_activity == nil {
<-donec
return
}
for w := range windowCreated {
if windowDraw(w, queue, donec) {
return

View File

@ -14,6 +14,13 @@ import java.util.concurrent.Executors;
// Seq is a sequence of machine-dependent encoded values.
// Used by automatically generated language bindings to talk to Go.
public class Seq {
static {
initSeq();
new Thread("GoSeq") {
public void run() { Seq.receive(); }
}.start();
}
@SuppressWarnings("UnusedDeclaration")
private long memptr; // holds C-allocated pointer
@ -67,10 +74,6 @@ public class Seq {
return tracker.get(refnum);
}
static {
initSeq();
}
static native void initSeq();
// Informs the Go ref tracker that Java is done with this ref.

View File

@ -15,7 +15,7 @@ import go.testpkg.Testpkg;
public class SeqTest extends AndroidTestCase {
public SeqTest() {
Go.init(this.getContext());
System.loadLibrary("gojni");
}
public void testAdd() {

View File

@ -8,11 +8,3 @@
//
// Currently, this works only for android.
package java
// Init initializes communication with Java.
// Typically called from the Start callback in app.Run.
func Init() {
close(running)
}
var running = make(chan struct{})

View File

@ -25,7 +25,6 @@ const debug = false
// Send is called by Java to send a request to run a Go function.
//export Send
func Send(descriptor string, code int, req *C.uint8_t, reqlen C.size_t, res **C.uint8_t, reslen *C.size_t) {
<-running
fn := seq.Registry[descriptor][code]
if fn == nil {
panic(fmt.Sprintf("invalid descriptor(%s) and code(0x%x)", descriptor, code))

View File

@ -150,15 +150,8 @@ func runBind(cmd *command) error {
return err
}
src := filepath.Join(repo, "app/Go.java")
dst := filepath.Join(androidDir, "src/main/java/go/Go.java")
rm(dst)
if err := symlink(src, dst); err != nil {
return err
}
src = filepath.Join(repo, "bind/java/Seq.java")
dst = filepath.Join(androidDir, "src/main/java/go/Seq.java")
src := filepath.Join(repo, "bind/java/Seq.java")
dst := filepath.Join(androidDir, "src/main/java/go/Seq.java")
rm(dst)
if err := symlink(src, dst); err != nil {
return err
@ -292,15 +285,11 @@ var androidMainTmpl = template.Must(template.New("android.go").Parse(`
package main
import (
"golang.org/x/mobile/app"
"golang.org/x/mobile/bind/java"
_ "golang.org/x/mobile/bind/java"
_ "{{.}}"
)
func main() {
app.Run(app.Callbacks{Start: java.Init})
}
func main() {}
`))
// AAR is the format for the binary distribution of an Android Library Project

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2014 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hello"
android:versionCode="1"
android:versionName="1.0">
<application android:label="Hello">
<activity android:name="com.example.hello.MainActivity"
android:label="Hello"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,42 +0,0 @@
The libhello app demonstrates calling Go code from a primarily Java app.
Starting in Java lets you program against Android's extensive UI
libraries in their native language and call into Go for library code
(business logic, code shared with a Go server, portable code).
The Java entry point to the program is the file
src/com/example/hello/MainActivity.java, where the statement
Hi.Hello("world");
is a call into Go code.
The Go code is in a package called hi, the file is hi/hi.go, and it
contains the function Hello:
func Hello(name string) {
fmt.Printf("Hello, %s!\n", name)
}
Java language bindings are generated for this package using the gobind
tool. There is a user guide for gobind at
http://golang.org/x/mobile/cmd/gobind
The generated source has been included in the distribution. If you
modify the exported interface of package hi, you have to run gobind
manually before calling all.bash.
Along with the gobind generated source, the app includes a main.go file
to define the app entry point.
make.bash builds the app, all.bash deploys it.
The first step in building the app is to build the native shared
library out of the Go code, and place it in
libs/armeabi-v7a/libgojni.so.
The second step is building the app with the standard Android build
system by calling ant debug (also done in make.bash). Two extra Java
files are included in the build by make.bash to support the language
bindings. This produces an apk ready for running on a device.

View File

@ -1,15 +0,0 @@
#!/usr/bin/env bash
# Copyright 2014 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# Script to build and launch the app on an android device.
set -e
./make.bash
adb install -r bin/Hello-debug.apk
adb shell am start -a android.intent.action.MAIN \
-n com.example.hello/com.example.hello.MainActivity

View File

@ -1,16 +0,0 @@
:: Copyright 2014 The Go Authors. All rights reserved.
:: Use of this source code is governed by a BSD-style
:: license that can be found in the LICENSE file.
@echo off
setlocal
echo # building libhello
call make.bat
echo # installing bin/Hello-debug.apk
adb install -r bin/Hello-debug.apk >nul
echo # starting com.example.hello.MainActivity
adb shell am start -a android.intent.action.MAIN -n com.example.hello/com.example.hello.MainActivity >nul

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2014 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<project name="Hello" default="help">
<property name="target" value="android-19" />
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<fail message="missing ANDROID_HOME env variable" unless="sdk.dir" />
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -1,19 +0,0 @@
// Package go_hi is an autogenerated binder stub for package hi.
// gobind -lang=go golang.org/x/mobile/example/libhello/hi
//
// File is generated by gobind. Do not edit.
package go_hi
import (
"golang.org/x/mobile/bind/seq"
"golang.org/x/mobile/example/libhello/hi"
)
func proxy_Hello(out, in *seq.Buffer) {
param_name := in.ReadUTF16()
hi.Hello(param_name)
}
func init() {
seq.Register("hi", 1, proxy_Hello)
}

View File

@ -1,8 +0,0 @@
// Package hi provides a function for saying hello.
package hi
import "fmt"
func Hello(name string) {
fmt.Printf("Hello, %s!\n", name)
}

View File

@ -1,20 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This is the Go entry point for the libhello app.
// It is invoked from Java.
//
// See README for details.
package main
import (
"golang.org/x/mobile/app"
"golang.org/x/mobile/bind/java"
_ "golang.org/x/mobile/example/libhello/hi/go_hi"
)
func main() {
app.Run(app.Callbacks{Start: java.Init})
}

View File

@ -1,20 +0,0 @@
#!/usr/bin/env bash
# Copyright 2014 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
set -e
if [ ! -f make.bash ]; then
echo 'make.bash must be run from $GOPATH/src/golang.org/x/mobile/example/libhello'
exit 1
fi
mkdir -p libs/armeabi-v7a src/go/hi
ANDROID_APP=$PWD
(cd ../.. && ln -sf $PWD/app/*.java $ANDROID_APP/src/go)
(cd ../.. && ln -sf $PWD/bind/java/Seq.java $ANDROID_APP/src/go)
CGO_ENABLED=1 GOOS=android GOARCH=arm GOARM=7 \
go build -ldflags="-shared" .
mv -f libhello libs/armeabi-v7a/libgojni.so
ant debug

View File

@ -1,46 +0,0 @@
:: Copyright 2014 The Go Authors. All rights reserved.
:: Use of this source code is governed by a BSD-style
:: license that can be found in the LICENSE file.
@echo off
setlocal
if not exist make.bat goto error-invalid-path
:go-build
if not exist libs\armeabi-v7a mkdir libs\armeabi-v7a
if not exist src\go\hi mkdir src\go\hi
if not exist jni\armeabi mkdir jni\armeabi
set CGO_ENABLED=1
set GOOS=android
set GOARCH=arm
set GOARM=7
set ANDROID_APP=%CD%
xcopy /y ..\..\app\*.java %ANDROID_APP%\src\go >nul
copy /y ..\..\bind\java\Seq.java %ANDROID_APP%\src\go\Seq.java >nul
go build -ldflags="-shared" .
if errorlevel 1 goto error-go-build
move /y libhello libs\armeabi-v7a\libgojni.so >nul
if defined ANT_HOME goto ant-build
echo ANT_HOME path not defined
goto end
:ant-build
call %ANT_HOME%\bin\ant.bat debug >nul
goto end
:error-invalid-path
echo make.bat must be run from example\libhello
goto end
:error-go-build
echo Error building go lib
goto end
:end

View File

@ -1,29 +0,0 @@
/*
* Copyright 2014 The Go 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 com.example.hello;
import go.Go;
import go.hi.Hi;
import android.app.Activity;
import android.os.Bundle;
/*
* MainActivity is the entry point for the libhello app.
*
* From here, the Go runtime is initialized and a Go function is
* invoked via gobind language bindings.
*
* See example/libhello/README for details.
*/
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Go.init(getApplicationContext());
Hi.Hello("world");
}
}

View File

@ -1,20 +0,0 @@
// Java Package hi is a proxy for talking to a Go program.
//
// File is generated by gobind. Do not edit.
package go.hi;
import go.Seq;
public abstract class Hi {
private Hi() {} // uninstantiable
public static void Hello(String name) {
go.Seq _in = new go.Seq();
go.Seq _out = new go.Seq();
_in.writeUTF16(name);
Seq.send(DESCRIPTOR, CALL_Hello, _in, _out);
}
private static final int CALL_Hello = 1;
private static final String DESCRIPTOR = "hi";
}

View File

@ -1,9 +0,0 @@
// Copyright 2014 The Go 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 demo;
public class Demo {
public static native void hello(String name);
}

View File

@ -1,27 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build android
// See main.go for commentary.
#include <android/log.h>
#include <jni.h>
#include <limits.h>
#include "_cgo_export.h"
JNIEXPORT void JNICALL
Java_demo_Demo_hello(JNIEnv* env, jclass clazz, jstring jname) {
// Turn Java's UTF16 string into (almost) UTF8.
const char *name = (*env)->GetStringUTFChars(env, jname, 0);
GoString go_name;
go_name.p = (char*)name;
go_name.n = (*env)->GetStringUTFLength(env, jname);
// Call into Go.
LogHello(go_name);
(*env)->ReleaseStringUTFChars(env, jname, name);
}

View File

@ -1,27 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build android
package main
// #cgo LDFLAGS: -llog
// #include <android/log.h>
// #include <string.h>
import "C"
import (
"fmt"
"unsafe"
)
//export LogHello
func LogHello(name string) {
fmt.Printf("Hello, %s!\n", name)
ctag := C.CString("Go")
cstr := C.CString(fmt.Sprintf("Printing hello message for %q", name))
C.__android_log_write(C.ANDROID_LOG_INFO, ctag, cstr)
C.free(unsafe.Pointer(ctag))
C.free(unsafe.Pointer(cstr))
}

View File

@ -1,30 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
This example program compiles to a gojni.so shared library, that can
be loaded from an android application. Build it by configuring a cross
compiler (see go.mobile/README) and then running:
ANDROID_APP=/path/to/Myapp/app ./make.bash
This program expects app/Go.java to be included in the Android
project, along with a Java class named Demo defining
public static native void hello();
calling hello prints "Hello, world!" to logcat.
This is a very early example program that does not represent the
intended development model for Go on Android. A language binding
generator will follow, as will gradle build system integration.
The result will be no make.bash, and no need to write C.
*/
package main
import "golang.org/x/mobile/app"
func main() {
app.Run(app.Callbacks{})
}

View File

@ -1,27 +0,0 @@
#!/usr/bin/env bash
# Copyright 2014 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# See main.go for commentary.
set -e
if [ ! -f make.bash ]; then
echo 'make.bash must be run from $GOPATH/src/golang.org/x/mobile/example/libhellojni'
exit 1
fi
if [ -z "$ANDROID_APP" ]; then
echo 'ERROR: Environment variable ANDROID_APP is unset.'
exit 1
fi
mkdir -p $ANDROID_APP/src/main/jniLibs/armeabi \
$ANDROID_APP/src/main/java/go \
$ANDROID_APP/src/main/java/demo
(cd ../.. && ln -sf $PWD/app/*.java $ANDROID_APP/src/main/java/go)
(cd ../.. && ln -sf $PWD/bind/java/*.java $ANDROID_APP/src/main/java/go)
ln -sf $PWD/*.java $ANDROID_APP/src/main/java/demo
CGO_ENABLED=1 GOOS=android GOARCH=arm GOARM=7 \
go build -ldflags="-shared" .
mv libhellojni $ANDROID_APP/src/main/jniLibs/armeabi/libgojni.so

View File

@ -1,39 +0,0 @@
:: Copyright 2014 The Go Authors. All rights reserved.
:: Use of this source code is governed by a BSD-style
:: license that can be found in the LICENSE file.
@echo off
setlocal
if not exist make.bat goto error-invalid-path
set CGO_ENABLED=1
set GOOS=android
set GOARCH=arm
set GOARM=7
set ANDROID_APP=%CD%
if not exist src\main\jniLibs\armeabi mkdir src\main\jniLibs\armeabi
if not exist src\main\java\go mkdir src\main\java\go
if not exist src\main\java\demo mkdir src\main\java\demo
xcopy /y ..\..\app\*.java %ANDROID_APP%\src\main\java\go >nul
xcopy /y ..\..\bind\java\*.java %ANDROID_APP%\src\main\java\go >nul
xcopy /y %CD%\*.java %ANDROID_APP%\src\main\java\demo >nul
go build -ldflags="-shared" .
if errorlevel 1 goto error-go-build
move /y libhellojni %ANDROID_APP%\src\main\jniLibs\armeabi\libgojni.so >nul
goto end
:error-invalid-path
echo make.bat must be run from example\libhellojni
goto end
:error-go-build
echo Error building go lib
goto end
:end