Expose Companion API via shell command
Usage:
adb shell cmd companion_device ...
Test: Call each subcommand and ensure it works
Change-Id: I383995221384013b798fdd1c30a2846e14f7ad06
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 9bb0f86..f0af3dd 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -48,7 +48,10 @@
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.SettingsStringUtil.ComponentNameSet;
@@ -72,6 +75,7 @@
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -87,7 +91,6 @@
//TODO schedule stopScan on activity destroy(except if configuration change)
//TODO on associate called again after configuration change -> replace old callback with new
//TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example)
-//TODO check user-feature present in manifest on API calls
/** @hide */
public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient {
@@ -235,8 +238,7 @@
checkNotNull(deviceMacAddress);
checkCallerIsSystemOr(callingPackage);
checkUsesFeature(callingPackage, getCallingUserId());
- updateAssociations(associations -> CollectionUtils.remove(associations,
- new Association(getCallingUserId(), deviceMacAddress, callingPackage)));
+ removeAssociation(getCallingUserId(), callingPackage, deviceMacAddress);
}
private void checkCallerIsSystemOr(String pkg) throws RemoteException {
@@ -304,6 +306,13 @@
+ requiredFeature
+ " in manifest to use this API");
}
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver)
+ throws RemoteException {
+ new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
+ }
}
private int getCallingUserId() {
@@ -367,8 +376,7 @@
@Override
public void onDeviceSelected(String packageName, int userId, String deviceAddress) {
- updateSpecialAccessPermissionForAssociatedPackage(packageName, userId);
- recordAssociation(packageName, deviceAddress);
+ addAssociation(userId, packageName, deviceAddress);
cleanup();
}
@@ -379,6 +387,16 @@
};
}
+ void addAssociation(int userId, String packageName, String deviceAddress) {
+ updateSpecialAccessPermissionForAssociatedPackage(packageName, userId);
+ recordAssociation(packageName, deviceAddress);
+ }
+
+ void removeAssociation(int userId, String pkg, String deviceMacAddress) {
+ updateAssociations(associations -> CollectionUtils.remove(associations,
+ new Association(userId, deviceMacAddress, pkg)));
+ }
+
private void updateSpecialAccessPermissionForAssociatedPackage(String packageName, int userId) {
PackageInfo packageInfo = getPackageInfo(packageName, userId);
if (packageInfo == null) {
@@ -486,8 +504,8 @@
}
@Nullable
- private ArrayList<Association> readAllAssociations(int uid) {
- return readAllAssociations(uid, null);
+ private ArrayList<Association> readAllAssociations(int userId) {
+ return readAllAssociations(userId, null);
}
@Nullable
@@ -523,6 +541,8 @@
}
}
+
+
private class Association {
public final int uid;
public final String deviceAddress;
@@ -556,4 +576,45 @@
}
}
+ private class ShellCmd extends ShellCommand {
+ public static final String USAGE = "help\n"
+ + "list USER_ID\n"
+ + "associate USER_ID PACKAGE MAC_ADDRESS\n"
+ + "disassociate USER_ID PACKAGE MAC_ADDRESS";
+
+ @Override
+ public int onCommand(String cmd) {
+ switch (cmd) {
+ case "list": {
+ ArrayList<Association> associations = readAllAssociations(getNextArgInt());
+ for (int i = 0; i < size(associations); i++) {
+ Association a = associations.get(i);
+ getOutPrintWriter()
+ .println(a.companionAppPackage + " " + a.deviceAddress);
+ }
+ } break;
+
+ case "associate": {
+ addAssociation(getNextArgInt(), getNextArgRequired(), getNextArgRequired());
+ } break;
+
+ case "disassociate": {
+ removeAssociation(getNextArgInt(), getNextArgRequired(), getNextArgRequired());
+ } break;
+
+ default: return handleDefaultCommands(cmd);
+ }
+ return 0;
+ }
+
+ private int getNextArgInt() {
+ return Integer.parseInt(getNextArgRequired());
+ }
+
+ @Override
+ public void onHelp() {
+ getOutPrintWriter().println(USAGE);
+ }
+ }
+
}