Expose syspem API for querying CDM associations

We want to restrict some BT capabilities(e.g. unpair device) to only the package's
associated device.
Since BT will become a mainline module, this needs to be exposed as a @SystemApi

Test: ateast android.os.cts.CompanionDeviceManagerTest#testGetAllAssociations
Bug: 165951651
Change-Id: Iab0da9352671e0b82ac855f91a6625c810946d17
This commit is contained in:
Eugene Susla
2020-07-09 17:51:20 -07:00
parent 0ebb3b81e1
commit 991e8eed4f
4 changed files with 106 additions and 52 deletions

View File

@@ -17,6 +17,7 @@ package android.companion;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,17 +31,21 @@ import java.util.Objects;
*
* @hide
*/
@DataClass(genEqualsHashCode = true, genToString = true)
public class Association implements Parcelable {
@DataClass(genEqualsHashCode = true, genToString = true, genHiddenConstructor = true)
public final class Association implements Parcelable {
public final int userId;
public final @NonNull String deviceAddress;
public final @NonNull String companionAppPackage;
private final @UserIdInt int mUserId;
private final @NonNull String mDeviceMacAddress;
private final @NonNull String mPackageName;
/** @hide */
public int getUserId() {
return mUserId;
}
// Code below generated by codegen v1.0.13.
// Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -53,22 +58,39 @@ public class Association implements Parcelable {
//@formatter:off
/**
* Creates a new Association.
*
* @hide
*/
@DataClass.Generated.Member
public Association(
int userId,
@NonNull String deviceAddress,
@NonNull String companionAppPackage) {
this.userId = userId;
this.deviceAddress = deviceAddress;
@UserIdInt int userId,
@NonNull String deviceMacAddress,
@NonNull String packageName) {
this.mUserId = userId;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, deviceAddress);
this.companionAppPackage = companionAppPackage;
UserIdInt.class, null, mUserId);
this.mDeviceMacAddress = deviceMacAddress;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, companionAppPackage);
NonNull.class, null, mDeviceMacAddress);
this.mPackageName = packageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public @NonNull String getDeviceMacAddress() {
return mDeviceMacAddress;
}
@DataClass.Generated.Member
public @NonNull String getPackageName() {
return mPackageName;
}
@Override
@DataClass.Generated.Member
public String toString() {
@@ -76,9 +98,9 @@ public class Association implements Parcelable {
// String fieldNameToString() { ... }
return "Association { " +
"userId = " + userId + ", " +
"deviceAddress = " + deviceAddress + ", " +
"companionAppPackage = " + companionAppPackage +
"userId = " + mUserId + ", " +
"deviceMacAddress = " + mDeviceMacAddress + ", " +
"packageName = " + mPackageName +
" }";
}
@@ -95,9 +117,9 @@ public class Association implements Parcelable {
Association that = (Association) o;
//noinspection PointlessBooleanExpression
return true
&& userId == that.userId
&& Objects.equals(deviceAddress, that.deviceAddress)
&& Objects.equals(companionAppPackage, that.companionAppPackage);
&& mUserId == that.mUserId
&& Objects.equals(mDeviceMacAddress, that.mDeviceMacAddress)
&& Objects.equals(mPackageName, that.mPackageName);
}
@Override
@@ -107,9 +129,9 @@ public class Association implements Parcelable {
// int fieldNameHashCode() { ... }
int _hash = 1;
_hash = 31 * _hash + userId;
_hash = 31 * _hash + Objects.hashCode(deviceAddress);
_hash = 31 * _hash + Objects.hashCode(companionAppPackage);
_hash = 31 * _hash + mUserId;
_hash = 31 * _hash + Objects.hashCode(mDeviceMacAddress);
_hash = 31 * _hash + Objects.hashCode(mPackageName);
return _hash;
}
@@ -119,9 +141,9 @@ public class Association implements Parcelable {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
dest.writeInt(userId);
dest.writeString(deviceAddress);
dest.writeString(companionAppPackage);
dest.writeInt(mUserId);
dest.writeString(mDeviceMacAddress);
dest.writeString(mPackageName);
}
@Override
@@ -131,21 +153,23 @@ public class Association implements Parcelable {
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
protected Association(@NonNull Parcel in) {
/* package-private */ Association(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
int _userId = in.readInt();
String _deviceAddress = in.readString();
String _companionAppPackage = in.readString();
int userId = in.readInt();
String deviceMacAddress = in.readString();
String packageName = in.readString();
this.userId = _userId;
this.deviceAddress = _deviceAddress;
this.mUserId = userId;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, deviceAddress);
this.companionAppPackage = _companionAppPackage;
UserIdInt.class, null, mUserId);
this.mDeviceMacAddress = deviceMacAddress;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, companionAppPackage);
NonNull.class, null, mDeviceMacAddress);
this.mPackageName = packageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
// onConstructed(); // You can define this method to get a callback
}
@@ -165,10 +189,10 @@ public class Association implements Parcelable {
};
@DataClass.Generated(
time = 1573767103332L,
codegenVersion = "1.0.13",
time = 1599083149942L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/companion/Association.java",
inputSignatures = "public final int userId\npublic final @android.annotation.NonNull java.lang.String deviceAddress\npublic final @android.annotation.NonNull java.lang.String companionAppPackage\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)")
inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\npublic int getUserId()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}

