E.g. instead of:
class Foo {
private static native int bar();
}
Do:
class Foo {
@Natives
interface Natives {
int bar();
}
}
Some details here still TBD.
Primary goal: Allow JNI to be mocked in robolectric tests
Secondary goal: Obfuscate JNI symbols for small binary size savings.
More details in Googler-only doc: https://goto.google.com/mockable-jni
============= For Static JNI that has no mNativePointer ==========
public interface org.chromium.base.JniStaticTestMocker<T> {
void setInstanceForTesting(T instance);
}
final class ExampleUtils_NativesJni {
// ... Existing methods as above, plus:
private static ExampleUtils_NativesJni sTestInstance;
public static final JniStaticTestMocker<Natives> TEST_HOOKS = new JniTestMocker<> {
public void setInstanceForTesting(Natives instance) {
sTestInstance = instance;
}
};
static Natives get() {
if (GEN_JNI.IS_TESTING_ENABLED && sTestInstance != null) {
return sTestInstance;
}
return new ExampleUtils_NativesJni();
}
}
Generated code:
// All native methods declared here so that we don't have to mark
// ExampleUtils_NativesJni as -keep.
public final class GEN_JNI {
public static boolean IS_TESTING_ENABLED;
public static final native boolean ExampleUtils_NativesJni_someMethod(String value);
}
final class ExampleUtils_NativesJni {
private boolean someMethod(String value) {
return GEN_JNI.ExampleUtils_NativesJni_someMethod(value);
}
static Natives get() {
return new ExampleUtils_NativesJni();
}
}
Sample Test:
class MyTest {
// Rule will reset mocks back to null in tearDown().
@Rule JniMocker mocker = new JniMocker();
@Mock ExampleUtils.Natives mock1;
@SetUp
public void setUp() {
mocker.mock(ExampleUtils_NativesJni.TEST_HOOKS, mock1);
}
}
============= For Non-static JNI that has no mNativePointer ==========
Still TBD. Right now there seems to be no design that r8 can fully optimize away the overhead.
Comment 1 by bugdroid1@chromium.org
, Oct 23