blob: 0ebd277026e107149967bcdcebca74b3ae9baab4 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.utils.chre;
import android.app.Instrumentation;
import android.content.Context;
import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubManager;
import android.hardware.location.ContextHubTransaction;
import android.hardware.location.NanoAppBinary;
import android.hardware.location.NanoAppState;
import android.os.ParcelFileDescriptor;
import androidx.test.InstrumentationRegistry;
import org.junit.Assert;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* A set of helper functions for PTS CHRE tests.
*/
public class ChreTestUtil {
// Various timeouts for Context Hub operations.
private static final long TIMEOUT_LOAD_NANOAPP_SECONDS = 5;
private static final long TIMEOUT_UNLOAD_NANOAPP_SECONDS = 5;
private static final long QUERY_NANOAPPS_TIMEOUT_SECONDS = 5;
/**
* Read the nanoapp to an InputStream object.
*
* @param context the Context to find the asset resources
* @param fileName the fileName of the nanoapp
* @return the InputStream of the nanoapp
*/
public static InputStream getNanoAppInputStream(Context context, String fileName) {
InputStream inputStream = null;
try {
inputStream = context.getAssets().open(fileName);
} catch (IOException e) {
Assert.fail("Could not find asset " + fileName + ": " + e.toString());
}
return inputStream;
}
/**
* Creates a NanoAppBinary object from the nanoapp fileName.
*
* @param fileName the fileName of the nanoapp
* @return the NanoAppBinary object
*/
public static NanoAppBinary createNanoAppBinary(String fileName) {
Context context = InstrumentationRegistry.getTargetContext();
InputStream stream = getNanoAppInputStream(context, fileName);
byte[] binary = null;
try {
binary = new byte[stream.available()];
stream.read(binary);
} catch (IOException e) {
Assert.fail("IOException while reading binary for " + fileName + ": " + e.getMessage());
}
return new NanoAppBinary(binary);
}
/**
* Loads a nanoapp.
*
* @param manager The ContextHubManager to use to load the nanoapp.
* @param info The ContextHubInfo describing the Context Hub to load the nanoapp to.
* @param nanoAppBinary The nanoapp binary to load.
* @return true if the load succeeded.
*/
public static boolean loadNanoApp(
ContextHubManager manager, ContextHubInfo info, NanoAppBinary nanoAppBinary) {
ContextHubTransaction<Void> txn = manager.loadNanoApp(info, nanoAppBinary);
ContextHubTransaction.Response<Void> resp = null;
try {
resp = txn.waitForResponse(TIMEOUT_LOAD_NANOAPP_SECONDS, TimeUnit.SECONDS);
} catch (TimeoutException | InterruptedException e) {
Assert.fail(e.getMessage());
}
return resp != null && resp.getResult() == ContextHubTransaction.RESULT_SUCCESS;
}
/**
* Same as loadNanoApp(), but asserts that it succeeds.
*/
public static void loadNanoAppAssertSuccess(
ContextHubManager manager, ContextHubInfo info, NanoAppBinary nanoAppBinary) {
if (!loadNanoApp(manager, info, nanoAppBinary)) {
Assert.fail("Failed to load nanoapp");
}
}
/**
* Unloads a nanoapp.
*
* @param manager The ContextHubManager to use to unload the nanoapp.
* @param info The ContextHubInfo describing the Context Hub to unload the nanoapp from.
* @param nanoAppId The 64-bit ID of the nanoapp to unload.
* @return true if the unload succeeded.
*/
public static boolean unloadNanoApp(
ContextHubManager manager, ContextHubInfo info, long nanoAppId) {
ContextHubTransaction<Void> txn = manager.unloadNanoApp(info, nanoAppId);
ContextHubTransaction.Response<Void> resp = null;
try {
resp = txn.waitForResponse(TIMEOUT_UNLOAD_NANOAPP_SECONDS, TimeUnit.SECONDS);
} catch (TimeoutException | InterruptedException e) {
Assert.fail(e.getMessage());
}
return resp != null && resp.getResult() == ContextHubTransaction.RESULT_SUCCESS;
}
/**
* Same as unloadNanoApp(), but asserts that it succeeds.
*/
public static void unloadNanoAppAssertSuccess(
ContextHubManager manager, ContextHubInfo info, long nanoAppId) {
if (!unloadNanoApp(manager, info, nanoAppId)) {
Assert.fail("Failed to unload nanoapp");
}
}
/**
* Executes a given shell command.
*
* @param instrumentation The instrumentation to use.
* @param command The shell command to execute.
* @return The string output.
*/
public static String executeShellCommand(Instrumentation instrumentation, String command) {
final ParcelFileDescriptor pfd = instrumentation.getUiAutomation()
.executeShellCommand(command);
StringBuilder out = new StringBuilder();
try (InputStream in = new FileInputStream(pfd.getFileDescriptor())) {
BufferedReader br = new BufferedReader(new InputStreamReader(in,
StandardCharsets.UTF_8));
String str = null;
while ((str = br.readLine()) != null) {
out.append(str);
}
closeOrAssert(br);
} catch (IOException e) {
Assert.fail(e.getMessage());
}
closeOrAssert(pfd);
return out.toString();
}
/**
* @param input The string input of an integer.
* @return The converted integer.
*/
public static int convertToIntegerOrFail(String input) {
try {
return Integer.parseInt(input);
} catch (NumberFormatException e) {
Assert.fail(e.getMessage());
}
return -1;
}
/**
* Get all the nanoapps currently loaded on device.
*
* @return The nanoapps loaded currently.
*/
public static List<NanoAppState> queryNanoAppsAssertSuccess(
ContextHubManager contextHubManager, ContextHubInfo contextHubInfo) {
ContextHubTransaction<List<NanoAppState>> transaction =
contextHubManager.queryNanoApps(contextHubInfo);
assertTransactionSuccessSync(transaction, QUERY_NANOAPPS_TIMEOUT_SECONDS);
ContextHubTransaction.Response<List<NanoAppState>> response = null;
try {
response = transaction.waitForResponse(QUERY_NANOAPPS_TIMEOUT_SECONDS,
TimeUnit.SECONDS);
} catch (InterruptedException e) {
Assert.fail("InterruptedException while getting query response");
} catch (TimeoutException e) {
Assert.fail("TimeoutException while getting query response");
}
return response.getContents();
}
/**
* Queries for the nanoapp version.
*
* @param contextHubManager The ContextHubManager to use.
* @param contextHubInfo The ContextHubInfo describing the Context Hub to query.
* @param nanoAppId The ID of the nanoapp to get the version for.
* @return The nanoapp version.
*/
public static int getNanoAppVersion(ContextHubManager contextHubManager,
ContextHubInfo contextHubInfo, long nanoAppId) {
List<NanoAppState> stateList = queryNanoAppsAssertSuccess(contextHubManager,
contextHubInfo);
for (NanoAppState state : stateList) {
if (state.getNanoAppId() == nanoAppId) {
return (int) state.getNanoAppVersion();
}
}
Assert.fail("Could not query for nanoapp with ID 0x" + Long.toHexString(nanoAppId));
return -1;
}
/**
* @param closeable The object to close.
*/
private static void closeOrAssert(AutoCloseable closeable) {
try {
closeable.close();
} catch (Exception e) {
Assert.fail(e.getMessage());
}
}
/**
* Assert that the context hub transaction gets a successful response.
*
* @param transaction The context hub transaction
* @param timeoutInSeconds The timeout while waiting for the transaction response in seconds
*/
private static void assertTransactionSuccessSync(
ContextHubTransaction<?> transaction, long timeoutInSeconds) throws AssertionError {
if (transaction == null) {
Assert.fail("ContextHubTransaction cannot be null");
}
String type = ContextHubTransaction.typeToString(transaction.getType(),
true /* upperCase */);
ContextHubTransaction.Response<?> response = null;
try {
response = transaction.waitForResponse(timeoutInSeconds, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Assert.fail("InterruptedException while waiting for " + type + " transaction");
} catch (TimeoutException e) {
Assert.fail("TimeoutException while waiting for " + type + " transaction");
}
Assert.assertTrue(type + " transaction failed with error code " + response.getResult(),
response.getResult() == ContextHubTransaction.RESULT_SUCCESS);
}
}