View File

@@ -305,6 +305,24 @@ public final class CompanionDeviceManager {
}
}
/**
* Gets all package-device {@link Association}s for the current user.
*
* @return the associations list
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
public @NonNull List<Association> getAllAssociations() {
if (!checkFeaturePresent()) {
return Collections.emptyList();
}
try {
return mService.getAssociationsForUser(mContext.getUser().getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
private boolean checkFeaturePresent() {
boolean featurePresent = mService != null;
if (!featurePresent && DEBUG) {

View File

@@ -18,6 +18,7 @@ package android.companion;
import android.app.PendingIntent;
import android.companion.IFindDeviceCallback;
import android.companion.Association;
import android.companion.AssociationRequest;
import android.content.ComponentName;
@@ -35,6 +36,8 @@ interface ICompanionDeviceManager {
in String callingPackage);
List<String> getAssociations(String callingPackage, int userId);
List<Association> getAssociationsForUser(int userId);
void disassociate(String deviceMacAddress, String callingPackage);
boolean hasNotificationAccess(in ComponentName component);

View File

@@ -85,7 +85,6 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import com.android.server.wm.ActivityTaskManagerInternal;
import org.xmlpull.v1.XmlPullParser;
@@ -170,7 +169,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
public void onPackageRemoved(String packageName, int uid) {
updateAssociations(
as -> CollectionUtils.filter(as,
a -> !Objects.equals(a.companionAppPackage, packageName)),
a -> !Objects.equals(a.getPackageName(), packageName)),
getChangingUserId());
}
@@ -199,7 +198,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
Set<String> companionAppPackages = new HashSet<>();
for (Association association : associations) {
companionAppPackages.add(association.companionAppPackage);
companionAppPackages.add(association.getPackageName());
}
ActivityTaskManagerInternal atmInternal = LocalServices.getService(
ActivityTaskManagerInternal.class);
@@ -229,10 +228,10 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
for (Association a : associations) {
try {
int uid = pm.getPackageUidAsUser(a.companionAppPackage, userId);
exemptFromAutoRevoke(a.companionAppPackage, uid);
int uid = pm.getPackageUidAsUser(a.getPackageName(), userId);
exemptFromAutoRevoke(a.getPackageName(), uid);
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Unknown companion package: " + a.companionAppPackage, e);
Log.w(LOG_TAG, "Unknown companion package: " + a.getPackageName(), e);
}
}
} finally {
@@ -344,7 +343,17 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
return new ArrayList<>(CollectionUtils.map(
readAllAssociations(userId, callingPackage),
a -> a.deviceAddress));
a -> a.getDeviceMacAddress()));
}
@Override
public List<Association> getAssociationsForUser(int userId) {
if (!callerCanManageCompanionDevices()) {
throw new SecurityException("Caller must hold "
+ android.Manifest.permission.MANAGE_COMPANION_DEVICES);
}
return new ArrayList<>(readAllAssociations(userId, null /* packageFilter */));
}
//TODO also revoke notification access
@@ -429,7 +438,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
return CollectionUtils.any(
readAllAssociations(userId, packageName),
a -> Objects.equals(a.deviceAddress, macAddress));
a -> Objects.equals(a.getDeviceMacAddress(), macAddress));
}
private void checkCanCallNotificationApi(String callingPackage) throws RemoteException {
@@ -479,7 +488,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
void addAssociation(Association association) {
updateSpecialAccessPermissionForAssociatedPackage(
association.companionAppPackage, association.userId);
association.getPackageName(), association.getUserId());
recordAssociation(association);
}
@@ -582,7 +591,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
Set<Association> finalAssociations = associations;
Set<String> companionAppPackages = new HashSet<>();
for (Association association : finalAssociations) {
companionAppPackages.add(association.companionAppPackage);
companionAppPackages.add(association.getPackageName());
}
file.write((out) -> {
@@ -595,8 +604,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
CollectionUtils.forEach(finalAssociations, association -> {
xml.startTag(null, XML_TAG_ASSOCIATION)
.attribute(null, XML_ATTR_PACKAGE, association.companionAppPackage)
.attribute(null, XML_ATTR_DEVICE, association.deviceAddress)
.attribute(null, XML_ATTR_PACKAGE, association.getPackageName())
.attribute(null, XML_ATTR_DEVICE, association.getDeviceMacAddress())
.endTag(null, XML_TAG_ASSOCIATION);
});
@@ -678,7 +687,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
CollectionUtils.forEach(
readAllAssociations(getNextArgInt()),
a -> getOutPrintWriter()
.println(a.companionAppPackage + " " + a.deviceAddress));
.println(a.getPackageName() + " " + a.getDeviceMacAddress()));
} break;
case "associate": {