Commit 64b329bc authored by Ryan Pavlik's avatar Ryan Pavlik

A little bit more implementation, a lot more documentation.

parent c1f64f96
Pipeline #199531 passed with stages
in 3 minutes and 31 seconds
......@@ -15,41 +15,133 @@ 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;
public void bind(Context context) {
/**
* @todo how to get the right package here? Do we have to go so far as to re-enumerate ourselves?
*/
/**
* 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("org.freedesktop.monado.openxr.out_of_process"),
.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.
*/
}
......@@ -16,6 +16,11 @@ 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 {
......@@ -28,15 +33,40 @@ public class MonadoImpl extends IMonado.Stub {
}
/**
* 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");
}
}
......@@ -15,6 +15,11 @@ 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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment