blob: ccd268dfc2349887af61a936f194572cf0543346 [file] [log] [blame]
// Copyright 2015 The Vanadium 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 io.v.android.v23;
import android.content.Context;
import io.v.v23.Options;
import io.v.v23.context.VContext;
import io.v.v23.security.Blessings;
import io.v.v23.security.BlessingStore;
import io.v.v23.security.Constants;
import io.v.v23.security.VPrincipal;
import io.v.v23.security.VSecurity;
import io.v.v23.security.VSigner;
import io.v.v23.verror.VException;
import java.security.KeyStore;
import java.security.interfaces.ECPublicKey;
/**
* The local android environment allowing clients and servers to communicate with one another.
* The expected usage pattern of this class goes something like this:
* <p><blockquote><pre>
* final VContext ctx = V.init(getApplicationContext(), opts);
* ...
* final Server s = V.newServer(ctx);
* ...
* final Client c = V.getClient(ctx);
* ...
* </pre></blockquote><p>
* This class is a convenience wrapper for android users. It provides Android-related setup
* and then delegates to the Java {@link io.v.v23.V} methods.
*/
public class V extends io.v.v23.V {
private static volatile VContext context = null;
/**
* Initializes the Vanadium environment, returning the base context. Calling this method
* multiple times will always return the result of the first call to {@link #init init},
* ignoring subsequently provided options.
* <p>
* A caller may pass the following option that specifies the runtime implementation to be used:
* <p><ul>
* <li>{@link io.v.v23.OptionDefs#RUNTIME}</li>
* </ul><p>
* <p>
* If this option isn't provided, the default runtime implementation is used.
*
* @param androidCtx Android application context
* @param opts options for the default runtime
* @return base context
*/
public static VContext init(Context androidCtx, Options opts) {
if (context != null) return context;
synchronized (V.class) {
if (context != null) return context;
if (androidCtx == null) {
throw new RuntimeException("Android context must be non-null.");
}
context = io.v.v23.V.init(opts);
RedirectStderr.Start();
// Attach principal and listen spec to the context.
try {
context = V.withPrincipal(context, createPrincipal(androidCtx));
} catch (VException e) {
throw new RuntimeException("Couldn't setup Vanadium Runtime options", e);
}
// Set the VException component name to the Android context package name.
context = VException.contextWithComponentName(context, androidCtx.getPackageName());
return context;
}
}
/**
* Initializes the Vanadium environment without options. See
* {@link #init(Context,Options)} for more information.
*
* @return base context
*/
public static VContext init(Context ctx) {
return V.init(ctx, null);
}
private static VPrincipal createPrincipal(Context ctx) throws VException {
// Check if the private key has already been generated for this package.
// (NOTE: Android package names are unique.)
KeyStore.PrivateKeyEntry keyEntry =
KeyStoreUtil.getKeyStorePrivateKey(ctx.getPackageName());
if (keyEntry == null) {
// Generate a new private key.
keyEntry = KeyStoreUtil.genKeyStorePrivateKey(ctx, ctx.getPackageName());
}
VSigner signer = VSecurity.newSigner(
keyEntry.getPrivateKey(), (ECPublicKey)keyEntry.getCertificate().getPublicKey());
VPrincipal principal =
VSecurity.newPersistentPrincipal(signer, ctx.getFilesDir().getAbsolutePath());
// Make sure we have at least one (i.e., self-signed) blessing in the store.
BlessingStore store = principal.blessingStore();
if (store.peerBlessings().isEmpty()) {
Blessings self = principal.blessSelf(ctx.getPackageName());
store.setDefaultBlessings(self);
store.set(self, Constants.ALL_PRINCIPALS);
VSecurity.addToRoots(principal, self);
}
return principal;
}
private V() {}
}