diff options
author | Xin Li <delphij@google.com> | 2022-02-11 06:57:32 +0000 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2022-02-11 06:57:32 +0000 |
commit | f7bd394f22e035c8c5be34ae9e3f8b43f299d22e (patch) | |
tree | 7dada9629976efaca4537893d3c6841bdee6f692 | |
parent | d683d7d4f36353ff6c40a719c785a0dd7e66e60d (diff) | |
parent | 265a3eca1141c83f1e7b58c781b3588d91a7c270 (diff) | |
download | connectedappssdk-f7bd394f22e035c8c5be34ae9e3f8b43f299d22e.tar.gz |
Merge sc-v2-dev-plus-aosp-without-vendor@8084891sam_222710654
Bug: 214455710
Merged-In: Ib299774f0d1722c0a40c3d9f6657882e5b2e2498
Change-Id: I45469716d8fc4030da6c31a691e3207b2b2be2e5
10 files changed, 519 insertions, 439 deletions
diff --git a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/DispatcherGenerator.java b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/DispatcherGenerator.java index f5264b0..a4f8ef6 100644 --- a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/DispatcherGenerator.java +++ b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/DispatcherGenerator.java @@ -187,6 +187,21 @@ final class DispatcherGenerator { methodCode.addStatement("$T.throwInBackground(e)", BACKGROUND_EXCEPTION_THROWER_CLASSNAME); methodCode.addStatement("return throwableBytes"); + methodCode.nextControlFlow("catch ($T e)", Error.class); + + // parcel is recycled in this method + methodCode.addStatement("$1T throwableParcel = $1T.obtain()", PARCEL_CLASSNAME); + methodCode.add("throwableParcel.writeInt(1); //errors\n"); + methodCode.addStatement( + "$T.writeThrowableToParcel(throwableParcel, e)", PARCEL_UTILITIES_CLASSNAME); + methodCode.addStatement( + "$1T throwableBytes = parcelCallReceiver.prepareResponse(callId, throwableParcel)", + ArrayTypeName.of(byte.class)); + methodCode.addStatement("throwableParcel.recycle()"); + + methodCode.addStatement("$T.throwInBackground(e)", BACKGROUND_EXCEPTION_THROWER_CLASSNAME); + + methodCode.addStatement("return throwableBytes"); methodCode.endControlFlow(); MethodSpec callMethod = diff --git a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/FakeOtherGenerator.java b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/FakeOtherGenerator.java index 20bf0fb..53e5c72 100644 --- a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/FakeOtherGenerator.java +++ b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/FakeOtherGenerator.java @@ -215,6 +215,8 @@ final class FakeOtherGenerator { methodBuilder.addStatement(methodCall); methodBuilder.nextControlFlow("catch ($T e)", RuntimeException.class); methodBuilder.addStatement("throw new $T(e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME); + methodBuilder.nextControlFlow("catch ($T e)", Error.class); + methodBuilder.addStatement("throw new $T(e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME); methodBuilder.endControlFlow(); classBuilder.addMethod(methodBuilder.build()); } @@ -267,6 +269,8 @@ final class FakeOtherGenerator { methodBuilder.addStatement(methodCall); methodBuilder.nextControlFlow("catch ($T e)", RuntimeException.class); methodBuilder.addStatement("throw new $T(e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME); + methodBuilder.nextControlFlow("catch ($T e)", Error.class); + methodBuilder.addStatement("throw new $T(e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME); methodBuilder.endControlFlow(); classBuilder.addMethod(methodBuilder.build()); @@ -332,6 +336,8 @@ final class FakeOtherGenerator { } methodBuilder.nextControlFlow("catch ($T e)", RuntimeException.class); methodBuilder.addStatement("throw new $T(e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME); + methodBuilder.nextControlFlow("catch ($T e)", Error.class); + methodBuilder.addStatement("throw new $T(e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME); methodBuilder.endControlFlow(); classBuilder.addMethod(methodBuilder.build()); diff --git a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/InternalCrossProfileClassGenerator.java b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/InternalCrossProfileClassGenerator.java index f4aad75..bbbf0ab 100644 --- a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/InternalCrossProfileClassGenerator.java +++ b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/InternalCrossProfileClassGenerator.java @@ -64,9 +64,9 @@ final class InternalCrossProfileClassGenerator { private final CrossProfileTypeInfo crossProfileType; InternalCrossProfileClassGenerator( - GeneratorContext generatorContext, - ProviderClassInfo providerClass, - CrossProfileTypeInfo crossProfileType) { + GeneratorContext generatorContext, + ProviderClassInfo providerClass, + CrossProfileTypeInfo crossProfileType) { this.generatorContext = checkNotNull(generatorContext); this.generatorUtilities = new GeneratorUtilities(generatorContext); this.providerClass = checkNotNull(providerClass); @@ -76,7 +76,7 @@ final class InternalCrossProfileClassGenerator { void generate() { if (generated) { throw new IllegalStateException( - "InternalCrossProfileClassGenerator#generate can only be called once"); + "InternalCrossProfileClassGenerator#generate can only be called once"); } generated = true; @@ -87,60 +87,60 @@ final class InternalCrossProfileClassGenerator { ClassName className = getInternalCrossProfileClassName(generatorContext, crossProfileType); TypeSpec.Builder classBuilder = - TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC, Modifier.FINAL); + TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC, Modifier.FINAL); classBuilder.addJavadoc( - "Internal class for {@link $T}.\n\n" - + "<p>This is used by the Connected Apps SDK to dispatch cross-profile calls.\n\n" - + "<p>Cross-profile type identifier: $L.\n", - crossProfileType.crossProfileTypeElement().asType(), - crossProfileType.identifier()); + "Internal class for {@link $T}.\n\n" + + "<p>This is used by the Connected Apps SDK to dispatch cross-profile calls.\n\n" + + "<p>Cross-profile type identifier: $L.\n", + crossProfileType.crossProfileTypeElement().asType(), + crossProfileType.identifier()); classBuilder.addField( - FieldSpec.builder(className, "instance") - .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) - .initializer("new $T()", className) - .build()); + FieldSpec.builder(className, "instance") + .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) + .initializer("new $T()", className) + .build()); classBuilder.addField( - FieldSpec.builder(BUNDLER_CLASSNAME, "bundler") - .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) - .initializer( - "new $T()", - BundlerGenerator.getBundlerClassName(generatorContext, crossProfileType)) - .build()); + FieldSpec.builder(BUNDLER_CLASSNAME, "bundler") + .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) + .initializer( + "new $T()", + BundlerGenerator.getBundlerClassName(generatorContext, crossProfileType)) + .build()); if (!crossProfileType.isStatic()) { ExecutableElement providerMethod = - providerClass.findProviderMethodFor(generatorContext, crossProfileType); + providerClass.findProviderMethodFor(generatorContext, crossProfileType); String paramsString = providerMethod.getParameters().isEmpty() ? "()" : "(context)"; CodeBlock providerMethodCall = - CodeBlock.of("$L$L", providerMethod.getSimpleName(), paramsString); + CodeBlock.of("$L$L", providerMethod.getSimpleName(), paramsString); classBuilder.addMethod( - MethodSpec.methodBuilder("crossProfileType") - .addParameter(CONTEXT_CLASSNAME, "context") - .returns(crossProfileType.className()) - .addStatement( - "return $T.instance().providerClass(context).$L", - InternalProviderClassGenerator.getInternalProviderClassName( - generatorContext, providerClass), - providerMethodCall) - .build()); + MethodSpec.methodBuilder("crossProfileType") + .addParameter(CONTEXT_CLASSNAME, "context") + .returns(crossProfileType.className()) + .addStatement( + "return $T.instance().providerClass(context).$L", + InternalProviderClassGenerator.getInternalProviderClassName( + generatorContext, providerClass), + providerMethodCall) + .build()); } classBuilder.addMethod( - MethodSpec.methodBuilder("bundler") - .returns(BUNDLER_CLASSNAME) - .addStatement("return bundler") - .build()); + MethodSpec.methodBuilder("bundler") + .returns(BUNDLER_CLASSNAME) + .addStatement("return bundler") + .build()); classBuilder.addMethod( - MethodSpec.methodBuilder("instance") - .addModifiers(Modifier.STATIC) - .returns(className) - .addStatement("return instance") - .build()); + MethodSpec.methodBuilder("instance") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(className) + .addStatement("return instance") + .build()); classBuilder.addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build()); @@ -152,23 +152,23 @@ final class InternalCrossProfileClassGenerator { } private void addMethodsField( - TypeSpec.Builder classBuilder, CrossProfileTypeInfo crossProfileType) { + TypeSpec.Builder classBuilder, CrossProfileTypeInfo crossProfileType) { int totalMethods = crossProfileType.crossProfileMethods().size(); classBuilder.addField( - FieldSpec.builder(ArrayTypeName.of(METHOD_RUNNER_CLASSNAME), "methods") - .addModifiers(Modifier.PRIVATE) - .initializer( - "new $T[]{$L}", - METHOD_RUNNER_CLASSNAME, - IntStream.range(0, totalMethods) - .mapToObj(n -> "this::method" + n) - .collect(joining(","))) - .build()); + FieldSpec.builder(ArrayTypeName.of(METHOD_RUNNER_CLASSNAME), "methods") + .addModifiers(Modifier.PRIVATE) + .initializer( + "new $T[]{$L}", + METHOD_RUNNER_CLASSNAME, + IntStream.range(0, totalMethods) + .mapToObj(n -> "this::method" + n) + .collect(joining(","))) + .build()); } private void addCrossProfileTypeMethods( - TypeSpec.Builder classBuilder, CrossProfileTypeInfo crossProfileType) { + TypeSpec.Builder classBuilder, CrossProfileTypeInfo crossProfileType) { for (CrossProfileMethodInfo method : crossProfileType.crossProfileMethods()) { if (method.isBlocking(generatorContext, crossProfileType)) { addBlockingCrossProfileTypeMethod(classBuilder, method); @@ -183,7 +183,7 @@ final class InternalCrossProfileClassGenerator { } private void addBlockingCrossProfileTypeMethod( - TypeSpec.Builder classBuilder, CrossProfileMethodInfo method) { + TypeSpec.Builder classBuilder, CrossProfileMethodInfo method) { CodeBlock.Builder methodCode = CodeBlock.builder(); // parcle is recycled by caller @@ -192,12 +192,12 @@ final class InternalCrossProfileClassGenerator { addExtractParametersCode(methodCode, method); CodeBlock methodCall = - CodeBlock.of( - "$L.$L($L)", - getCrossProfileTypeReference(method), - method.simpleName(), - method.commaSeparatedParameters( - crossProfileType.supportedTypes(), REPLACE_AUTOMATICALLY_RESOLVED_PARAMETERS)); + CodeBlock.of( + "$L.$L($L)", + getCrossProfileTypeReference(method), + method.simpleName(), + method.commaSeparatedParameters( + crossProfileType.supportedTypes(), REPLACE_AUTOMATICALLY_RESOLVED_PARAMETERS)); if (!method.thrownExceptions().isEmpty()) { methodCode.beginControlFlow("try"); @@ -210,8 +210,8 @@ final class InternalCrossProfileClassGenerator { methodCode.addStatement(methodCall); methodCode.add("returnParcel.writeInt(0); // No errors\n"); methodCode.addStatement( - "bundler.writeToParcel(returnParcel, returnValue, $L, /* flags= */ 0)", - TypeUtils.generateBundlerType(method.returnType())); + "bundler.writeToParcel(returnParcel, returnValue, $L, /* flags= */ 0)", + TypeUtils.generateBundlerType(method.returnType())); } if (!method.thrownExceptions().isEmpty()) { @@ -219,7 +219,7 @@ final class InternalCrossProfileClassGenerator { methodCode.nextControlFlow("catch ($L e)", exceptionType); methodCode.add("returnParcel.writeInt(1); // Errors\n"); methodCode.addStatement( - "$T.writeThrowableToParcel(returnParcel, e)", PARCEL_UTILITIES_CLASSNAME); + "$T.writeThrowableToParcel(returnParcel, e)", PARCEL_UTILITIES_CLASSNAME); } methodCode.endControlFlow(); } @@ -227,23 +227,23 @@ final class InternalCrossProfileClassGenerator { methodCode.addStatement("return returnParcel"); classBuilder.addMethod( - MethodSpec.methodBuilder("method" + method.identifier()) - .addModifiers(Modifier.PRIVATE) - .returns(PARCEL_CLASSNAME) - .addParameter(CONTEXT_CLASSNAME, "context") - .addParameter(PARCEL_CLASSNAME, "params") - .addParameter(CROSS_PROFILE_CALLBACK_CLASSNAME, "callback") - .addCode(methodCode.build()) - .addJavadoc( - "Call $1L and return a {@link $2T} containing the return value.\n\n" - + "<p>The {@link $2T} must be recycled after use.\n", - GeneratorUtilities.methodJavadocReference(method.methodElement()), - PARCEL_CLASSNAME) - .build()); + MethodSpec.methodBuilder("method" + method.identifier()) + .addModifiers(Modifier.PRIVATE) + .returns(PARCEL_CLASSNAME) + .addParameter(CONTEXT_CLASSNAME, "context") + .addParameter(PARCEL_CLASSNAME, "params") + .addParameter(CROSS_PROFILE_CALLBACK_CLASSNAME, "callback") + .addCode(methodCode.build()) + .addJavadoc( + "Call $1L and return a {@link $2T} containing the return value.\n\n" + + "<p>The {@link $2T} must be recycled after use.\n", + GeneratorUtilities.methodJavadocReference(method.methodElement()), + PARCEL_CLASSNAME) + .build()); } private void addCrossProfileCallbackCrossProfileTypeMethod( - TypeSpec.Builder classBuilder, CrossProfileMethodInfo method) { + TypeSpec.Builder classBuilder, CrossProfileMethodInfo method) { CodeBlock.Builder methodCode = CodeBlock.builder(); // parcel is recycled by caller @@ -254,12 +254,12 @@ final class InternalCrossProfileClassGenerator { createCrossProfileCallbackParameter(methodCode, method); CodeBlock methodCall = - CodeBlock.of( - "$L.$L($L)", - getCrossProfileTypeReference(method), - method.simpleName(), - method.commaSeparatedParameters( - crossProfileType.supportedTypes(), REPLACE_AUTOMATICALLY_RESOLVED_PARAMETERS)); + CodeBlock.of( + "$L.$L($L)", + getCrossProfileTypeReference(method), + method.simpleName(), + method.commaSeparatedParameters( + crossProfileType.supportedTypes(), REPLACE_AUTOMATICALLY_RESOLVED_PARAMETERS)); if (isPrimitiveOrObjectVoid(method.returnType())) { methodCode.addStatement(methodCall); @@ -268,31 +268,31 @@ final class InternalCrossProfileClassGenerator { methodCode.addStatement(methodCall); methodCode.add("returnParcel.writeInt(0); // No errors\n"); methodCode.addStatement( - "bundler.writeToParcel(returnParcel, returnValue, $L, /* flags= */ 0)", - TypeUtils.generateBundlerType(method.returnType())); + "bundler.writeToParcel(returnParcel, returnValue, $L, /* flags= */ 0)", + TypeUtils.generateBundlerType(method.returnType())); } methodCode.addStatement("return returnParcel"); classBuilder.addMethod( - MethodSpec.methodBuilder("method" + method.identifier()) - .addModifiers(Modifier.PRIVATE) - .returns(PARCEL_CLASSNAME) - .addParameter(CONTEXT_CLASSNAME, "context") - .addParameter(PARCEL_CLASSNAME, "params") - // TODO: This should be renamed to "callback" once we prefix unpacked parameter names - // (without doing this, a param named "callback" will cause a compile error) - .addParameter(CROSS_PROFILE_CALLBACK_CLASSNAME, "crossProfileCallback") - .addCode(methodCode.build()) - .addJavadoc( - "Call $1L, and link the callback to {@code crossProfileCallback}.\n\n" - + "@return An empty parcel. This must be recycled after use.\n", - GeneratorUtilities.methodJavadocReference(method.methodElement())) - .build()); + MethodSpec.methodBuilder("method" + method.identifier()) + .addModifiers(Modifier.PRIVATE) + .returns(PARCEL_CLASSNAME) + .addParameter(CONTEXT_CLASSNAME, "context") + .addParameter(PARCEL_CLASSNAME, "params") + // TODO: This should be renamed to "callback" once we prefix unpacked parameter names + // (without doing this, a param named "callback" will cause a compile error) + .addParameter(CROSS_PROFILE_CALLBACK_CLASSNAME, "crossProfileCallback") + .addCode(methodCode.build()) + .addJavadoc( + "Call $1L, and link the callback to {@code crossProfileCallback}.\n\n" + + "@return An empty parcel. This must be recycled after use.\n", + GeneratorUtilities.methodJavadocReference(method.methodElement())) + .build()); } private void addFutureCrossProfileTypeMethod( - TypeSpec.Builder classBuilder, CrossProfileMethodInfo method) { + TypeSpec.Builder classBuilder, CrossProfileMethodInfo method) { CodeBlock.Builder methodCode = CodeBlock.builder(); // parcel is recycled by caller @@ -301,110 +301,110 @@ final class InternalCrossProfileClassGenerator { addExtractParametersCode(methodCode, method); CodeBlock methodCall = - CodeBlock.of( - "$L.$L($L)", - getCrossProfileTypeReference(method), - method.simpleName(), - method.commaSeparatedParameters( - crossProfileType.supportedTypes(), REPLACE_AUTOMATICALLY_RESOLVED_PARAMETERS)); + CodeBlock.of( + "$L.$L($L)", + getCrossProfileTypeReference(method), + method.simpleName(), + method.commaSeparatedParameters( + crossProfileType.supportedTypes(), REPLACE_AUTOMATICALLY_RESOLVED_PARAMETERS)); methodCode.addStatement("$T future = $L", method.returnType(), methodCall); TypeMirror rawFutureType = TypeUtils.removeTypeArguments(method.returnType()); FutureWrapper futureWrapper = - crossProfileType.supportedTypes().getType(rawFutureType).getFutureWrapper().get(); + crossProfileType.supportedTypes().getType(rawFutureType).getFutureWrapper().get(); // This assumes every Future is generic with one type argument TypeMirror wrappedReturnType = - TypeUtils.extractTypeArguments(method.returnType()).iterator().next(); + TypeUtils.extractTypeArguments(method.returnType()).iterator().next(); methodCode.addStatement( - "$T.writeFutureResult(future, new $T<>(callback, bundler, $L))", - futureWrapper.wrapperClassName(), - CROSS_PROFILE_FUTURE_RESULT_WRITER, - TypeUtils.generateBundlerType(wrappedReturnType)); + "$T.writeFutureResult(future, new $T<>(callback, bundler, $L))", + futureWrapper.wrapperClassName(), + CROSS_PROFILE_FUTURE_RESULT_WRITER, + TypeUtils.generateBundlerType(wrappedReturnType)); // TODO: Can this just return null? where does it go? that'd avoid having to obtain/recycle methodCode.addStatement("return returnParcel"); classBuilder.addMethod( - MethodSpec.methodBuilder("method" + method.identifier()) - .addModifiers(Modifier.PRIVATE) - .returns(PARCEL_CLASSNAME) - .addParameter(CONTEXT_CLASSNAME, "context") - .addParameter(PARCEL_CLASSNAME, "params") - .addParameter(CROSS_PROFILE_CALLBACK_CLASSNAME, "callback") - .addCode(methodCode.build()) - .addJavadoc( - "Call $1L, and link the returned future to {@code crossProfileCallback}.\n\n" - + "@return An empty parcel. This must be recycled after use.\n", - GeneratorUtilities.methodJavadocReference(method.methodElement())) - .build()); + MethodSpec.methodBuilder("method" + method.identifier()) + .addModifiers(Modifier.PRIVATE) + .returns(PARCEL_CLASSNAME) + .addParameter(CONTEXT_CLASSNAME, "context") + .addParameter(PARCEL_CLASSNAME, "params") + .addParameter(CROSS_PROFILE_CALLBACK_CLASSNAME, "callback") + .addCode(methodCode.build()) + .addJavadoc( + "Call $1L, and link the returned future to {@code crossProfileCallback}.\n\n" + + "@return An empty parcel. This must be recycled after use.\n", + GeneratorUtilities.methodJavadocReference(method.methodElement())) + .build()); } private void createCrossProfileCallbackParameter( - CodeBlock.Builder methodCode, CrossProfileMethodInfo method) { + CodeBlock.Builder methodCode, CrossProfileMethodInfo method) { VariableElement asyncCallbackParam = - method.getCrossProfileCallbackParam(generatorContext).get(); + method.getCrossProfileCallbackParam(generatorContext).get(); TypeElement callbackType = - generatorContext.elements().getTypeElement(asyncCallbackParam.asType().toString()); + generatorContext.elements().getTypeElement(asyncCallbackParam.asType().toString()); CrossProfileCallbackInterfaceInfo callbackInterface = - CrossProfileCallbackInterfaceInfo.create(callbackType); + CrossProfileCallbackInterfaceInfo.create(callbackType); methodCode.addStatement( - "$T $L = new $L(crossProfileCallback, bundler)", - asyncCallbackParam.asType(), - asyncCallbackParam.getSimpleName(), - CrossProfileCallbackCodeGenerator.getCrossProfileCallbackReceiverClassName( - generatorContext, callbackInterface)); + "$T $L = new $L(crossProfileCallback, bundler)", + asyncCallbackParam.asType(), + asyncCallbackParam.getSimpleName(), + CrossProfileCallbackCodeGenerator.getCrossProfileCallbackReceiverClassName( + generatorContext, callbackInterface)); } private static boolean isPrimitiveOrObjectVoid(TypeMirror typeMirror) { return typeMirror.getKind().equals(TypeKind.VOID) - || typeMirror.toString().equals("java.lang.Void"); + || typeMirror.toString().equals("java.lang.Void"); } private void addExtractParametersCode(CodeBlock.Builder code, CrossProfileMethodInfo method) { Optional<VariableElement> callbackParameter = - method.getCrossProfileCallbackParam(generatorContext); + method.getCrossProfileCallbackParam(generatorContext); for (VariableElement parameter : method.methodElement().getParameters()) { if (callbackParameter.isPresent() - && callbackParameter.get().getSimpleName().equals(parameter.getSimpleName())) { + && callbackParameter.get().getSimpleName().equals(parameter.getSimpleName())) { continue; // Don't extract a callback parameter } if (crossProfileType.supportedTypes().isAutomaticallyResolved(parameter.asType())) { continue; } code.addStatement( - "@SuppressWarnings(\"unchecked\") $1T $2L = ($1T) bundler.readFromParcel(params, $3L)", - parameter.asType(), - parameter.getSimpleName().toString(), - TypeUtils.generateBundlerType(parameter.asType())); + "@SuppressWarnings(\"unchecked\") $1T $2L = ($1T) bundler.readFromParcel(params, $3L)", + parameter.asType(), + parameter.getSimpleName().toString(), + TypeUtils.generateBundlerType(parameter.asType())); } } private static void addCallMethod(TypeSpec.Builder classBuilder) { classBuilder.addMethod( - MethodSpec.methodBuilder("call") - .addModifiers(Modifier.PUBLIC) - .returns(PARCEL_CLASSNAME) - .addParameter(CONTEXT_CLASSNAME, "context") - .addParameter(int.class, "methodIdentifier") - .addParameter(PARCEL_CLASSNAME, "params") - .addParameter(CROSS_PROFILE_CALLBACK_CLASSNAME, "callback") - .beginControlFlow("if (methodIdentifier >= methods.length)") - .addStatement( - "throw new $T(\"Invalid method identifier\" + methodIdentifier)", - IllegalArgumentException.class) - .endControlFlow() - .addStatement("return methods[methodIdentifier].call(context, params, callback)") - .addJavadoc( - "Call the method referenced by {@code methodIdentifier}.\n\n" - + "<p>If the method is synchronous, this will return a {@link $1T} containing" - + " the return value, otherwise it will return an empty {@link $1T}. The" - + " {@link $1T} must be recycled after use.\n", - PARCEL_CLASSNAME) - .build()); + MethodSpec.methodBuilder("call") + .addModifiers(Modifier.PUBLIC) + .returns(PARCEL_CLASSNAME) + .addParameter(CONTEXT_CLASSNAME, "context") + .addParameter(int.class, "methodIdentifier") + .addParameter(PARCEL_CLASSNAME, "params") + .addParameter(CROSS_PROFILE_CALLBACK_CLASSNAME, "callback") + .beginControlFlow("if (methodIdentifier >= methods.length)") + .addStatement( + "throw new $T(\"Invalid method identifier\" + methodIdentifier)", + IllegalArgumentException.class) + .endControlFlow() + .addStatement("return methods[methodIdentifier].call(context, params, callback)") + .addJavadoc( + "Call the method referenced by {@code methodIdentifier}.\n\n" + + "<p>If the method is synchronous, this will return a {@link $1T} containing" + + " the return value, otherwise it will return an empty {@link $1T}. The" + + " {@link $1T} must be recycled after use.\n", + PARCEL_CLASSNAME) + .build()); } private CodeBlock getCrossProfileTypeReference(CrossProfileMethodInfo method) { @@ -415,7 +415,7 @@ final class InternalCrossProfileClassGenerator { } static ClassName getInternalCrossProfileClassName( - GeneratorContext generatorContext, CrossProfileTypeInfo crossProfileType) { + GeneratorContext generatorContext, CrossProfileTypeInfo crossProfileType) { return GeneratorUtilities.appendToClassName(crossProfileType.profileClassName(), "_Internal"); } } diff --git a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/OtherProfileGenerator.java b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/OtherProfileGenerator.java index ace2f9e..08011ca 100644 --- a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/OtherProfileGenerator.java +++ b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/OtherProfileGenerator.java @@ -19,6 +19,7 @@ import static com.google.android.enterprise.connectedapps.processor.CommonClassN import static com.google.android.enterprise.connectedapps.processor.CommonClassNames.LOCAL_CALLBACK_CLASSNAME; import static com.google.android.enterprise.connectedapps.processor.CommonClassNames.PARCEL_CLASSNAME; import static com.google.android.enterprise.connectedapps.processor.CommonClassNames.PROFILE_CONNECTOR_CLASSNAME; +import static com.google.android.enterprise.connectedapps.processor.CommonClassNames.PROFILE_RUNTIME_EXCEPTION_CLASSNAME; import static com.google.android.enterprise.connectedapps.processor.CommonClassNames.UNAVAILABLE_PROFILE_EXCEPTION_CLASSNAME; import static com.google.android.enterprise.connectedapps.processor.containers.CrossProfileMethodInfo.AutomaticallyResolvedParameterFilterBehaviour.REMOVE_AUTOMATICALLY_RESOLVED_PARAMETERS; import static com.google.common.base.Preconditions.checkNotNull; @@ -209,9 +210,12 @@ final class OtherProfileGenerator { methodBuilder.addStatement("throw e"); } + methodBuilder.nextControlFlow("catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME); + methodBuilder.addStatement("throw e"); + methodBuilder.nextControlFlow("catch ($T e)", Throwable.class); methodBuilder.addStatement( - "throw new $T($S)", IllegalStateException.class, "Unexpected exception thrown"); + "throw new $T($S, e)", IllegalStateException.class, "Unexpected exception thrown"); methodBuilder.endControlFlow(); } diff --git a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/SupportedTypes.java b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/SupportedTypes.java index 1238b4b..254c455 100644 --- a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/SupportedTypes.java +++ b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/SupportedTypes.java @@ -50,8 +50,8 @@ public final class SupportedTypes { @Override public String toString() { return "SupportedTypes{" + - "usableTypes=" + usableTypes + - '}'; + "usableTypes=" + usableTypes + + '}'; } @Override @@ -84,16 +84,16 @@ public final class SupportedTypes { public static TypeCheckContext create() { return new AutoValue_SupportedTypes_TypeCheckContext.Builder() - .setWrapped(false) - .setOnCrossProfileCallbackInterface(false) - .build(); + .setWrapped(false) + .setOnCrossProfileCallbackInterface(false) + .build(); } public static TypeCheckContext createForCrossProfileCallbackInterface() { return new AutoValue_SupportedTypes_TypeCheckContext.Builder() - .setWrapped(false) - .setOnCrossProfileCallbackInterface(true) - .build(); + .setWrapped(false) + .setOnCrossProfileCallbackInterface(true) + .build(); } @AutoValue.Builder @@ -123,9 +123,6 @@ public final class SupportedTypes { if (TypeUtils.isGeneric(wrappedType)) { return false; // We don't support generic arrays } - if (wrappedType.getKind().isPrimitive()) { - return false; // We don't support primitive arrays - } if (TypeUtils.isArray(wrappedType)) { return false; // We don't support multidimensional arrays } @@ -133,8 +130,8 @@ public final class SupportedTypes { } return TypeUtils.isGeneric(type) - ? isValidGenericReturnType(type, context) - : isValidReturnType(get(type), context); + ? isValidGenericReturnType(type, context) + : isValidReturnType(get(type), context); } private static boolean isValidReturnType(@Nullable Type supportedType, TypeCheckContext context) { @@ -196,9 +193,6 @@ public final class SupportedTypes { if (TypeUtils.isGeneric(wrappedType)) { return false; // We don't support generic arrays } - if (wrappedType.getKind().isPrimitive()) { - return false; // We don't support primitive arrays - } if (TypeUtils.isArray(wrappedType)) { return false; // We don't support multidimensional arrays } @@ -219,8 +213,8 @@ public final class SupportedTypes { } return TypeUtils.isGeneric(type) - ? isValidGenericParameterType(type, context) - : isValidParameterType(get(type)); + ? isValidGenericParameterType(type, context) + : isValidParameterType(get(type)); } private static boolean isValidParameterType(Type supportedType) { @@ -261,7 +255,7 @@ public final class SupportedTypes { } throw new IllegalArgumentException( - String.format("%s can not write to parcel", type.getQualifiedName())); + String.format("%s can not write to parcel", type.getQualifiedName())); } CodeBlock generateReadFromParcelCode(String parcelName, Type type) { @@ -270,7 +264,7 @@ public final class SupportedTypes { } throw new IllegalArgumentException( - String.format("%s can not read from parcel", type.getQualifiedName())); + String.format("%s can not read from parcel", type.getQualifiedName())); } public Type getType(TypeMirror type) { @@ -287,11 +281,11 @@ public final class SupportedTypes { } public static SupportedTypes createFromMethods( - Types types, - Elements elements, - Collection<ParcelableWrapper> parcelableWrappers, - Collection<FutureWrapper> futureWrappers, - Collection<ExecutableElement> methods) { + Types types, + Elements elements, + Collection<ParcelableWrapper> parcelableWrappers, + Collection<FutureWrapper> futureWrappers, + Collection<ExecutableElement> methods) { Map<String, Type> usableTypes = new HashMap<>(); addDefaultTypes(types, elements, usableTypes); @@ -303,10 +297,10 @@ public final class SupportedTypes { } private static void addSupportForUsedTypes( - Types types, - Elements elements, - Map<String, Type> usableTypes, - Collection<ExecutableElement> methods) { + Types types, + Elements elements, + Map<String, Type> usableTypes, + Collection<ExecutableElement> methods) { for (ExecutableElement method : methods) { addSupportForUsedType(types, elements, usableTypes, method.getReturnType()); @@ -317,7 +311,7 @@ public final class SupportedTypes { } private static void addSupportForUsedType( - Types types, Elements elements, Map<String, Type> usableTypes, TypeMirror type) { + Types types, Elements elements, Map<String, Type> usableTypes, TypeMirror type) { if (TypeUtils.isArray(type)) { addSupportForUsedType(types, elements, usableTypes, TypeUtils.extractTypeFromArray(type)); if (!TypeUtils.extractTypeFromArray(type).getKind().isPrimitive()) { @@ -341,7 +335,7 @@ public final class SupportedTypes { // We don't support generic callbacks so any callback interfaces can be picked up here if (supportedType.isCrossProfileCallbackInterface()) { for (TypeMirror typeMirror : - supportedType.getCrossProfileCallbackInterface().get().argumentTypes()) { + supportedType.getCrossProfileCallbackInterface().get().argumentTypes()) { addSupportForUsedType(types, elements, usableTypes, typeMirror); } } @@ -350,11 +344,11 @@ public final class SupportedTypes { } private static void addSupportForGenericUsedType( - Types types, Elements elements, Map<String, Type> usableTypes, TypeMirror type) { + Types types, Elements elements, Map<String, Type> usableTypes, TypeMirror type) { TypeMirror genericType = TypeUtils.removeTypeArguments(type); Optional<Type> optionalSupportedType = - getSupportedType(types, elements, usableTypes, genericType); + getSupportedType(types, elements, usableTypes, genericType); if (!optionalSupportedType.isPresent()) { // The base type isn't supported return; @@ -372,7 +366,7 @@ public final class SupportedTypes { } private static Optional<Type> getSupportedType( - Types types, Elements elements, Map<String, Type> usableTypes, TypeMirror type) { + Types types, Elements elements, Map<String, Type> usableTypes, TypeMirror type) { if (usableTypes.containsKey(type.toString())) { return Optional.of(usableTypes.get(type.toString())); } @@ -399,37 +393,37 @@ public final class SupportedTypes { private static Type createCrossProfileCallbackType(TypeElement type) { return Type.builder() - .setTypeMirror(type.asType()) - .setAcceptableReturnType(false) - .setAcceptableParameterType(true) - .setSupportedInsideWrapper(false) - .setSupportedInsideCrossProfileCallback(false) - .setCrossProfileCallbackInterface(CrossProfileCallbackInterfaceInfo.create(type)) - .build(); + .setTypeMirror(type.asType()) + .setAcceptableReturnType(false) + .setAcceptableParameterType(true) + .setSupportedInsideWrapper(false) + .setSupportedInsideCrossProfileCallback(false) + .setCrossProfileCallbackInterface(CrossProfileCallbackInterfaceInfo.create(type)) + .build(); } private static Type createParcelableType(TypeMirror typeMirror) { return Type.builder() - .setTypeMirror(typeMirror) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeParcelable($L, flags)") - .setReadFromParcelCode("$L.readParcelable(Bundler.class.getClassLoader())") - // Parcelables must take care of their own generic types - .setSupportedWithAnyGenericType(true) - .build(); + .setTypeMirror(typeMirror) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeParcelable($L, flags)") + .setReadFromParcelCode("$L.readParcelable(Bundler.class.getClassLoader())") + // Parcelables must take care of their own generic types + .setSupportedWithAnyGenericType(true) + .build(); } private static Type createSerializableType(TypeMirror typeMirror) { return Type.builder() - .setTypeMirror(typeMirror) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeSerializable($L)") - .setReadFromParcelCode("$L.readSerializable()") - // Serializables must take care of their own generic types - .setSupportedWithAnyGenericType(true) - .build(); + .setTypeMirror(typeMirror) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeSerializable($L)") + .setReadFromParcelCode("$L.readSerializable()") + // Serializables must take care of their own generic types + .setSupportedWithAnyGenericType(true) + .build(); } /** Create a {@link Builder} to create a new {@link SupportedTypes} with modified entries. */ @@ -438,184 +432,193 @@ public final class SupportedTypes { } private static void addDefaultTypes( - Types types, Elements elements, Map<String, Type> usableTypes) { + Types types, Elements elements, Map<String, Type> usableTypes) { addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.getNoType(TypeKind.VOID)) - .setAcceptableReturnType(true) - .setReadFromParcelCode("null") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.getNoType(TypeKind.VOID)) + .setAcceptableReturnType(true) + .setReadFromParcelCode("null") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(elements.getTypeElement("java.lang.Void").asType()) - .setAcceptableReturnType(true) - .setReadFromParcelCode("null") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(elements.getTypeElement("java.lang.Void").asType()) + .setAcceptableReturnType(true) + .setReadFromParcelCode("null") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(elements.getTypeElement("java.lang.String").asType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeString($L)") - .setReadFromParcelCode("$L.readString()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(elements.getTypeElement("java.lang.String").asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeString($L)") + .setReadFromParcelCode("$L.readString()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.getPrimitiveType(TypeKind.BYTE)) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeByte($L)") - .setReadFromParcelCode("$L.readByte()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(elements.getTypeElement("java.lang.CharSequence").asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeString(String.valueOf($L))") + .setReadFromParcelCode("$L.readString()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.BYTE)).asType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeByte($L)") - .setReadFromParcelCode("$L.readByte()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.getPrimitiveType(TypeKind.BYTE)) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeByte($L)") + .setReadFromParcelCode("$L.readByte()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.getPrimitiveType(TypeKind.SHORT)) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeInt($L)") - .setReadFromParcelCode("(short)$L.readInt()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.BYTE)).asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeByte($L)") + .setReadFromParcelCode("$L.readByte()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.SHORT)).asType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeInt($L)") - .setReadFromParcelCode("(short)$L.readInt()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.getPrimitiveType(TypeKind.SHORT)) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeInt($L)") + .setReadFromParcelCode("(short)$L.readInt()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.getPrimitiveType(TypeKind.INT)) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeInt($L)") - .setReadFromParcelCode("$L.readInt()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.SHORT)).asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeInt($L)") + .setReadFromParcelCode("(short)$L.readInt()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.INT)).asType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeInt($L)") - .setReadFromParcelCode("$L.readInt()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.getPrimitiveType(TypeKind.INT)) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeInt($L)") + .setReadFromParcelCode("$L.readInt()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.getPrimitiveType(TypeKind.LONG)) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeLong($L)") - .setReadFromParcelCode("$L.readLong()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.INT)).asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeInt($L)") + .setReadFromParcelCode("$L.readInt()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.LONG)).asType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeLong($L)") - .setReadFromParcelCode("$L.readLong()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.getPrimitiveType(TypeKind.LONG)) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeLong($L)") + .setReadFromParcelCode("$L.readLong()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.getPrimitiveType(TypeKind.FLOAT)) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeFloat($L)") - .setReadFromParcelCode("$L.readFloat()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.LONG)).asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeLong($L)") + .setReadFromParcelCode("$L.readLong()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.FLOAT)).asType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeFloat($L)") - .setReadFromParcelCode("$L.readFloat()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.getPrimitiveType(TypeKind.FLOAT)) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeFloat($L)") + .setReadFromParcelCode("$L.readFloat()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.getPrimitiveType(TypeKind.DOUBLE)) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeDouble($L)") - .setReadFromParcelCode("$L.readDouble()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.FLOAT)).asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeFloat($L)") + .setReadFromParcelCode("$L.readFloat()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.DOUBLE)).asType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeDouble($L)") - .setReadFromParcelCode("$L.readDouble()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.getPrimitiveType(TypeKind.DOUBLE)) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeDouble($L)") + .setReadFromParcelCode("$L.readDouble()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.getPrimitiveType(TypeKind.CHAR)) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeInt($L)") - .setReadFromParcelCode("(char)$L.readInt()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.DOUBLE)).asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeDouble($L)") + .setReadFromParcelCode("$L.readDouble()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.CHAR)).asType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeInt($L)") - .setReadFromParcelCode("(char)$L.readInt()") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.getPrimitiveType(TypeKind.CHAR)) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeInt($L)") + .setReadFromParcelCode("(char)$L.readInt()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.getPrimitiveType(TypeKind.BOOLEAN)) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeInt($L ? 1 : 0)") - .setReadFromParcelCode("($L.readInt() == 1)") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.CHAR)).asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeInt($L)") + .setReadFromParcelCode("(char)$L.readInt()") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.BOOLEAN)).asType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeInt($L ? 1 : 0)") - .setReadFromParcelCode("($L.readInt() == 1)") - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.getPrimitiveType(TypeKind.BOOLEAN)) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeInt($L ? 1 : 0)") + .setReadFromParcelCode("($L.readInt() == 1)") + .build()); addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(elements.getTypeElement("android.content.Context").asType()) - .setAcceptableParameterType(true) - .setAutomaticallyResolvedReplacement("context") - .setAcceptableReturnType(false) - .setSupportedInsideWrapper(false) - .setSupportedInsideCrossProfileCallback(false) - .build()); + usableTypes, + Type.builder() + .setTypeMirror(types.boxedClass(types.getPrimitiveType(TypeKind.BOOLEAN)).asType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeInt($L ? 1 : 0)") + .setReadFromParcelCode("($L.readInt() == 1)") + .build()); + addUsableType( + usableTypes, + Type.builder() + .setTypeMirror(elements.getTypeElement("android.content.Context").asType()) + .setAcceptableParameterType(true) + .setAutomaticallyResolvedReplacement("context") + .setAcceptableReturnType(false) + .setSupportedInsideWrapper(false) + .setSupportedInsideCrossProfileCallback(false) + .build()); } private static void addUsableType(Map<String, Type> usableTypes, Type type) { @@ -623,49 +626,49 @@ public final class SupportedTypes { } private static void addParcelableWrapperTypes( - Map<String, Type> usableTypes, Collection<ParcelableWrapper> parcelableWrappers) { + Map<String, Type> usableTypes, Collection<ParcelableWrapper> parcelableWrappers) { for (ParcelableWrapper parcelableWrapper : parcelableWrappers) { addParcelableWrapperType(usableTypes, parcelableWrapper); } } private static void addParcelableWrapperType( - Map<String, Type> usableTypes, ParcelableWrapper parcelableWrapper) { + Map<String, Type> usableTypes, ParcelableWrapper parcelableWrapper) { String createParcelableCode = parcelableWrapper.wrapperClassName() + ".of(this, valueType, $L)"; // "this" will be a Bundler as this code is only run within a Bundler addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(parcelableWrapper.wrappedType()) - .setAcceptableReturnType(true) - .setAcceptableParameterType(true) - .setWriteToParcelCode("$L.writeParcelable(" + createParcelableCode + ", flags)") - .setReadFromParcelCode( - "((" - + parcelableWrapper.wrapperClassName() - + ") $L.readParcelable(Bundler.class.getClassLoader())).get()") - .setParcelableWrapper(parcelableWrapper) - .build()); + usableTypes, + Type.builder() + .setTypeMirror(parcelableWrapper.wrappedType()) + .setAcceptableReturnType(true) + .setAcceptableParameterType(true) + .setWriteToParcelCode("$L.writeParcelable(" + createParcelableCode + ", flags)") + .setReadFromParcelCode( + "((" + + parcelableWrapper.wrapperClassName() + + ") $L.readParcelable(Bundler.class.getClassLoader())).get()") + .setParcelableWrapper(parcelableWrapper) + .build()); } private static void addFutureWrapperTypes( - Map<String, Type> usableTypes, Collection<FutureWrapper> futureWrappers) { + Map<String, Type> usableTypes, Collection<FutureWrapper> futureWrappers) { for (FutureWrapper futureWrapper : futureWrappers) { addFutureWrapperType(usableTypes, futureWrapper); } } private static void addFutureWrapperType( - Map<String, Type> usableTypes, FutureWrapper futureWrapper) { + Map<String, Type> usableTypes, FutureWrapper futureWrapper) { addUsableType( - usableTypes, - Type.builder() - .setTypeMirror(futureWrapper.wrappedType()) - .setAcceptableReturnType(true) - .setSupportedInsideWrapper(false) - .setFutureWrapper(futureWrapper) - .build()); + usableTypes, + Type.builder() + .setTypeMirror(futureWrapper.wrappedType()) + .setAcceptableReturnType(true) + .setSupportedInsideWrapper(false) + .setFutureWrapper(futureWrapper) + .build()); } public static final class Builder { @@ -678,7 +681,7 @@ public final class SupportedTypes { /** Filtering to only include used types. */ public Builder filterUsed( - ValidatorContext context, Collection<CrossProfileMethodInfo> methods) { + ValidatorContext context, Collection<CrossProfileMethodInfo> methods) { Map<String, Type> usedTypes = new HashMap<>(); @@ -692,7 +695,7 @@ public final class SupportedTypes { } private void copySupportedTypesForMethod( - ValidatorContext context, Map<String, Type> usedTypes, CrossProfileMethodInfo method) { + ValidatorContext context, Map<String, Type> usedTypes, CrossProfileMethodInfo method) { copySupportedType(context, usedTypes, method.returnType()); for (TypeMirror argumentType : method.parameterTypes()) { copySupportedType(context, usedTypes, argumentType); @@ -700,7 +703,7 @@ public final class SupportedTypes { } private void copySupportedType( - ValidatorContext context, Map<String, Type> usedTypes, TypeMirror type) { + ValidatorContext context, Map<String, Type> usedTypes, TypeMirror type) { if (TypeUtils.isGeneric(type)) { copySupportedGenericType(context, usedTypes, type); return; @@ -710,9 +713,9 @@ public final class SupportedTypes { copySupportedType(context, usedTypes, TypeUtils.extractTypeFromArray(type)); if (!TypeUtils.extractTypeFromArray(type).getKind().isPrimitive()) { type = - context - .types() - .getArrayType(context.elements().getTypeElement("java.lang.Object").asType()); + context + .types() + .getArrayType(context.elements().getTypeElement("java.lang.Object").asType()); } } @@ -723,7 +726,7 @@ public final class SupportedTypes { // We don't support generic callbacks so any callback interfaces can be picked up here if (supportedType.isCrossProfileCallbackInterface()) { for (TypeMirror typeMirror : - supportedType.getCrossProfileCallbackInterface().get().argumentTypes()) { + supportedType.getCrossProfileCallbackInterface().get().argumentTypes()) { copySupportedType(context, usedTypes, typeMirror); } } @@ -736,7 +739,7 @@ public final class SupportedTypes { } private void copySupportedGenericType( - ValidatorContext context, Map<String, Type> usedTypes, TypeMirror type) { + ValidatorContext context, Map<String, Type> usedTypes, TypeMirror type) { TypeMirror genericType = TypeUtils.removeTypeArguments(type); // The type must have been seen in when constructing the oldSupportedTypes so this should not @@ -794,7 +797,7 @@ public final class SupportedTypes { } private void replaceParcelableWrapperPrefix( - Map<String, Type> newUsableTypes, ClassName prefix, Type usableType) { + Map<String, Type> newUsableTypes, ClassName prefix, Type usableType) { ParcelableWrapper parcelableWrapper = usableType.getParcelableWrapper().get(); if (parcelableWrapper.wrapperType().equals(ParcelableWrapper.WrapperType.CUSTOM)) { @@ -804,16 +807,16 @@ public final class SupportedTypes { } addParcelableWrapperType( - newUsableTypes, - ParcelableWrapper.create( - parcelableWrapper.wrappedType(), - parcelableWrapper.defaultWrapperClassName(), - prefix(prefix, parcelableWrapper.wrapperClassName()), - parcelableWrapper.wrapperType())); + newUsableTypes, + ParcelableWrapper.create( + parcelableWrapper.wrappedType(), + parcelableWrapper.defaultWrapperClassName(), + prefix(prefix, parcelableWrapper.wrapperClassName()), + parcelableWrapper.wrapperType())); } private void replaceFutureWrapperPrefix( - Map<String, Type> newUsableTypes, ClassName prefix, Type usableType) { + Map<String, Type> newUsableTypes, ClassName prefix, Type usableType) { FutureWrapper futureWrapper = usableType.getFutureWrapper().get(); if (futureWrapper.wrapperType().equals(FutureWrapper.WrapperType.CUSTOM)) { @@ -823,17 +826,17 @@ public final class SupportedTypes { } addFutureWrapperType( - newUsableTypes, - FutureWrapper.create( - futureWrapper.wrappedType(), - futureWrapper.defaultWrapperClassName(), - prefix(prefix, futureWrapper.wrapperClassName()), - futureWrapper.wrapperType())); + newUsableTypes, + FutureWrapper.create( + futureWrapper.wrappedType(), + futureWrapper.defaultWrapperClassName(), + prefix(prefix, futureWrapper.wrapperClassName()), + futureWrapper.wrapperType())); } private ClassName prefix(ClassName prefix, ClassName finalName) { return ClassName.get( - prefix.packageName(), prefix.simpleName() + "_" + finalName.simpleName()); + prefix.packageName(), prefix.simpleName() + "_" + finalName.simpleName()); } /** Build a new {@link SupportedTypes}. */ diff --git a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/TypeUtils.java b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/TypeUtils.java index 6d5d073..ffa68c9 100644 --- a/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/TypeUtils.java +++ b/processor/src/main/java/com/google/android/enterprise/connectedapps/processor/TypeUtils.java @@ -95,18 +95,25 @@ public class TypeUtils { private static CodeBlock generateArrayBundlerType(TypeMirror type) { TypeMirror arrayType = extractTypeFromArray(type); + if (arrayType.getKind().isPrimitive()) { + return CodeBlock.of( + "$T.of($S)", + BUNDLER_TYPE_CLASSNAME, + arrayType.toString() + "[]"); + } + return CodeBlock.of( - "$T.of($S, $L)", - BUNDLER_TYPE_CLASSNAME, - "java.lang.Object[]", - generateBundlerType(arrayType)); + "$T.of($S, $L)", + BUNDLER_TYPE_CLASSNAME, + "java.lang.Object[]", + generateBundlerType(arrayType)); } private static CodeBlock generateGenericBundlerType(TypeMirror type) { CodeBlock.Builder typeArgs = CodeBlock.builder(); List<CodeBlock> typeArgBlocks = - extractTypeArguments(type).stream().map(TypeUtils::generateBundlerType).collect(toList()); + extractTypeArguments(type).stream().map(TypeUtils::generateBundlerType).collect(toList()); typeArgs.add(typeArgBlocks.get(0)); for (CodeBlock typeArgBlock : typeArgBlocks.subList(1, typeArgBlocks.size())) { @@ -114,7 +121,7 @@ public class TypeUtils { } return CodeBlock.of( - "$T.of($S, $L)", BUNDLER_TYPE_CLASSNAME, getRawTypeQualifiedName(type), typeArgs.build()); + "$T.of($S, $L)", BUNDLER_TYPE_CLASSNAME, getRawTypeQualifiedName(type), typeArgs.build()); } private TypeUtils() {} diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/AbstractProfileConnector.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/AbstractProfileConnector.java index ae24257..cc71c7b 100644 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/AbstractProfileConnector.java +++ b/sdk/src/main/java/com/google/android/enterprise/connectedapps/AbstractProfileConnector.java @@ -110,7 +110,6 @@ public abstract class AbstractProfileConnector /* availabilityListener= */ this, scheduledExecutorService, availabilityRestrictions); - crossProfileSender.beginMonitoringAvailabilityChanges(); } return crossProfileSender; } diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/CrossProfileSender.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/CrossProfileSender.java index fe34d09..9cc287b 100644 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/CrossProfileSender.java +++ b/sdk/src/main/java/com/google/android/enterprise/connectedapps/CrossProfileSender.java @@ -18,6 +18,9 @@ package com.google.android.enterprise.connectedapps; import static com.google.android.enterprise.connectedapps.CrossProfileSDKUtilities.filterUsersByAvailabilityRestrictions; import static com.google.android.enterprise.connectedapps.CrossProfileSDKUtilities.selectUserHandleToBind; +import static java.util.Collections.newSetFromMap; +import static java.util.Collections.synchronizedSet; + import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -27,6 +30,7 @@ import android.content.ServiceConnection; import android.content.pm.CrossProfileApps; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; +import android.os.Bundle; import android.os.IBinder; import android.os.Looper; import android.os.Parcel; @@ -41,8 +45,13 @@ import com.google.android.enterprise.connectedapps.internal.CrossProfileParcelCa import com.google.android.enterprise.connectedapps.internal.ParcelCallReceiver; import com.google.android.enterprise.connectedapps.internal.ParcelUtilities; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ScheduledExecutorService; @@ -238,6 +247,11 @@ public class CrossProfileSender { @Nullable private volatile ScheduledFuture<Void> automaticDisconnectionFuture; private final AvailabilityRestrictions availabilityRestrictions; + // This is synchronized which isn't massively performant but it only gets accessed once straight + // after creating a Sender, and once each time availability changes + private static final Set<CrossProfileSender> senders = + synchronizedSet(newSetFromMap(new WeakHashMap<>())); + private boolean isManuallyManagingConnection = false; private ConcurrentLinkedDeque<OngoingCrossProfileCall> ongoingCrossProfileCalls = new ConcurrentLinkedDeque<>(); @@ -277,13 +291,18 @@ public class CrossProfileSender { canUseReflectedApis = ReflectionUtilities.canUseReflectedApis(); this.scheduledExecutorService = scheduledExecutorService; this.availabilityRestrictions = availabilityRestrictions; + + senders.add(this); + beginMonitoringAvailabilityChanges(); } - private final BroadcastReceiver profileAvailabilityReceiver = + private static final BroadcastReceiver profileAvailabilityReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - checkAvailability(); + for (CrossProfileSender sender : senders) { + sender.scheduledExecutorService.execute(sender::checkAvailability); + } } }; @@ -370,7 +389,13 @@ public class CrossProfileSender { return null; } - void beginMonitoringAvailabilityChanges() { + private static final AtomicBoolean isMonitoringAvailabilityChanges = new AtomicBoolean(false); + + private void beginMonitoringAvailabilityChanges() { + if (isMonitoringAvailabilityChanges.getAndSet(true)) { + return; + } + IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED); filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); @@ -593,10 +618,17 @@ public class CrossProfileSender { * @throws UnavailableProfileException if a connection is not already established */ public Parcel call(long crossProfileTypeIdentifier, int methodIdentifier, Parcel params) - throws UnavailableProfileException { + throws UnavailableProfileException { try { return callWithExceptions(crossProfileTypeIdentifier, methodIdentifier, params); - } catch (UnavailableProfileException | RuntimeException e) { + } catch (UnavailableProfileException | RuntimeException | Error e) { + StackTraceElement[] remoteStack = e.getStackTrace(); + StackTraceElement[] localStack = Thread.currentThread().getStackTrace(); + StackTraceElement[] totalStack = + Arrays.copyOf(remoteStack, remoteStack.length + localStack.length - 1); + // We cut off the first element of localStack as it is just getting the stack trace + System.arraycopy(localStack, 1, totalStack, remoteStack.length, localStack.length - 1); + e.setStackTrace(totalStack); throw e; } catch (Throwable e) { throw new UnavailableProfileException("Unexpected checked exception", e); diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/exceptions/ProfileRuntimeException.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/exceptions/ProfileRuntimeException.java index 6ea9005..511a77a 100644 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/exceptions/ProfileRuntimeException.java +++ b/sdk/src/main/java/com/google/android/enterprise/connectedapps/exceptions/ProfileRuntimeException.java @@ -16,12 +16,12 @@ package com.google.android.enterprise.connectedapps.exceptions; /** - * Thrown when a {@link RuntimeException} is thrown during a cross-profile call. + * Thrown when a {@link Throwable} is thrown during a cross-profile call. * * <p>To get the original exception, call {@link #getCause()}. */ public class ProfileRuntimeException extends RuntimeException { - public ProfileRuntimeException(RuntimeException cause) { + public ProfileRuntimeException(Throwable cause) { super(cause); } } diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/BackgroundExceptionThrower.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/BackgroundExceptionThrower.java index 0999a35..9511e19 100644 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/BackgroundExceptionThrower.java +++ b/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/BackgroundExceptionThrower.java @@ -24,15 +24,23 @@ public final class BackgroundExceptionThrower { private BackgroundExceptionThrower() {} private static class ThrowingRunnable implements Runnable { - RuntimeException throwable; + RuntimeException runtimeException; + Error error; - ThrowingRunnable(RuntimeException throwable) { - this.throwable = throwable; + ThrowingRunnable(RuntimeException runtimeException) { + this.runtimeException = runtimeException; + } + + ThrowingRunnable(Error error) { + this.error = error; } @Override public void run() { - throw throwable; + if (error != null) { + throw error; + } + throw runtimeException; } } @@ -41,4 +49,10 @@ public final class BackgroundExceptionThrower { // We add a small delay to ensure that the return can be completed before crashing new Handler(Looper.getMainLooper()).postDelayed(new ThrowingRunnable(throwable), 1000); } + + /** Throw the given {@link Error} after a delay on the main looper. */ + public static void throwInBackground(Error throwable) { + // We add a small delay to ensure that the return can be completed before crashing + new Handler(Looper.getMainLooper()).postDelayed(new ThrowingRunnable(throwable), 1000); + } } |