mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-16 03:45:24 +00:00
ipc_android: Add Android-specific Java/AIDL code
This commit is contained in:
parent
d0187cee9a
commit
d6564e3798
|
@ -3,4 +3,5 @@
|
|||
|
||||
rootProject.name = 'monado'
|
||||
|
||||
include ":src:xrt:auxiliary:android"
|
||||
include ':src:xrt:auxiliary:android'
|
||||
include ':src:xrt:ipc_android'
|
||||
|
|
33
src/xrt/ipc_android/build.gradle
Normal file
33
src/xrt/ipc_android/build.gradle
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion project.sharedTargetSdk
|
||||
buildToolsVersion '30.0.2'
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
targetSdkVersion project.sharedTargetSdk
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
// Gradle plugin produces proguard-android-optimize.txt from @Keep annotations
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':src:xrt:auxiliary:android')
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.annotation:annotation:1.1.0'
|
||||
}
|
4
src/xrt/ipc_android/proguard-rules.pro
vendored
Normal file
4
src/xrt/ipc_android/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Copyright 2020, Collabora, Ltd.
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# see http://developer.android.com/guide/developing/tools/proguard.html
|
||||
# Trying to keep most of them in source code annotations and let Gradle do the work
|
14
src/xrt/ipc_android/src/main/AndroidManifest.xml
Normal file
14
src/xrt/ipc_android/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.freedesktop.monado.ipc">
|
||||
<!--
|
||||
Copyright 2020, Collabora, Ltd.
|
||||
SPDX-License-Identifier: BSL-1.0
|
||||
-->
|
||||
<application>
|
||||
<service android:name=".MonadoService">
|
||||
<intent-filter>
|
||||
<action android:name="org.freedesktop.monado.CONNECT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
</manifest>
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Interface to bootstrap the Monado IPC connection.
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @ingroup aux_android_java
|
||||
*/
|
||||
|
||||
package org.freedesktop.monado.ipc;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.view.Surface;
|
||||
|
||||
interface IMonado {
|
||||
/*!
|
||||
* Pass one side of the socket pair to the service to set up the IPC.
|
||||
*/
|
||||
void connect(in ParcelFileDescriptor parcelFileDescriptor);
|
||||
|
||||
/*!
|
||||
* Provide the surface we inject into the activity, back to the service.
|
||||
*/
|
||||
void passAppSurface(in Surface surface);
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Implementation of the Monado AIDL server
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
*/
|
||||
|
||||
|
||||
package org.freedesktop.monado.ipc;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Provides the client-side code to initiate connection to Monado IPC service.
|
||||
* <p>
|
||||
* This class will get loaded into the OpenXR client application by our native code.
|
||||
*/
|
||||
@Keep
|
||||
public class Client implements ServiceConnection {
|
||||
private static final String TAG = "monado-ipc-client";
|
||||
|
||||
/**
|
||||
* Context provided by app.
|
||||
*/
|
||||
private Context context;
|
||||
|
||||
/**
|
||||
* Pointer to local IPC proxy: calling methods on it automatically transports arguments across binder IPC.
|
||||
* <p>
|
||||
* May be null!
|
||||
*/
|
||||
public IMonado monado;
|
||||
|
||||
/**
|
||||
* "Our" side of the socket pair - the other side is sent to the server automatically on connection.
|
||||
*/
|
||||
public ParcelFileDescriptor fd;
|
||||
|
||||
/**
|
||||
* Indicates that we tried to connect but failed.
|
||||
* <p>
|
||||
* Used to distinguish a "not yet fully connected" null monado member from a "tried and failed"
|
||||
* null monado member.
|
||||
*/
|
||||
public boolean failed = false;
|
||||
|
||||
/**
|
||||
* Bind to the Monado IPC service - this asynchronously starts connecting (and launching the
|
||||
* service if it's not already running)
|
||||
* <p>
|
||||
* The IPC client code on Android should load this class (from the right package), instantiate
|
||||
* this class, and call this method.
|
||||
*
|
||||
* @param context_ Context to use to make the connection. (We get the application context
|
||||
* from it.)
|
||||
* @param packageName The package name containing the Monado runtime. The caller is guaranteed
|
||||
* to know this because it had to load this class from that package.
|
||||
* (Often "org.freedesktop.monado.openxr.out_of_process" for now, at least)
|
||||
* @todo how to get the right package name here? Do we have to go so far as to re-enumerate ourselves?
|
||||
* <p>
|
||||
* Various builds, variants, etc. will have different package names, but we must specify the
|
||||
* package name explicitly to avoid violating security restrictions.
|
||||
*/
|
||||
public void bind(Context context_, String packageName) {
|
||||
context = context_.getApplicationContext();
|
||||
if (context == null) {
|
||||
// in case app context returned null
|
||||
context = context_;
|
||||
}
|
||||
context.bindService(
|
||||
new Intent("org.freedesktop.monado.CONNECT")
|
||||
.setPackage(packageName),
|
||||
this, Context.BIND_AUTO_CREATE);
|
||||
// does not bind right away! This takes some time.
|
||||
}
|
||||
|
||||
/**
|
||||
* Some on-failure cleanup.
|
||||
*/
|
||||
private void handleFailure() {
|
||||
failed = true;
|
||||
if (context != null) context.unbindService(this);
|
||||
monado = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the asynchronous connection of the binder IPC.
|
||||
* <p>
|
||||
* This sets up the class member `monado`, as well as the member `fd`. It calls
|
||||
* `IMonado.connect()` automatically. The client still needs to call `IMonado.passAppSurface()`
|
||||
* on `monado`.
|
||||
*
|
||||
* @param name should match the intent above, but not used.
|
||||
* @param service the associated service, which we cast in this function.
|
||||
*/
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
monado = IMonado.Stub.asInterface(service);
|
||||
ParcelFileDescriptor theirs;
|
||||
try {
|
||||
ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair();
|
||||
fd = fds[0];
|
||||
theirs = fds[1];
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "could not create socket pair: " + e.toString());
|
||||
handleFailure();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
monado.connect(theirs);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "could not call IMonado.connect: " + e.toString());
|
||||
handleFailure();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle asynchronous disconnect.
|
||||
*
|
||||
* @param name should match the intent above, but not used.
|
||||
*/
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
monado = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @todo do we need to watch for a disconnect here?
|
||||
* https://stackoverflow.com/questions/18078914/notify-an-android-service-when-a-bound-client-disconnects
|
||||
*
|
||||
* Our existing native disconnect handling might be sufficient.
|
||||
*/
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Implementation of the Monado AIDL server
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
*/
|
||||
|
||||
|
||||
package org.freedesktop.monado.ipc;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.view.Surface;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import org.freedesktop.monado.ipc.IMonado.Stub;
|
||||
|
||||
/**
|
||||
* Java implementation of the IMonado IPC interface.
|
||||
*
|
||||
* All this does is delegate calls to native JNI implementations
|
||||
*/
|
||||
@Keep
|
||||
public class MonadoImpl extends IMonado.Stub {
|
||||
|
||||
public void connect(ParcelFileDescriptor parcelFileDescriptor) {
|
||||
nativeAddClient(parcelFileDescriptor);
|
||||
}
|
||||
|
||||
public void passAppSurface(Surface surface) {
|
||||
nativeAppSurface(surface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Native handling of receiving a surface: should convert it to an ANativeWindow then do stuff
|
||||
* with it.
|
||||
*
|
||||
* Ignore Android Studio complaining that this function is missing: it is not, it is just in a
|
||||
* different module. See `src/xrt/targets/service-lib/lib.cpp` for the implementation.
|
||||
* (Ignore the warning saying that file isn't included in the build: it is, Android Studio
|
||||
* is just confused.)
|
||||
*
|
||||
* @param surface
|
||||
* @todo figure out a good way to make the MonadoImpl pointer a client ID
|
||||
*/
|
||||
private native void nativeAppSurface(Surface surface);
|
||||
|
||||
/**
|
||||
* Native handling of receiving an FD for a new client: the FD should be used to start up the
|
||||
* rest of the native IPC code on that socket.
|
||||
*
|
||||
* This is essentially the entry point for the monado service on Android: if it's already
|
||||
* running, this will be called in it. If it's not already running, a process will be created,
|
||||
* and this will be the first native code executed in that process.
|
||||
*
|
||||
* Ignore Android Studio complaining that this function is missing: it is not, it is just in a
|
||||
* different module. See `src/xrt/targets/service-lib/lib.cpp` for the implementation.
|
||||
* (Ignore the warning saying that file isn't included in the build: it is, Android Studio
|
||||
* is just confused.)
|
||||
*
|
||||
* @param surface
|
||||
* @todo figure out a good way to make the MonadoImpl pointer a client ID
|
||||
*/
|
||||
private native void nativeAddClient(ParcelFileDescriptor parcelFileDescriptor);
|
||||
|
||||
static {
|
||||
// Load the shared library with the native parts of this class
|
||||
// This is the service-lib target.
|
||||
System.loadLibrary("monado-service");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Service implementation for exposing IMonado.
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
*/
|
||||
|
||||
|
||||
package org.freedesktop.monado.ipc;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Minimal implementation of a Service.
|
||||
*
|
||||
* This is needed so that the APK can expose the binder service implemented in MonadoImpl.
|
||||
*/
|
||||
public class MonadoService extends Service {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return new MonadoImpl();
|
||||
}
|
||||
|
||||
}
|
3
src/xrt/ipc_android/src/main/res/values/strings.xml
Normal file
3
src/xrt/ipc_android/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
</resources>
|
Loading…
Reference in a new issue