/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.commands.hidl_test_java; import android.hidl.manager.V1_0.IServiceManager; import android.hardware.tests.baz.V1_0.IBase; import android.hardware.tests.baz.V1_0.IBaz; import android.hardware.tests.baz.V1_0.IQuux; import android.hardware.tests.baz.V1_0.IBaz.NestedStruct; import android.hardware.tests.baz.V1_0.IBazCallback; import android.os.HwBinder; import android.os.RemoteException; import android.os.HidlSupport; import android.util.Log; import java.util.ArrayList; import java.util.Arrays; import java.util.NoSuchElementException; import java.util.Objects; public final class HidlTestJava { private static final String TAG = "HidlTestJava"; public static void main(String[] args) { int exitCode = 1; try { exitCode = new HidlTestJava().run(args); } catch (Exception e) { e.printStackTrace(); Log.e(TAG, "Error ", e); } System.exit(exitCode); } public int run(String[] args) throws RemoteException { if (args[0].equals("-c")) { client(); } else if (args[0].equals("-s")) { server(); } else { Log.e(TAG, "Usage: HidlTestJava -c(lient) | -s(erver)"); System.err.printf("Usage: HidlTestJava -c(lient) | -s(erver)\n"); return 1; } return 0; } final class HidlDeathRecipient implements HwBinder.DeathRecipient { final Object mLock = new Object(); boolean mCalled = false; long mCookie = 0; @Override public void serviceDied(long cookie) { synchronized (mLock) { mCalled = true; mCookie = cookie; mLock.notify(); } } public boolean cookieMatches(long cookie) { synchronized (mLock) { return mCookie == cookie; } } public boolean waitUntilServiceDied(long timeoutMillis) { synchronized(mLock) { while (!mCalled) { try { mLock.wait(timeoutMillis); } catch (InterruptedException e) { continue; // Spin for another loop } break; // got notified or timeout hit } return mCalled; } } }; private void ExpectTrue(boolean x) { if (x) { return; } throw new RuntimeException(); } private void ExpectFalse(boolean x) { ExpectTrue(!x); } private void Expect(String result, String s) { if (result.equals(s)) { return; } System.err.printf("Expected '%s', got '%s'\n", s, result); Log.e(TAG, "Expected '" + s + "', got '" + result + "'"); throw new RuntimeException(); } // .equals and HidlSupport.interfacesEqual should have the same behavior. private void ExpectEqual(android.hidl.base.V1_0.IBase l, android.hidl.base.V1_0.IBase r) { ExpectTrue(Objects.equals(l, r)); ExpectTrue(Objects.equals(r, l)); ExpectTrue(HidlSupport.interfacesEqual(l, r)); ExpectTrue(HidlSupport.interfacesEqual(r, l)); } private void ExpectNotEqual(android.hidl.base.V1_0.IBase l, android.hidl.base.V1_0.IBase r) { ExpectFalse(Objects.equals(l, r)); ExpectFalse(Objects.equals(r, l)); ExpectFalse(HidlSupport.interfacesEqual(l, r)); ExpectFalse(HidlSupport.interfacesEqual(r, l)); } class BazCallback extends IBazCallback.Stub { private boolean mCalled; public BazCallback() { mCalled = false; } boolean wasCalled() { return mCalled; } public void heyItsMe(IBazCallback cb) throws RemoteException { mCalled = true; cb.heyItsMe(null); } public void hey() { mCalled = true; } @Override public boolean equals(Object other) { return other != null && other.getClass() == BazCallback.class && ((BazCallback) other).mCalled == mCalled; } @Override public int hashCode() { return mCalled ? 1 : 0; } } private String numberToEnglish(int x) { final String[] kDigits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", }; if (x < 0) { return "negative " + numberToEnglish(-x); } if (x < 10) { return kDigits[x]; } if (x <= 15) { final String[] kSpecialTens = { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", }; return kSpecialTens[x - 10]; } if (x < 20) { return kDigits[x % 10] + "teen"; } if (x < 100) { final String[] kDecades = { "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety", }; return kDecades[x / 10 - 2] + kDigits[x % 10]; } return "positively huge!"; } private void ExpectDeepEq(Object l, Object r) { ExpectTrue(HidlSupport.deepEquals(l, r)); ExpectTrue(HidlSupport.deepHashCode(l) == HidlSupport.deepHashCode(r)); } private void ExpectDeepNe(Object l, Object r) { ExpectTrue(!HidlSupport.deepEquals(l, r)); } private void client() throws RemoteException { ExpectDeepEq(null, null); ExpectDeepNe(null, new String()); ExpectDeepNe(new String(), null); ExpectDeepEq(new String(), new String()); ExpectDeepEq("hey", "hey"); ExpectDeepEq(new int[]{1,2}, new int[]{1,2}); ExpectDeepNe(new int[]{1,2}, new int[]{1,3}); ExpectDeepNe(new int[]{1,2}, new int[]{1,2,3}); ExpectDeepEq(new int[][]{{1,2},{3,4}}, new int[][]{{1,2},{3,4}}); ExpectDeepNe(new int[][]{{1,2},{3,4}}, new int[][]{{1,2},{3,5}}); ExpectDeepNe(new int[][]{{1,2},{3,4}}, new int[][]{{1,2,3},{4,5,6}}); ExpectDeepNe(new int[][]{{1,2},{3,4}}, new int[][]{{1,2},{3,4,5}}); ExpectDeepEq(new Integer[]{1,2}, new Integer[]{1,2}); ExpectDeepNe(new Integer[]{1,2}, new Integer[]{1,3}); ExpectDeepNe(new Integer[]{1,2}, new Integer[]{1,2,3}); ExpectDeepEq(new Integer[][]{{1,2},{3,4}}, new Integer[][]{{1,2},{3,4}}); ExpectDeepNe(new Integer[][]{{1,2},{3,4}}, new Integer[][]{{1,2},{3,5}}); ExpectDeepNe(new Integer[][]{{1,2},{3,4}}, new Integer[][]{{1,2,3},{4,5,6}}); ExpectDeepNe(new Integer[][]{{1,2},{3,4}}, new Integer[][]{{1,2},{3,4,5}}); ExpectDeepEq(new ArrayList(Arrays.asList(1, 2)), new ArrayList(Arrays.asList(1, 2))); ExpectDeepNe(new ArrayList(Arrays.asList(1, 2)), new ArrayList(Arrays.asList(1, 2, 3))); ExpectDeepEq(new ArrayList(Arrays.asList(new int[]{1,2}, new int[]{3,4})), new ArrayList(Arrays.asList(new int[]{1,2}, new int[]{3,4}))); ExpectDeepNe(new ArrayList(Arrays.asList(new int[]{1,2}, new int[]{3,4})), new ArrayList(Arrays.asList(new int[]{1,2}, new int[]{3,5}))); ExpectDeepEq(new ArrayList(Arrays.asList(new Integer[]{1,2}, new Integer[]{3,4})), new ArrayList(Arrays.asList(new Integer[]{1,2}, new Integer[]{3,4}))); ExpectDeepNe(new ArrayList(Arrays.asList(new Integer[]{1,2}, new Integer[]{3,4})), new ArrayList(Arrays.asList(new Integer[]{1,2}, new Integer[]{3,5}))); ExpectDeepEq(new ArrayList[]{new ArrayList(Arrays.asList(1,2)), new ArrayList(Arrays.asList(3,4))}, new ArrayList[]{new ArrayList(Arrays.asList(1,2)), new ArrayList(Arrays.asList(3,4))}); { // Test proper exceptions are thrown try { IBase proxy = IBase.getService("this-doesn't-exist"); } catch (Exception e) { ExpectTrue(e instanceof NoSuchElementException); } } { // Test access through base interface binder. IBase baseProxy = IBase.getService("baz"); baseProxy.someBaseMethod(); IBaz bazProxy = IBaz.castFrom(baseProxy); ExpectTrue(bazProxy != null); // IQuux is completely unrelated to IBase/IBaz, so the following // should fail, i.e. return null. IQuux quuxProxy = IQuux.castFrom(baseProxy); ExpectTrue(quuxProxy == null); } { // Test waiting API IBase baseProxyA = IBaz.getService("baz", true /* retry */); ExpectTrue(baseProxyA != null); IBase baseProxyB = IBaz.getService("baz", false /* retry */); ExpectTrue(baseProxyB != null); } IBaz proxy = IBaz.getService("baz"); proxy.someBaseMethod(); { Expect(proxy.interfaceDescriptor(), IBaz.kInterfaceName); } { IBase.Foo foo = new IBase.Foo(); foo.x = 1; for (int i = 0; i < 5; ++i) { IBase.Foo.Bar bar = new IBase.Foo.Bar(); bar.z = 1.0f + (float)i * 0.01f; bar.s = "Hello, world " + i; foo.aaa.add(bar); } foo.y.z = 3.14f; foo.y.s = "Lorem ipsum..."; IBase.Foo result = proxy.someOtherBaseMethod(foo); ExpectTrue(result.equals(foo)); } { IBase.Foo[] inputArray = new IBase.Foo[2]; IBase.Foo foo = new IBase.Foo(); foo.x = 1; for (int i = 0; i < 5; ++i) { IBase.Foo.Bar bar = new IBase.Foo.Bar(); bar.z = 1.0f + (float)i * 0.01f; bar.s = "Hello, world " + i; foo.aaa.add(bar); } foo.y.z = 3.14f; foo.y.s = "Lorem ipsum..."; inputArray[0] = foo; foo = new IBase.Foo(); foo.x = 2; for (int i = 0; i < 3; ++i) { IBase.Foo.Bar bar = new IBase.Foo.Bar(); bar.z = 2.0f - (float)i * 0.01f; bar.s = "Lorem ipsum " + i; foo.aaa.add(bar); } foo.y.z = 1.1414f; foo.y.s = "Et tu brute?"; inputArray[1] = foo; IBase.Foo[] expectedOutputArray = new IBase.Foo[2]; expectedOutputArray[0] = inputArray[1]; expectedOutputArray[1] = inputArray[0]; IBase.Foo[] outputArray = proxy.someMethodWithFooArrays(inputArray); ExpectTrue(java.util.Objects.deepEquals(outputArray, expectedOutputArray)); } { ArrayList inputVec = new ArrayList(); IBase.Foo foo = new IBase.Foo(); foo.x = 1; for (int i = 0; i < 5; ++i) { IBase.Foo.Bar bar = new IBase.Foo.Bar(); bar.z = 1.0f + (float)i * 0.01f; bar.s = "Hello, world " + i; foo.aaa.add(bar); } foo.y.z = 3.14f; foo.y.s = "Lorem ipsum..."; inputVec.add(foo); foo = new IBase.Foo(); foo.x = 2; for (int i = 0; i < 3; ++i) { IBase.Foo.Bar bar = new IBase.Foo.Bar(); bar.z = 2.0f - (float)i * 0.01f; bar.s = "Lorem ipsum " + i; foo.aaa.add(bar); } foo.y.z = 1.1414f; foo.y.s = "Et tu brute?"; inputVec.add(foo); ArrayList expectedOutputVec = new ArrayList(); expectedOutputVec.add(inputVec.get(1)); expectedOutputVec.add(inputVec.get(0)); ArrayList outputVec = proxy.someMethodWithFooVectors(inputVec); ExpectTrue(java.util.Objects.deepEquals(outputVec, expectedOutputVec)); } { IBase.VectorOfArray in = new IBase.VectorOfArray(); int k = 0; for (int i = 0; i < 3; ++i) { byte[] mac = new byte[6]; for (int j = 0; j < 6; ++j, ++k) { mac[j] = (byte)k; } in.addresses.add(mac); } IBase.VectorOfArray expectedOut = new IBase.VectorOfArray(); int n = in.addresses.size(); for (int i = 0; i < n; ++i) { expectedOut.addresses.add(in.addresses.get(n - 1 - i)); } IBase.VectorOfArray out = proxy.someMethodWithVectorOfArray(in); ExpectTrue(out.equals(expectedOut)); } { ArrayList in = new ArrayList(); int k = 0; for (int i = 0; i < 3; ++i) { byte[] mac = new byte[6]; for (int j = 0; j < 6; ++j, ++k) { mac[j] = (byte)k; } in.add(mac); } ArrayList expectedOut = new ArrayList(); int n = in.size(); for (int i = 0; i < n; ++i) { expectedOut.add(in.get(n - 1 - i)); } ArrayList out = proxy.someMethodTakingAVectorOfArray(in); ExpectTrue(out.size() == expectedOut.size()); for (int i = 0; i < n; ++i) { ExpectTrue(java.util.Objects.deepEquals(out.get(i), expectedOut.get(i))); } } { IBase.StringMatrix5x3 in = new IBase.StringMatrix5x3(); IBase.StringMatrix3x5 expectedOut = new IBase.StringMatrix3x5(); for (int i = 0; i < 5; ++i) { for (int j = 0; j < 3; ++j) { in.s[i][j] = numberToEnglish(3 * i + j + 1); expectedOut.s[j][i] = in.s[i][j]; } } IBase.StringMatrix3x5 out = proxy.transpose(in); // [[1 2 3] [4 5 6] [7 8 9] [10 11 12] [13 14 15]]^T // = [[1 4 7 10 13] [2 5 8 11 14] [3 6 9 12 15]] ExpectTrue(out.equals(expectedOut)); } { String[][] in = new String[5][3]; String[][] expectedOut = new String[3][5]; for (int i = 0; i < 5; ++i) { for (int j = 0; j < 3; ++j) { in[i][j] = numberToEnglish(3 * i + j + 1); expectedOut[j][i] = in[i][j]; } } String[][] out = proxy.transpose2(in); // [[1 2 3] [4 5 6] [7 8 9] [10 11 12] [13 14 15]]^T // = [[1 4 7 10 13] [2 5 8 11 14] [3 6 9 12 15]] ExpectTrue(java.util.Arrays.deepEquals(out, expectedOut)); } ExpectTrue(proxy.someBoolMethod(true) == false); { boolean[] someBoolArray = new boolean[3]; someBoolArray[0] = true; someBoolArray[1] = false; someBoolArray[2] = true; boolean[] resultArray = proxy.someBoolArrayMethod(someBoolArray); ExpectTrue(resultArray[0] == false); ExpectTrue(resultArray[1] == true); ExpectTrue(resultArray[2] == false); ArrayList someBoolVec = new ArrayList(); someBoolVec.add(true); someBoolVec.add(false); someBoolVec.add(true); ArrayList resultVec = proxy.someBoolVectorMethod(someBoolVec); ExpectTrue(resultVec.get(0) == false); ExpectTrue(resultVec.get(1) == true); ExpectTrue(resultVec.get(2) == false); } proxy.doThis(1.0f); ExpectTrue(proxy.doThatAndReturnSomething(1) == 666); ExpectTrue(proxy.doQuiteABit(1, 2L, 3.0f, 4.0) == 666.5); { int[] paramArray = new int[15]; int[] expectedOutArray = new int[32]; ArrayList paramVec = new ArrayList(); ArrayList expectedOutVec = new ArrayList(); for (int i = 0; i < paramArray.length; ++i) { paramArray[i] = i; paramVec.add(i); expectedOutArray[i] = 2 * i; expectedOutArray[15 + i] = i; expectedOutVec.add(2 * i); } expectedOutArray[30] = 1; expectedOutArray[31] = 2; int[] outArray = proxy.doSomethingElse(paramArray); ExpectTrue(java.util.Objects.deepEquals(outArray, expectedOutArray)); ArrayList outVec = proxy.mapThisVector(paramVec); java.util.Objects.equals(outVec, expectedOutVec); } Expect(proxy.doStuffAndReturnAString(), "Hello, world!"); BazCallback cb = new BazCallback(); ExpectTrue(!cb.wasCalled()); proxy.callMe(cb); ExpectTrue(cb.wasCalled()); ExpectTrue(proxy.useAnEnum(IBaz.SomeEnum.goober) == -64); { String[] stringArray = new String[3]; stringArray[0] = "one"; stringArray[1] = "two"; stringArray[2] = "three"; String[] expectedOutArray = new String[2]; expectedOutArray[0] = "Hello"; expectedOutArray[1] = "World"; String[] outArray = proxy.haveSomeStrings(stringArray); ExpectTrue(java.util.Arrays.deepEquals(outArray, expectedOutArray)); ArrayList stringVec = new ArrayList(); stringVec.add("one"); stringVec.add("two"); stringVec.add("three"); ArrayList expectedOutVec = new ArrayList(); expectedOutVec.add("Hello"); expectedOutVec.add("World"); ExpectTrue(expectedOutVec.equals(proxy.haveAStringVec(stringVec))); } proxy.returnABunchOfStrings( new IBaz.returnABunchOfStringsCallback() { @Override public void onValues(String a, String b, String c) { Expect(a, "Eins"); Expect(b, "Zwei"); Expect(c, "Drei"); } }); proxy.returnABunchOfStrings((a,b,c) -> Expect(a + b + c, "EinsZweiDrei")); proxy.callMeLater(new BazCallback()); System.gc(); proxy.iAmFreeNow(); { IBaz.T t1 = new IBaz.T(); IBaz.T t2 = new IBaz.T(); for (int i = 0; i < 5; i++) { for (int j = 0; j < 3; j++) { t1.matrix5x3[i][j] = t2.matrix5x3[i][j] = (i + 1) * (j + 1); } } ExpectTrue(t1.equals(t2)); ExpectTrue(t1.hashCode() == t2.hashCode()); t2.matrix5x3[4][2] = -60; ExpectTrue(!t1.equals(t2)); } ArrayList structs = proxy.getNestedStructs(); ExpectTrue(structs.size() == 5); ExpectTrue(structs.get(1).matrices.size() == 6); { IBaz.Everything e = new IBaz.Everything(); Expect(e.toString(), "{.number = 0, .anotherNumber = 0, .s = , " + ".vs = [], .multidimArray = [[null, null], [null, null]], " + ".sArray = [null, null, null], .anotherStruct = {.first = , .last = }, .bf = }"); e.s = "string!"; e.number = 127; e.anotherNumber = 100; e.vs.addAll(Arrays.asList("One", "Two", "Three")); for (int i = 0; i < e.multidimArray.length; i++) for (int j = 0; j < e.multidimArray[i].length; j++) e.multidimArray[i][j] = Integer.toString(i) + Integer.toString(j); e.bf = IBaz.BitField.VALL; e.anotherStruct.first = "James"; e.anotherStruct.last = "Bond"; Expect(e.toString(), "{.number = 127, .anotherNumber = 100, .s = string!, " + ".vs = [One, Two, Three], .multidimArray = [[00, 01], [10, 11]], " + ".sArray = [null, null, null], .anotherStruct = {.first = James, .last = Bond}, " + ".bf = V0 | V1 | V2 | V3 | VALL}"); Expect(IBaz.BitField.toString(IBaz.BitField.VALL), "VALL"); Expect(IBaz.BitField.toString((byte)(IBaz.BitField.V0 | IBaz.BitField.V2)), "0x5"); Expect(IBaz.BitField.dumpBitfield(IBaz.BitField.VALL), "V0 | V1 | V2 | V3 | VALL"); Expect(IBaz.BitField.dumpBitfield((byte)(IBaz.BitField.V1 | IBaz.BitField.V3 | 0xF0)), "V1 | V3 | 0xf0"); Expect(proxy.toString(), IBaz.kInterfaceName + "@Proxy"); } { // Ensure that native parcel is cleared even if the corresponding // Java object isn't GC'd. ArrayList data4K = new ArrayList<>(1024); for (int i = 0; i < 1024; i++) { data4K.add(i); } for (int i = 0; i < 1024; i++) { // If they are not properly cleaned up, these calls will put 4MB of data in // kernel binder buffer, and will fail. try { proxy.mapThisVector(data4K); } catch (RemoteException ex) { throw new RuntimeException("Failed at call #" + Integer.toString(i), ex); } } } { // TestArrays IBase.LotsOfPrimitiveArrays in = new IBase.LotsOfPrimitiveArrays(); for (int i = 0; i < 128; ++i) { in.byte1[i] = (byte)i; in.boolean1[i] = (i & 4) != 0; in.double1[i] = i; } int m = 0; for (int i = 0; i < 8; ++i) { for (int j = 0; j < 128; ++j, ++m) { in.byte2[i][j] = (byte)m; in.boolean2[i][j] = (m & 4) != 0; in.double2[i][j] = m; } } m = 0; for (int i = 0; i < 8; ++i) { for (int j = 0; j < 16; ++j) { for (int k = 0; k < 128; ++k, ++m) { in.byte3[i][j][k] = (byte)m; in.boolean3[i][j][k] = (m & 4) != 0; in.double3[i][j][k] = m; } } } IBase.LotsOfPrimitiveArrays out = proxy.testArrays(in); ExpectTrue(in.equals(out)); } { // testByteVecs ArrayList in = new ArrayList(); int k = 0; for (int i = 0; i < in.size(); ++i) { byte[] elem = new byte[128]; for (int j = 0; j < 128; ++j, ++k) { elem[j] = (byte)k; } in.add(elem); } ArrayList out = proxy.testByteVecs(in); ExpectTrue(in.equals(out)); } { // testBooleanVecs ArrayList in = new ArrayList(); int k = 0; for (int i = 0; i < in.size(); ++i) { boolean[] elem = new boolean[128]; for (int j = 0; j < 128; ++j, ++k) { elem[j] = (k & 4) != 0; } in.add(elem); } ArrayList out = proxy.testBooleanVecs(in); ExpectTrue(in.equals(out)); } { // testDoubleVecs ArrayList in = new ArrayList(); int k = 0; for (int i = 0; i < in.size(); ++i) { double[] elem = new double[128]; for (int j = 0; j < 128; ++j, ++k) { elem[j] = k; } in.add(elem); } ArrayList out = proxy.testDoubleVecs(in); ExpectTrue(in.equals(out)); } { // testProxyEquals // TODO(b/68727931): test passthrough services as well. IBase proxy1 = IBase.getService("baz"); IBase proxy2 = IBase.getService("baz"); IBaz proxy3 = IBaz.getService("baz"); IBazCallback callback1 = new BazCallback(); IBazCallback callback2 = new BazCallback(); IServiceManager manager = IServiceManager.getService(); // test hwbinder proxies ExpectEqual(proxy1, proxy2); // same proxy class ExpectEqual(proxy1, proxy3); // different proxy class // negative tests ExpectNotEqual(proxy1, null); ExpectNotEqual(proxy1, callback1); // proxy != stub ExpectNotEqual(proxy1, manager); // HidlSupport.interfacesEqual use overridden .equals for stubs ExpectEqual(callback1, callback1); ExpectEqual(callback1, callback2); callback1.hey(); ExpectNotEqual(callback1, callback2); callback2.hey(); ExpectEqual(callback1, callback2); // test hash for proxies java.util.HashSet set = new java.util.HashSet<>(); set.add(proxy1); ExpectTrue(set.contains(proxy1)); // hash is stable ExpectTrue(set.contains(proxy2)); ExpectFalse(set.contains(manager)); } // --- DEATH RECIPIENT TESTING --- // This must always be done last, since it will kill the native server process HidlDeathRecipient recipient1 = new HidlDeathRecipient(); HidlDeathRecipient recipient2 = new HidlDeathRecipient(); final int cookie1 = 0x1481; final int cookie2 = 0x1482; ExpectTrue(proxy.linkToDeath(recipient1, cookie1)); ExpectTrue(proxy.linkToDeath(recipient2, cookie2)); ExpectTrue(proxy.unlinkToDeath(recipient2)); try { proxy.dieNow(); } catch (RemoteException e) { // Expected } ExpectTrue(recipient1.waitUntilServiceDied(2000 /*timeoutMillis*/)); ExpectTrue(!recipient2.waitUntilServiceDied(2000 /*timeoutMillis*/)); ExpectTrue(recipient1.cookieMatches(cookie1)); Log.d(TAG, "OK, exiting"); } class Baz extends IBaz.Stub { // from IBase public void someBaseMethod() { Log.d(TAG, "Baz someBaseMethod"); } public IBase.Foo someOtherBaseMethod(IBase.Foo foo) { Log.d(TAG, "Baz someOtherBaseMethod " + foo.toString()); return foo; } public IBase.Foo[] someMethodWithFooArrays(IBase.Foo[] fooInput) { Log.d(TAG, "Baz someMethodWithFooArrays " + fooInput.toString()); IBase.Foo[] fooOutput = new IBase.Foo[2]; fooOutput[0] = fooInput[1]; fooOutput[1] = fooInput[0]; return fooOutput; } public ArrayList someMethodWithFooVectors( ArrayList fooInput) { Log.d(TAG, "Baz someMethodWithFooVectors " + fooInput.toString()); ArrayList fooOutput = new ArrayList(); fooOutput.add(fooInput.get(1)); fooOutput.add(fooInput.get(0)); return fooOutput; } public IBase.VectorOfArray someMethodWithVectorOfArray( IBase.VectorOfArray in) { Log.d(TAG, "Baz someMethodWithVectorOfArray " + in.toString()); IBase.VectorOfArray out = new IBase.VectorOfArray(); int n = in.addresses.size(); for (int i = 0; i < n; ++i) { out.addresses.add(in.addresses.get(n - i - 1)); } return out; } public ArrayList someMethodTakingAVectorOfArray( ArrayList in) { Log.d(TAG, "Baz someMethodTakingAVectorOfArray"); int n = in.size(); ArrayList out = new ArrayList(); for (int i = 0; i < n; ++i) { out.add(in.get(n - i - 1)); } return out; } public IBase.StringMatrix3x5 transpose(IBase.StringMatrix5x3 in) { Log.d(TAG, "Baz transpose " + in.toString()); IBase.StringMatrix3x5 out = new IBase.StringMatrix3x5(); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 5; ++j) { out.s[i][j] = in.s[j][i]; } } return out; } public String[][] transpose2(String[][] in) { Log.d(TAG, "Baz transpose2 " + in.toString()); String[][] out = new String[3][5]; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 5; ++j) { out[i][j] = in[j][i]; } } return out; } public boolean someBoolMethod(boolean x) { Log.d(TAG, "Baz someBoolMethod(" + x + ")"); return !x; } public boolean[] someBoolArrayMethod(boolean[] x) { Log.d(TAG, "Baz someBoolArrayMethod(" + x.toString() + ")"); boolean[] out = new boolean[4]; out[0] = !x[0]; out[1] = !x[1]; out[2] = !x[2]; out[3] = true; return out; } public ArrayList someBoolVectorMethod(ArrayList x) { Log.d(TAG, "Baz someBoolVectorMethod(" + x.toString() + ")"); ArrayList out = new ArrayList(); for (int i = 0; i < x.size(); ++i) { out.add(!x.get(i)); } return out; } public void doThis(float param) { Log.d(TAG, "Baz doThis " + param); } public int doThatAndReturnSomething(long param) { Log.d(TAG, "Baz doThatAndReturnSomething " + param); return 666; } public double doQuiteABit(int a, long b, float c, double d) { Log.d(TAG, "Baz doQuiteABit " + a + ", " + b + ", " + c + ", " + d); return 666.5; } public int[] doSomethingElse(int[] param) { Log.d(TAG, "Baz doSomethingElse " + param.toString()); int[] something = new int[32]; for (int i = 0; i < 15; ++i) { something[i] = 2 * param[i]; something[15 + i] = param[i]; } something[30] = 1; something[31] = 2; return something; } public String doStuffAndReturnAString() { Log.d(TAG, "doStuffAndReturnAString"); return "Hello, world!"; } public ArrayList mapThisVector(ArrayList param) { Log.d(TAG, "mapThisVector " + param.toString()); ArrayList out = new ArrayList(); for (int i = 0; i < param.size(); ++i) { out.add(2 * param.get(i)); } return out; } public void takeAMask(byte bf, byte first, IBase.MyMask second, byte third, takeAMaskCallback cb) { cb.onValues(bf, (byte)(bf | first), (byte)(second.value & bf), (byte)((bf | bf) & third)); } public LotsOfPrimitiveArrays testArrays(LotsOfPrimitiveArrays in) { return in; } public ArrayList testByteVecs(ArrayList in) { return in; } public ArrayList testBooleanVecs(ArrayList in) { return in; } public ArrayList testDoubleVecs(ArrayList in) { return in; } public byte returnABitField() { return 0; } public int size(int size) { return size; } @Override public ArrayList getNestedStructs() throws RemoteException { return new ArrayList<>(); } class BazCallback extends IBazCallback.Stub { public void heyItsMe(IBazCallback cb) { Log.d(TAG, "SERVER: heyItsMe"); } public void hey() { Log.d(TAG, "SERVER: hey"); } } public void callMe(IBazCallback cb) throws RemoteException { Log.d(TAG, "callMe"); cb.heyItsMe(new BazCallback()); } private IBazCallback mStoredCallback; public void callMeLater(IBazCallback cb) { mStoredCallback = cb; } public void iAmFreeNow() throws RemoteException { if (mStoredCallback != null) { mStoredCallback.hey(); } } public void dieNow() { // Not tested in Java } public byte useAnEnum(byte zzz) { Log.d(TAG, "useAnEnum " + zzz); return SomeEnum.quux; } public String[] haveSomeStrings(String[] array) { Log.d(TAG, "haveSomeStrings [" + "\"" + array[0] + "\", " + "\"" + array[1] + "\", " + "\"" + array[2] + "\"]"); String[] result = new String[2]; result[0] = "Hello"; result[1] = "World"; return result; } public ArrayList haveAStringVec(ArrayList vector) { Log.d(TAG, "haveAStringVec [" + "\"" + vector.get(0) + "\", " + "\"" + vector.get(1) + "\", " + "\"" + vector.get(2) + "\"]"); ArrayList result = new ArrayList(); result.add("Hello"); result.add("World"); return result; } public void returnABunchOfStrings(returnABunchOfStringsCallback cb) { cb.onValues("Eins", "Zwei", "Drei"); } } private void server() throws RemoteException { HwBinder.configureRpcThreadpool(1, true); Baz baz = new Baz(); baz.registerAsService("baz"); HwBinder.joinRpcThreadpool(); } }