1 /* 2 * Copyright (C) 2022 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 17 package com.android.adservices.service.js; 18 19 import static com.android.adservices.service.js.JSScriptEngineCommonConstants.WASM_MODULE_ARG_NAME; 20 import static com.android.adservices.service.js.JSScriptEngineCommonConstants.WASM_MODULE_BYTES_ID; 21 22 import android.annotation.NonNull; 23 24 import java.util.List; 25 import java.util.stream.Collectors; 26 27 /** Helper method for generating code. */ 28 public final class JSScriptEngineCommonCodeGenerator { 29 30 /** 31 * @return The JS code for the definition an anonymous function containing the declaration of 32 * the value of {@code args} and the invocation of the given {@code entryFunctionName}. If 33 * the {@code addWasmBinary} parameter is true, the target function is expected to accept an 34 * extra final parameter 'wasmModule' of type {@code WebAssembly.Module} and the method will 35 * return a promise. 36 */ 37 @NonNull generateEntryPointCallingCode( @onNull List<JSScriptArgument> args, @NonNull String entryFunctionName, boolean addWasmBinary)38 public static String generateEntryPointCallingCode( 39 @NonNull List<JSScriptArgument> args, 40 @NonNull String entryFunctionName, 41 boolean addWasmBinary) { 42 StringBuilder resultBuilder = new StringBuilder("(function() {\n"); 43 // Declare args as constant inside this function closure to avoid any direct access by 44 // the functions in the script we are calling. 45 for (JSScriptArgument arg : args) { 46 // Avoiding to use addJavaScriptInterface because too expensive, just 47 // declaring the string parameter as part of the script. 48 resultBuilder.append(arg.variableDeclaration()); 49 resultBuilder.append("\n"); 50 } 51 52 String argumentPassing = 53 args.stream().map(JSScriptArgument::name).collect(Collectors.joining(",")); 54 if (addWasmBinary) { 55 argumentPassing += "," + WASM_MODULE_ARG_NAME; 56 resultBuilder.append( 57 String.format( 58 "return android.consumeNamedDataAsArrayBuffer(\"%s\")" 59 + ".then((__value) => {\n" 60 + " return WebAssembly.compile(__value).then((%s) => {\n", 61 WASM_MODULE_BYTES_ID, WASM_MODULE_ARG_NAME)); 62 } 63 64 // Call entryFunctionName with the constants just declared as parameters 65 resultBuilder.append( 66 String.format( 67 "return JSON.stringify(%s(%s));\n", entryFunctionName, argumentPassing)); 68 69 if (addWasmBinary) { 70 resultBuilder.append("})});\n"); 71 } 72 resultBuilder.append("})();\n"); 73 74 return resultBuilder.toString(); 75 } 76 } 77