1/*
2 * Copyright (C) 2015, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.aidl.tests;
18
19import android.aidl.tests.SimpleParcelable;
20import android.aidl.tests.TestFailException;
21import android.aidl.tests.TestLogger;
22import android.app.Activity;
23import android.content.Context;
24import android.content.Intent;
25import android.os.ServiceSpecificException;
26import android.os.Bundle;
27import android.os.IBinder;
28import android.os.PersistableBundle;
29import android.os.RemoteException;
30import android.os.ServiceManager;
31import android.util.Log;
32import java.io.File;
33import java.io.FileDescriptor;
34import java.io.FileInputStream;
35import java.io.FileOutputStream;
36import java.io.IOException;
37import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.Collections;
40import java.util.List;
41import java.util.Map;
42import java.util.HashMap;
43
44// Generated
45import android.aidl.tests.INamedCallback;
46import android.aidl.tests.ITestService;
47
48public class TestServiceClient extends Activity {
49    private static final String TAG = "TestServiceClient";
50
51    private TestLogger mLog;
52    private String mSuccessSentinel;
53    private String mFailureSentinel;
54
55    private void init() {
56        Intent intent = getIntent();
57        mLog = new TestLogger(this);
58        mLog.log("Reading sentinels from intent...");
59        mSuccessSentinel = intent.getStringExtra("sentinel.success");
60        mFailureSentinel = intent.getStringExtra("sentinel.failure");
61        if (mSuccessSentinel == null || mFailureSentinel == null) {
62            String message = "Failed to read intent extra input.";
63            Log.e(TAG, message);
64            mLog.close();
65            throw new RuntimeException(message);
66        }
67    }
68
69    private ITestService getService() throws TestFailException {
70        IBinder service = new ServiceManager().getService(
71                ITestService.class.getName());
72        if (service == null) {
73            mLog.logAndThrow("Failed to obtain binder...");
74        }
75        ITestService ret = ITestService.Stub.asInterface(service);
76        if (ret == null) {
77            mLog.logAndThrow("Failed to cast IBinder instance.");
78        }
79        return ret;
80    }
81
82    private void checkPrimitiveRepeat(ITestService service)
83            throws TestFailException {
84        mLog.log("Checking that service can repeat primitives back...");
85        try {
86            {
87                boolean query = true;
88                boolean response = service.RepeatBoolean(query);
89                if (query != response) {
90                    mLog.logAndThrow("Repeat with " + query +
91                                     " responded " + response);
92                }
93            }
94            {
95                char query = 'A';
96                char response = service.RepeatChar(query);
97                if (query != response) {
98                    mLog.logAndThrow("Repeat with " + query +
99                                     " responded " + response);
100                }
101            }
102            {
103                byte query = -128;
104                byte response = service.RepeatByte(query);
105                if (query != response) {
106                    mLog.logAndThrow("Repeat with " + query +
107                                     " responded " + response);
108                }
109            }
110            {
111                int query = 1 << 30;
112                int response = service.RepeatInt(query);
113                if (query != response) {
114                    mLog.logAndThrow("Repeat with " + query +
115                                     " responded " + response);
116                }
117            }
118            {
119                int query[] = {ITestService.TEST_CONSTANT,
120                               ITestService.TEST_CONSTANT2,
121                               ITestService.TEST_CONSTANT3,
122                               ITestService.TEST_CONSTANT4,
123                               ITestService.TEST_CONSTANT5,
124                               ITestService.TEST_CONSTANT6,
125                               ITestService.TEST_CONSTANT7,
126                               ITestService.TEST_CONSTANT8};
127                for (int i = 0; i < query.length; i++) {
128                    int response = service.RepeatInt(query[i]);
129                    if (query[i] != response) {
130                        mLog.logAndThrow("Repeat with " + query[i] +
131                                " responded " + response);
132                    }
133                }
134            }
135            {
136                long query = 1L << 60;
137                long response = service.RepeatLong(query);
138                if (query != response) {
139                    mLog.logAndThrow("Repeat with " + query +
140                                     " responded " + response);
141                }
142            }
143            {
144                float query = 1.0f/3.0f;
145                float response = service.RepeatFloat(query);
146                if (query != response) {
147                    mLog.logAndThrow("Repeat with " + query +
148                                     " responded " + response);
149                }
150            }
151            {
152                double query = 1.0/3.0;
153                double response = service.RepeatDouble(query);
154                if (query != response) {
155                    mLog.logAndThrow("Repeat with " + query +
156                                     " responded " + response);
157                }
158            }
159            {
160                Map<String, Object> query = new HashMap<String, Object>();
161                query.put("first_val", new Byte((byte)-128));
162                query.put("second_val", new Integer(1<<30));
163                query.put("third_val", "OHAI");
164                Object response = service.RepeatMap(query);
165                if (!query.equals(response)) {
166                    mLog.logAndThrow("Repeat with " + query +
167                                     " responded " + response);
168                }
169            }
170
171            List<String> queries = Arrays.asList(
172                "not empty", "", "\0",
173                ITestService.STRING_TEST_CONSTANT,
174                ITestService.STRING_TEST_CONSTANT2);
175            for (String query : queries) {
176                String response = service.RepeatString(query);
177                if (!query.equals(response)) {
178                    mLog.logAndThrow("Repeat request with '" + query + "'" +
179                                     " of length " + query.length() +
180                                     " responded with '" + response + "'" +
181                                     " of length " + response.length());
182                }
183            }
184        } catch (RemoteException ex) {
185            mLog.log(ex.toString());
186            mLog.logAndThrow("Service failed to repeat a primitive back.");
187        }
188        mLog.log("...Basic primitive repeating works.");
189    }
190
191    private void checkArrayReversal(ITestService service)
192            throws TestFailException {
193        mLog.log("Checking that service can reverse and return arrays...");
194        try {
195            {
196                boolean[] input = {true, false, false, false};
197                boolean echoed[] = new boolean[input.length];
198                boolean[] reversed = service.ReverseBoolean(input, echoed);
199                if (!Arrays.equals(input, echoed)) {
200                    mLog.logAndThrow("Failed to echo input array back.");
201                }
202                if (input.length != reversed.length) {
203                    mLog.logAndThrow("Reversed array is the wrong size.");
204                }
205                for (int i = 0; i < input.length; ++i) {
206                    int j = reversed.length - (1 + i);
207                    if (input[i] != reversed[j]) {
208                        mLog.logAndThrow(
209                                "input[" + i + "] = " + input[i] +
210                                " but reversed value = " + reversed[j]);
211                    }
212                }
213            }
214            {
215                byte[] input = {0, 1, 2};
216                byte echoed[] = new byte[input.length];
217                byte[] reversed = service.ReverseByte(input, echoed);
218                if (!Arrays.equals(input, echoed)) {
219                    mLog.logAndThrow("Failed to echo input array back.");
220                }
221                if (input.length != reversed.length) {
222                    mLog.logAndThrow("Reversed array is the wrong size.");
223                }
224                for (int i = 0; i < input.length; ++i) {
225                    int j = reversed.length - (1 + i);
226                    if (input[i] != reversed[j]) {
227                        mLog.logAndThrow(
228                                "input[" + i + "] = " + input[i] +
229                                " but reversed value = " + reversed[j]);
230                    }
231                }
232            }
233            {
234                char[] input = {'A', 'B', 'C', 'D', 'E'};
235                char echoed[] = new char[input.length];
236                char[] reversed = service.ReverseChar(input, echoed);
237                if (!Arrays.equals(input, echoed)) {
238                    mLog.logAndThrow("Failed to echo input array back.");
239                }
240                if (input.length != reversed.length) {
241                    mLog.logAndThrow("Reversed array is the wrong size.");
242                }
243                for (int i = 0; i < input.length; ++i) {
244                    int j = reversed.length - (1 + i);
245                    if (input[i] != reversed[j]) {
246                        mLog.logAndThrow(
247                                "input[" + i + "] = " + input[i] +
248                                " but reversed value = " + reversed[j]);
249                    }
250                }
251            }
252            {
253                int[] input = {-1, 0, 1, 2, 3, 4, 5, 6};
254                int echoed[] = new int[input.length];
255                int[] reversed = service.ReverseInt(input, echoed);
256                if (!Arrays.equals(input, echoed)) {
257                    mLog.logAndThrow("Failed to echo input array back.");
258                }
259                if (input.length != reversed.length) {
260                    mLog.logAndThrow("Reversed array is the wrong size.");
261                }
262                for (int i = 0; i < input.length; ++i) {
263                    int j = reversed.length - (1 + i);
264                    if (input[i] != reversed[j]) {
265                        mLog.logAndThrow(
266                                "input[" + i + "] = " + input[i] +
267                                " but reversed value = " + reversed[j]);
268                    }
269                }
270            }
271            {
272                long[] input = {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8};
273                long echoed[] = new long[input.length];
274                long[] reversed = service.ReverseLong(input, echoed);
275                if (!Arrays.equals(input, echoed)) {
276                    mLog.logAndThrow("Failed to echo input array back.");
277                }
278                if (input.length != reversed.length) {
279                    mLog.logAndThrow("Reversed array is the wrong size.");
280                }
281                for (int i = 0; i < input.length; ++i) {
282                    int j = reversed.length - (1 + i);
283                    if (input[i] != reversed[j]) {
284                        mLog.logAndThrow(
285                                "input[" + i + "] = " + input[i] +
286                                " but reversed value = " + reversed[j]);
287                    }
288                }
289            }
290            {
291                float[] input = {0.0f, 1.0f, -0.3f};
292                float echoed[] = new float[input.length];
293                float[] reversed = service.ReverseFloat(input, echoed);
294                if (!Arrays.equals(input, echoed)) {
295                    mLog.logAndThrow("Failed to echo input array back.");
296                }
297                if (input.length != reversed.length) {
298                    mLog.logAndThrow("Reversed array is the wrong size.");
299                }
300                for (int i = 0; i < input.length; ++i) {
301                    int j = reversed.length - (1 + i);
302                    if (input[i] != reversed[j]) {
303                        mLog.logAndThrow(
304                                "input[" + i + "] = " + input[i] +
305                                " but reversed value = " + reversed[j]);
306                    }
307                }
308            }
309            {
310                double[] input = {-1.0, -4.0, -2.0};
311                double echoed[] = new double[input.length];
312                double[] reversed = service.ReverseDouble(input, echoed);
313                if (!Arrays.equals(input, echoed)) {
314                    mLog.logAndThrow("Failed to echo input array back.");
315                }
316                if (input.length != reversed.length) {
317                    mLog.logAndThrow("Reversed array is the wrong size.");
318                }
319                for (int i = 0; i < input.length; ++i) {
320                    int j = reversed.length - (1 + i);
321                    if (input[i] != reversed[j]) {
322                        mLog.logAndThrow(
323                                "input[" + i + "] = " + input[i] +
324                                " but reversed value = " + reversed[j]);
325                    }
326                }
327            }
328            {
329                String[] input = {"For", "relaxing", "times"};
330                String echoed[] = new String[input.length];
331                String[] reversed = service.ReverseString(input, echoed);
332                if (!Arrays.equals(input, echoed)) {
333                    mLog.logAndThrow("Failed to echo input array back.");
334                }
335                if (input.length != reversed.length) {
336                    mLog.logAndThrow("Reversed array is the wrong size.");
337                }
338                for (int i = 0; i < input.length; ++i) {
339                    int j = reversed.length - (1 + i);
340                    if (!input[i].equals(reversed[j])) {
341                        mLog.logAndThrow(
342                                "input[" + i + "] = " + input[i] +
343                                " but reversed value = " + reversed[j]);
344                    }
345                }
346            }
347        } catch (RemoteException ex) {
348            mLog.log(ex.toString());
349            mLog.logAndThrow("Service failed to reverse an array.");
350        }
351        mLog.log("...service can reverse and return arrays.");
352    }
353
354    private void checkBinderExchange(
355                ITestService service) throws TestFailException {
356      mLog.log("Checking exchange of binders...");
357      try {
358          INamedCallback got = service.GetOtherTestService("Smythe");
359          mLog.log("Received test service");
360          String name = got.GetName();
361
362          if (!name.equals("Smythe")) {
363              mLog.logAndThrow("Tried to get service with name 'Smythe'" +
364                               " and found service with name '" + name + "'");
365          }
366
367          if (!service.VerifyName(got, "Smythe")) {
368              mLog.logAndThrow("Test service could not verify name of 'Smythe'");
369          }
370      } catch (RemoteException ex) {
371          mLog.log(ex.toString());
372          mLog.logAndThrow("Service failed to exchange binders.");
373      }
374      mLog.log("...Exchange of binders works");
375    }
376
377    private void checkListReversal(ITestService service)
378            throws TestFailException {
379        mLog.log("Checking that service can reverse and return lists...");
380        try {
381            {
382                List<String> input = Arrays.asList("Walk", "into", "Córdoba");
383                List<String> echoed = new ArrayList<String>();
384                List<String> reversed = service.ReverseStringList(input, echoed);
385                if (!input.equals(echoed)) {
386                    mLog.logAndThrow("Failed to echo input List<String> back.");
387                }
388                Collections.reverse(input);
389                if (!input.equals(reversed)) {
390                    mLog.logAndThrow("Reversed list is not correct.");
391                }
392            }
393        } catch (RemoteException ex) {
394            mLog.log(ex.toString());
395            mLog.logAndThrow("Service failed to reverse an List<String>.");
396        }
397        mLog.log("...service can reverse and return lists.");
398    }
399
400    private void checkSimpleParcelables(ITestService service)
401            throws TestFailException {
402        mLog.log("Checking that service can repeat and reverse SimpleParcelable objects...");
403        try {
404            {
405                SimpleParcelable input = new SimpleParcelable("foo", 42);
406                SimpleParcelable out_param = new SimpleParcelable();
407                SimpleParcelable returned =
408                        service.RepeatSimpleParcelable(input, out_param);
409                if (!input.equals(out_param)) {
410                    mLog.log(input.toString() + " != " + out_param.toString());
411                    mLog.logAndThrow("out param SimpleParcelable was not equivalent");
412                }
413                if (!input.equals(returned)) {
414                    mLog.log(input.toString() + " != " + returned.toString());
415                    mLog.logAndThrow("returned SimpleParcelable was not equivalent");
416                }
417            }
418            {
419                SimpleParcelable[] input = new SimpleParcelable[3];
420                input[0] = new SimpleParcelable("a", 1);
421                input[1] = new SimpleParcelable("b", 2);
422                input[2] = new SimpleParcelable("c", 3);
423                SimpleParcelable[] repeated = new SimpleParcelable[3];
424                SimpleParcelable[] reversed = service.ReverseSimpleParcelables(
425                        input, repeated);
426                if (!Arrays.equals(input, repeated)) {
427                    mLog.logAndThrow(
428                            "Repeated list of SimpleParcelable objects did not match.");
429                }
430                if (input.length != reversed.length) {
431                    mLog.logAndThrow(
432                            "Reversed list of SimpleParcelable objects had wrong length.");
433                }
434                for (int i = 0, k = input.length - 1;
435                     i < input.length;
436                     ++i, --k) {
437                    if (!input[i].equals(reversed[k])) {
438                        mLog.log(input[i].toString() + " != " +
439                                 reversed[k].toString());
440                        mLog.logAndThrow("reversed SimpleParcelable was not equivalent");
441                    }
442                }
443            }
444        } catch (Exception ex) {
445            mLog.log(ex.toString());
446            mLog.logAndThrow("Service failed to handle SimpleParcelable objects.");
447        }
448        mLog.log("...service can manipulate SimpleParcelable objects.");
449    }
450
451    private void checkPersistableBundles(ITestService service)
452            throws TestFailException {
453        mLog.log("Checking that service can repeat and reverse PersistableBundle objects...");
454        try {
455            {
456                PersistableBundle emptyBundle = new PersistableBundle();
457                PersistableBundle returned = service.RepeatPersistableBundle(emptyBundle);
458                if (emptyBundle.size() != 0 || returned.size() != 0) {
459                    mLog.log(emptyBundle.toString() + " != " + returned.toString());
460                    mLog.logAndThrow("returned empty PersistableBundle object was not equivalent");
461                }
462                mLog.log("...service can repeat and reverse empty PersistableBundle objects...");
463            }
464            {
465                final String testBoolKey = new String("testBool");
466                final String testIntKey = new String("testInt");
467                final String testNestedIntKey = new String("testNestedInt");
468                final String testLongKey = new String("testLong");
469                final String testDoubleKey = new String("testDouble");
470                final String testStringKey = new String("testString");
471                final String testBoolArrayKey = new String("testBoolArray");
472                final String testIntArrayKey = new String("testIntArray");
473                final String testLongArrayKey = new String("testLongArray");
474                final String testDoubleArrayKey = new String("testDoubleArray");
475                final String testStringArrayKey = new String("testStringArray");
476                final String testPersistableBundleKey = new String("testPersistableBundle");
477                PersistableBundle nonEmptyBundle = new PersistableBundle();
478                nonEmptyBundle.putBoolean(testBoolKey, false);
479                nonEmptyBundle.putInt(testIntKey, 33);
480                nonEmptyBundle.putLong(testLongKey, 34359738368L);
481                nonEmptyBundle.putDouble(testDoubleKey, 1.1);
482                nonEmptyBundle.putString(testStringKey, new String("Woot!"));
483                nonEmptyBundle.putBooleanArray(testBoolArrayKey, new boolean[] {true, false, true});
484                nonEmptyBundle.putIntArray(testIntArrayKey, new int[] {33, 44, 55, 142});
485                nonEmptyBundle.putLongArray(
486                    testLongArrayKey, new long[] {34L, 8371L, 34359738375L});
487                nonEmptyBundle.putDoubleArray(testDoubleArrayKey, new double[] {2.2, 5.4});
488                nonEmptyBundle.putStringArray(testStringArrayKey, new String[] {"hello", "world!"});
489                PersistableBundle testNestedPersistableBundle = new PersistableBundle();
490                testNestedPersistableBundle.putInt(testNestedIntKey, 345);
491                nonEmptyBundle.putPersistableBundle(
492                    testPersistableBundleKey, testNestedPersistableBundle);
493                PersistableBundle returned = service.RepeatPersistableBundle(nonEmptyBundle);
494                if (returned.size() != nonEmptyBundle.size()
495                    || returned.getBoolean(testBoolKey) != nonEmptyBundle.getBoolean(testBoolKey)
496                    || returned.getInt(testIntKey) != nonEmptyBundle.getInt(testIntKey)
497                    || returned.getLong(testLongKey) != nonEmptyBundle.getLong(testLongKey)
498                    || returned.getDouble(testDoubleKey) != nonEmptyBundle.getDouble(testDoubleKey)
499                    || !returned.getString(testStringKey)
500                                .equals(nonEmptyBundle.getString(testStringKey))
501                    || !Arrays.equals(nonEmptyBundle.getBooleanArray(testBoolArrayKey),
502                                      returned.getBooleanArray(testBoolArrayKey))
503                    || !Arrays.equals(nonEmptyBundle.getIntArray(testIntArrayKey),
504                                      returned.getIntArray(testIntArrayKey))
505                    || !Arrays.equals(nonEmptyBundle.getLongArray(testLongArrayKey),
506                                      returned.getLongArray(testLongArrayKey))
507                    || !Arrays.equals(nonEmptyBundle.getDoubleArray(testDoubleArrayKey),
508                                      returned.getDoubleArray(testDoubleArrayKey))
509                    || !Arrays.equals(nonEmptyBundle.getStringArray(testStringArrayKey),
510                                      returned.getStringArray(testStringArrayKey))) {
511                    PersistableBundle temp =
512                        returned.getPersistableBundle(testPersistableBundleKey);
513                    if (temp == null
514                        || temp.getInt(testNestedIntKey)
515                            != testNestedPersistableBundle.getInt(testNestedIntKey)) {
516                        mLog.log(nonEmptyBundle.toString() + " != " + returned.toString());
517                        mLog.logAndThrow("returned non-empty PersistableBundle " +
518                                         "object was not equivalent");
519                    }
520                }
521                mLog.log("...service can repeat and reverse non-empty " +
522                         "PersistableBundle objects...");
523            }
524            {
525                PersistableBundle[] input = new PersistableBundle[3];
526                PersistableBundle first = new PersistableBundle();
527                PersistableBundle second = new PersistableBundle();
528                PersistableBundle third = new PersistableBundle();
529                final String testIntKey = new String("testInt");
530                final String testLongKey = new String("testLong");
531                final String testDoubleKey = new String("testDouble");
532                first.putInt(testIntKey, 1231);
533                second.putLong(testLongKey, 222222L);
534                third.putDouble(testDoubleKey, 10.8);
535                input[0] = first;
536                input[1] = second;
537                input[2] = third;
538                final int original_input_size = input.length;
539                PersistableBundle[] repeated = new PersistableBundle[input.length];
540                PersistableBundle[] reversed = service.ReversePersistableBundles(input, repeated);
541                if (input.length != repeated.length || input.length != original_input_size) {
542                    mLog.logAndThrow("Repeated list of PersistableBundle objects had " +
543                                     "wrong length.");
544                }
545                if (input[0].getInt(testIntKey) != repeated[0].getInt(testIntKey)
546                    || input[1].getLong(testLongKey) != repeated[1].getLong(testLongKey)
547                    || input[2].getDouble(testDoubleKey) != repeated[2].getDouble(testDoubleKey)) {
548                    mLog.logAndThrow("Repeated list of PersistableBundle objects did not match.");
549                }
550                if (input.length != reversed.length || input.length != original_input_size) {
551                    mLog.logAndThrow("Reversed list of PersistableBundle objects had " +
552                                     "wrong length.");
553                }
554                if (input[0].getInt(testIntKey) != reversed[2].getInt(testIntKey)
555                    || input[1].getLong(testLongKey) != reversed[1].getLong(testLongKey)
556                    || input[2].getDouble(testDoubleKey) != reversed[0].getDouble(testDoubleKey)) {
557                    mLog.logAndThrow("reversed PersistableBundle objects were not equivalent");
558                }
559                mLog.log("...service can repeat and reverse arrays of " +
560                         "non-empty PersistableBundle objects...");
561            }
562        } catch (Exception ex) {
563            mLog.log(ex.toString());
564            mLog.logAndThrow("Service failed to handle PersistableBundle objects.");
565        }
566        mLog.log("...service can manipulate PersistableBundle objects.");
567    }
568
569    private void checkFileDescriptorPassing(ITestService service)
570            throws TestFailException {
571        mLog.log("Checking that service can receive and return file descriptors...");
572        try {
573            FileOutputStream fileOutputStream =
574                    openFileOutput("test-dummy", Context.MODE_PRIVATE);
575
576            FileDescriptor descriptor = fileOutputStream.getFD();
577            FileDescriptor journeyed = service.RepeatFileDescriptor(descriptor);
578            fileOutputStream.close();
579
580            FileOutputStream journeyedStream = new FileOutputStream(journeyed);
581
582            String testData = "FrazzleSnazzleFlimFlamFlibbityGumboChops";
583            byte[] output = testData.getBytes();
584            journeyedStream.write(output);
585            journeyedStream.close();
586
587            FileInputStream fileInputStream = openFileInput("test-dummy");
588            byte[] input = new byte[output.length];
589            if (fileInputStream.read(input) != input.length) {
590                mLog.logAndThrow("Read short count from file");
591            }
592
593            if (!Arrays.equals(input, output)) {
594                mLog.logAndThrow("Read incorrect data");
595            }
596        } catch (RemoteException ex) {
597            mLog.log(ex.toString());
598            mLog.logAndThrow("Service failed to repeat a file descriptor.");
599        } catch (IOException ex) {
600            mLog.log(ex.toString());
601            mLog.logAndThrow("Exception while operating on temporary file");
602        }
603        mLog.log("...service can receive and return file descriptors.");
604    }
605
606    private void checkServiceSpecificExceptions(
607                ITestService service) throws TestFailException {
608        mLog.log("Checking application exceptions...");
609        for (int i = -1; i < 2; ++i) {
610            try {
611                service.ThrowServiceException(i);
612            } catch (RemoteException ex) {
613                mLog.logAndThrow("Service threw RemoteException: " +
614                                 ex.toString());
615            } catch (ServiceSpecificException ex) {
616                if (ex.errorCode != i) {
617                    mLog.logAndThrow("Service threw wrong error code: " + i);
618                }
619            }
620        }
621        mLog.log("...application exceptions work");
622    }
623
624    private void checkUtf8Strings(ITestService service)
625            throws TestFailException {
626        mLog.log("Checking that service can work with UTF8 strings...");
627        // Note that Java's underlying encoding is UTF16.
628        final List<String> utf8_queries = Arrays.asList(
629              "typical string",
630              "",
631              "\0\0\0",
632              // Java doesn't handle unicode code points above U+FFFF well.
633              new String(Character.toChars(0x1F701)) + "\u03A9");
634        final List<String> utf8_queries_and_nulls = Arrays.asList(
635              "typical string",
636              null,
637              "",
638              "\0\0\0",
639              null,
640              // Java doesn't handle unicode code points above U+FFFF well.
641              new String(Character.toChars(0x1F701)) + "\u03A9");
642        try {
643            for (String query : utf8_queries) {
644                String response = service.RepeatUtf8CppString(query);
645                if (!query.equals(response)) {
646                    mLog.logAndThrow("Repeat request with '" + query + "'" +
647                                     " of length " + query.length() +
648                                     " responded with '" + response + "'" +
649                                     " of length " + response.length());
650                }
651            }
652            {
653                String[] input = (String[])utf8_queries.toArray();
654                String echoed[] = new String[input.length];
655                String[] reversed = service.ReverseUtf8CppString(input, echoed);
656                if (!Arrays.equals(input, echoed)) {
657                    mLog.logAndThrow("Failed to echo utf8 input array back.");
658                }
659                if (input.length != reversed.length) {
660                    mLog.logAndThrow("Reversed utf8 array is the wrong size.");
661                }
662                for (int i = 0; i < input.length; ++i) {
663                    int j = reversed.length - (1 + i);
664                    if (!input[i].equals(reversed[j])) {
665                        mLog.logAndThrow(
666                                "input[" + i + "] = " + input[i] +
667                                " but reversed value = " + reversed[j]);
668                    }
669                }
670            }
671            {
672                String[] input = (String[])utf8_queries_and_nulls.toArray();
673                String echoed[] = new String[input.length];
674                String[] reversed = service.ReverseNullableUtf8CppString(input,
675                    echoed);
676                if (!Arrays.equals(input, echoed)) {
677                    mLog.logAndThrow("Failed to echo utf8 input array back.");
678                }
679                if (input.length != reversed.length) {
680                    mLog.logAndThrow("Reversed utf8 array is the wrong size.");
681                }
682                for (int i = 0; i < input.length; ++i) {
683                    int j = reversed.length - (1 + i);
684                    if (input[i] == null && reversed[j] == null) {
685                        continue;
686                    }
687
688                    if (!input[i].equals(reversed[j])) {
689                        mLog.logAndThrow(
690                                "input[" + i + "] = " + input[i] +
691                                " but reversed value = " + reversed[j]);
692                    }
693                }
694            }
695        } catch (RemoteException ex) {
696            mLog.log(ex.toString());
697            mLog.logAndThrow("Service failed to handle utf8 strings.");
698        }
699        mLog.log("...UTF8 annotations work.");
700    }
701
702    @Override
703    protected void onCreate(Bundle savedInstanceState) {
704        super.onCreate(savedInstanceState);
705        Log.i(TAG, "Starting!");
706        try {
707          init();
708          ITestService service = getService();
709          checkPrimitiveRepeat(service);
710          checkArrayReversal(service);
711          checkBinderExchange(service);
712          checkListReversal(service);
713          checkSimpleParcelables(service);
714          checkPersistableBundles(service);
715          checkFileDescriptorPassing(service);
716          checkServiceSpecificExceptions(service);
717          checkUtf8Strings(service);
718          new NullableTests(service, mLog).runTests();
719
720          mLog.log(mSuccessSentinel);
721        } catch (TestFailException e) {
722            mLog.log(mFailureSentinel);
723            throw new RuntimeException(e);
724        } finally {
725            if (mLog != null) {
726                mLog.close();
727            }
728        }
729    }
730}
731