Register PackageMonitor for CompanionDeviceManagerService
1. On package removed -> remove all its associations 2. On package updated -> if had associations, update special access permission in accordance with (potentially changed) permission entries in manifest Bug: 30932767 Test: 1. Remove app, and ensure xml entries for it got removed. 2. adb install new version of app without special permissions in manifest, and ensure whitelist removal method got called Change-Id: I87261c05ddcf40a18332d160b44ee2f8284df5e4
This commit is contained in:
@@ -23,6 +23,7 @@ import android.os.Parcelable;
|
||||
import android.provider.OneTimeUseBuilder;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -47,7 +48,7 @@ public final class AssociationRequest implements Parcelable {
|
||||
private AssociationRequest(
|
||||
boolean singleDevice, @Nullable List<DeviceFilter<?>> deviceFilters) {
|
||||
this.mSingleDevice = singleDevice;
|
||||
this.mDeviceFilters = ArrayUtils.emptyIfNull(deviceFilters);
|
||||
this.mDeviceFilters = CollectionUtils.emptyIfNull(deviceFilters);
|
||||
}
|
||||
|
||||
private AssociationRequest(Parcel in) {
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.os.ParcelUuid;
|
||||
import android.provider.OneTimeUseBuilder;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -53,8 +54,8 @@ public final class BluetoothDeviceFilter implements DeviceFilter<BluetoothDevice
|
||||
List<ParcelUuid> serviceUuidMasks) {
|
||||
mNamePattern = namePattern;
|
||||
mAddress = address;
|
||||
mServiceUuids = ArrayUtils.emptyIfNull(serviceUuids);
|
||||
mServiceUuidMasks = ArrayUtils.emptyIfNull(serviceUuidMasks);
|
||||
mServiceUuids = CollectionUtils.emptyIfNull(serviceUuids);
|
||||
mServiceUuidMasks = CollectionUtils.emptyIfNull(serviceUuidMasks);
|
||||
}
|
||||
|
||||
private BluetoothDeviceFilter(Parcel in) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Base class for a remotable object, the core part of a lightweight
|
||||
@@ -245,6 +246,36 @@ public class Binder implements IBinder {
|
||||
*/
|
||||
public static final native void restoreCallingIdentity(long token);
|
||||
|
||||
/**
|
||||
* Convenience method for running the provided action enclosed in
|
||||
* {@link #clearCallingIdentity}/{@link #restoreCallingIdentity}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final void withCleanCallingIdentity(Runnable action) {
|
||||
long callingIdentity = clearCallingIdentity();
|
||||
try {
|
||||
action.run();
|
||||
} finally {
|
||||
restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for running the provided action enclosed in
|
||||
* {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final <T> T withCleanCallingIdentity(Supplier<T> action) {
|
||||
long callingIdentity = clearCallingIdentity();
|
||||
try {
|
||||
return action.get();
|
||||
} finally {
|
||||
restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the native thread-local StrictMode policy mask.
|
||||
*
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Handy class for starting a new thread that has a looper. The looper can then be
|
||||
* used to create handler classes. Note that start() must still be called.
|
||||
@@ -24,6 +27,7 @@ public class HandlerThread extends Thread {
|
||||
int mPriority;
|
||||
int mTid = -1;
|
||||
Looper mLooper;
|
||||
private @Nullable Handler mHandler;
|
||||
|
||||
public HandlerThread(String name) {
|
||||
super(name);
|
||||
@@ -85,6 +89,18 @@ public class HandlerThread extends Thread {
|
||||
return mLooper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a shared {@link Handler} associated with this thread
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public Handler getThreadHandler() {
|
||||
if (mHandler == null) {
|
||||
mHandler = new Handler(getLooper());
|
||||
}
|
||||
return mHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quits the handler thread's looper.
|
||||
* <p>
|
||||
|
||||
@@ -31,7 +31,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* ArrayUtils contains some methods that you can call to find out
|
||||
@@ -237,35 +236,6 @@ public class ArrayUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> List<T> filter(@Nullable List<?> list, Class<T> c) {
|
||||
if (isEmpty(list)) return Collections.emptyList();
|
||||
ArrayList<T> result = null;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
final Object item = list.get(i);
|
||||
if (c.isInstance(item)) {
|
||||
result = add(result, (T) item);
|
||||
}
|
||||
}
|
||||
return emptyIfNull(result);
|
||||
}
|
||||
|
||||
public static <T> boolean any(@Nullable List<T> items,
|
||||
java.util.function.Predicate<T> predicate) {
|
||||
return find(items, predicate) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T> T find(@Nullable List<T> items,
|
||||
java.util.function.Predicate<T> predicate) {
|
||||
if (isEmpty(items)) return null;
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
final T item = items.get(i);
|
||||
if (predicate.test(item)) return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static long total(@Nullable long[] array) {
|
||||
long total = 0;
|
||||
if (array != null) {
|
||||
@@ -504,29 +474,6 @@ public class ArrayUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static int size(@Nullable Collection<?> cur) {
|
||||
return cur != null ? cur.size() : 0;
|
||||
}
|
||||
|
||||
public static @NonNull <I, O> List<O> map(@Nullable List<I> cur,
|
||||
Function<? super I, ? extends O> f) {
|
||||
if (cur == null || cur.isEmpty()) return Collections.emptyList();
|
||||
final ArrayList<O> result = new ArrayList<>();
|
||||
for (int i = 0; i < cur.size(); i++) {
|
||||
result.add(f.apply(cur.get(i)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given list, or an immutable empty list if the provided list is null
|
||||
*
|
||||
* @see Collections#emptyList
|
||||
*/
|
||||
public static @NonNull <T> List<T> emptyIfNull(@Nullable List<T> cur) {
|
||||
return cur == null ? Collections.emptyList() : cur;
|
||||
}
|
||||
|
||||
public static <T> boolean contains(@Nullable Collection<T> cur, T val) {
|
||||
return (cur != null) ? cur.contains(val) : false;
|
||||
}
|
||||
|
||||
130
core/java/com/android/internal/util/CollectionUtils.java
Normal file
130
core/java/com/android/internal/util/CollectionUtils.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.android.internal.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Utility methods for dealing with (typically {@link Nullable}) {@link Collection}s
|
||||
*
|
||||
* Unless a method specifies otherwise, a null value for a collection is treated as an empty
|
||||
* collection of that type.
|
||||
*/
|
||||
public class CollectionUtils {
|
||||
private CollectionUtils() { /* cannot be instantiated */ }
|
||||
|
||||
/**
|
||||
* Returns a list of items from the provided list that match the given condition.
|
||||
*
|
||||
* This is similar to {@link Stream#filter} but without the overhead of creating an intermediate
|
||||
* {@link Stream} instance
|
||||
*/
|
||||
public static @NonNull <T> List<T> filter(@Nullable List<T> list,
|
||||
java.util.function.Predicate<? super T> predicate) {
|
||||
ArrayList<T> result = null;
|
||||
for (int i = 0; i < size(list); i++) {
|
||||
final T item = list.get(i);
|
||||
if (predicate.test(item)) {
|
||||
result = ArrayUtils.add(result, item);
|
||||
}
|
||||
}
|
||||
return emptyIfNull(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of items resulting from applying the given function to each element of the
|
||||
* provided list.
|
||||
*
|
||||
* The resulting list will have the same {@link #size} as the input one.
|
||||
*
|
||||
* This is similar to {@link Stream#map} but without the overhead of creating an intermediate
|
||||
* {@link Stream} instance
|
||||
*/
|
||||
public static @NonNull <I, O> List<O> map(@Nullable List<I> cur,
|
||||
Function<? super I, ? extends O> f) {
|
||||
if (cur == null || cur.isEmpty()) return Collections.emptyList();
|
||||
final ArrayList<O> result = new ArrayList<>();
|
||||
for (int i = 0; i < cur.size(); i++) {
|
||||
result.add(f.apply(cur.get(i)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given list, or an immutable empty list if the provided list is null
|
||||
*
|
||||
* This can be used to guaranty null-safety without paying the price of extra allocations
|
||||
*
|
||||
* @see Collections#emptyList
|
||||
*/
|
||||
public static @NonNull <T> List<T> emptyIfNull(@Nullable List<T> cur) {
|
||||
return cur == null ? Collections.emptyList() : cur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the given list, or 0 if the list is null
|
||||
*/
|
||||
public static int size(@Nullable Collection<?> cur) {
|
||||
return cur != null ? cur.size() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the elements of the given list that are of type {@code c}
|
||||
*/
|
||||
public static @NonNull <T> List<T> filter(@Nullable List<?> list, Class<T> c) {
|
||||
if (ArrayUtils.isEmpty(list)) return Collections.emptyList();
|
||||
ArrayList<T> result = null;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
final Object item = list.get(i);
|
||||
if (c.isInstance(item)) {
|
||||
result = ArrayUtils.add(result, (T) item);
|
||||
}
|
||||
}
|
||||
return emptyIfNull(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there exists at least one element in the list for which
|
||||
* condition {@code predicate} is true
|
||||
*/
|
||||
public static <T> boolean any(@Nullable List<T> items,
|
||||
java.util.function.Predicate<T> predicate) {
|
||||
return find(items, predicate) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first element from the list for which
|
||||
* condition {@code predicate} is true, or null if there is no such element
|
||||
*/
|
||||
public static @Nullable <T> T find(@Nullable List<T> items,
|
||||
java.util.function.Predicate<T> predicate) {
|
||||
if (ArrayUtils.isEmpty(items)) return null;
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
final T item = items.get(i);
|
||||
if (predicate.test(item)) return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -35,9 +35,7 @@ import android.bluetooth.le.ScanResult;
|
||||
import android.bluetooth.le.ScanSettings;
|
||||
import android.companion.AssociationRequest;
|
||||
import android.companion.BluetoothDeviceFilter;
|
||||
import android.companion.BluetoothDeviceFilterUtils;
|
||||
import android.companion.BluetoothLEDeviceFilter;
|
||||
import android.companion.CompanionDeviceManager;
|
||||
import android.companion.DeviceFilter;
|
||||
import android.companion.ICompanionDeviceDiscoveryService;
|
||||
import android.companion.ICompanionDeviceDiscoveryServiceCallback;
|
||||
@@ -60,7 +58,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.CollectionUtils;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -185,10 +183,10 @@ public class DeviceDiscoveryService extends Service {
|
||||
mRequest = request;
|
||||
|
||||
mFilters = request.getDeviceFilters();
|
||||
mWifiFilters = ArrayUtils.filter(mFilters, WifiDeviceFilter.class);
|
||||
mBluetoothFilters = ArrayUtils.filter(mFilters, BluetoothDeviceFilter.class);
|
||||
mBLEFilters = ArrayUtils.filter(mFilters, BluetoothLEDeviceFilter.class);
|
||||
mBLEScanFilters = ArrayUtils.map(mBLEFilters, BluetoothLEDeviceFilter::getScanFilter);
|
||||
mWifiFilters = CollectionUtils.filter(mFilters, WifiDeviceFilter.class);
|
||||
mBluetoothFilters = CollectionUtils.filter(mFilters, BluetoothDeviceFilter.class);
|
||||
mBLEFilters = CollectionUtils.filter(mFilters, BluetoothLEDeviceFilter.class);
|
||||
mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLEDeviceFilter::getScanFilter);
|
||||
|
||||
reset();
|
||||
|
||||
@@ -357,7 +355,7 @@ public class DeviceDiscoveryService extends Service {
|
||||
public static <T extends Parcelable> DeviceFilterPair<T> findMatch(
|
||||
T dev, @Nullable List<? extends DeviceFilter<T>> filters) {
|
||||
if (isEmpty(filters)) return new DeviceFilterPair<>(dev, null);
|
||||
final DeviceFilter<T> matchingFilter = ArrayUtils.find(filters, (f) -> f.matches(dev));
|
||||
final DeviceFilter<T> matchingFilter = CollectionUtils.find(filters, (f) -> f.matches(dev));
|
||||
return matchingFilter != null ? new DeviceFilterPair<>(dev, matchingFilter) : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1136,6 +1136,9 @@ public class DeviceIdleController extends SystemService
|
||||
|
||||
private final class BinderService extends IDeviceIdleController.Stub {
|
||||
@Override public void addPowerSaveWhitelistApp(String name) {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "addPowerSaveWhitelistApp(name = " + name + ")");
|
||||
}
|
||||
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
|
||||
null);
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
@@ -1147,6 +1150,9 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
|
||||
@Override public void removePowerSaveWhitelistApp(String name) {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "removePowerSaveWhitelistApp(name = " + name + ")");
|
||||
}
|
||||
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
|
||||
null);
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
|
||||
@@ -46,7 +46,10 @@ import android.util.ExceptionUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.CollectionUtils;
|
||||
import com.android.server.FgThread;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
@@ -86,10 +89,35 @@ public class CompanionDeviceManagerService extends SystemService {
|
||||
|
||||
private final CompanionDeviceManagerImpl mImpl;
|
||||
private final ConcurrentMap<Integer, AtomicFile> mUidToStorage = new ConcurrentHashMap<>();
|
||||
private IDeviceIdleController mIdleController;
|
||||
|
||||
public CompanionDeviceManagerService(Context context) {
|
||||
super(context);
|
||||
mImpl = new CompanionDeviceManagerImpl();
|
||||
mIdleController = IDeviceIdleController.Stub.asInterface(
|
||||
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
|
||||
registerPackageMonitor();
|
||||
}
|
||||
|
||||
private void registerPackageMonitor() {
|
||||
new PackageMonitor() {
|
||||
@Override
|
||||
public void onPackageRemoved(String packageName, int uid) {
|
||||
updateAssociations(
|
||||
as -> CollectionUtils.filter(as,
|
||||
a -> !Objects.equals(a.companionAppPackage, packageName)),
|
||||
getChangingUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageModified(String packageName) {
|
||||
int userId = getChangingUserId();
|
||||
if (!ArrayUtils.isEmpty(readAllAssociations(userId, packageName))) {
|
||||
updateSpecialAccessPermissionForAssociatedPackage(packageName, userId);
|
||||
}
|
||||
}
|
||||
|
||||
}.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,9 +152,9 @@ public class CompanionDeviceManagerService extends SystemService {
|
||||
|
||||
@Override
|
||||
public List<String> getAssociations(String callingPackage) {
|
||||
return ArrayUtils.map(
|
||||
return CollectionUtils.map(
|
||||
readAllAssociations(getUserId(), callingPackage),
|
||||
(a) -> a.deviceAddress);
|
||||
a -> a.deviceAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,43 +206,55 @@ public class CompanionDeviceManagerService extends SystemService {
|
||||
@Override
|
||||
public void onDeviceSelected(String packageName, int userId, String deviceAddress) {
|
||||
//TODO unbind
|
||||
grantSpecialAccessPermissionsIfNeeded(packageName, userId);
|
||||
updateSpecialAccessPermissionForAssociatedPackage(packageName, userId);
|
||||
recordAssociation(packageName, deviceAddress);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void grantSpecialAccessPermissionsIfNeeded(String packageName, int userId) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
final PackageInfo packageInfo;
|
||||
try {
|
||||
private void updateSpecialAccessPermissionForAssociatedPackage(String packageName, int userId) {
|
||||
PackageInfo packageInfo = getPackageInfo(packageName, userId);
|
||||
if (packageInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Binder.withCleanCallingIdentity(() -> {
|
||||
try {
|
||||
packageInfo = getContext().getPackageManager().getPackageInfoAsUser(
|
||||
packageName, PackageManager.GET_PERMISSIONS, userId);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.e(LOG_TAG, "Error granting special access permissions to package:"
|
||||
+ packageName, e);
|
||||
return;
|
||||
}
|
||||
if (ArrayUtils.contains(packageInfo.requestedPermissions,
|
||||
Manifest.permission.RUN_IN_BACKGROUND)) {
|
||||
IDeviceIdleController idleController = IDeviceIdleController.Stub.asInterface(
|
||||
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
|
||||
try {
|
||||
idleController.addPowerSaveWhitelistApp(packageName);
|
||||
} catch (RemoteException e) {
|
||||
/* ignore - local call */
|
||||
if (ArrayUtils.contains(packageInfo.requestedPermissions,
|
||||
Manifest.permission.RUN_IN_BACKGROUND)) {
|
||||
mIdleController.addPowerSaveWhitelistApp(packageInfo.packageName);
|
||||
} else {
|
||||
mIdleController.removePowerSaveWhitelistApp(packageInfo.packageName);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
/* ignore - local call */
|
||||
}
|
||||
|
||||
NetworkPolicyManager networkPolicyManager = NetworkPolicyManager.from(getContext());
|
||||
if (ArrayUtils.contains(packageInfo.requestedPermissions,
|
||||
Manifest.permission.USE_DATA_IN_BACKGROUND)) {
|
||||
NetworkPolicyManager.from(getContext()).addUidPolicy(
|
||||
networkPolicyManager.addUidPolicy(
|
||||
packageInfo.applicationInfo.uid,
|
||||
NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
|
||||
} else {
|
||||
networkPolicyManager.removeUidPolicy(
|
||||
packageInfo.applicationInfo.uid,
|
||||
NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PackageInfo getPackageInfo(String packageName, int userId) {
|
||||
return Binder.withCleanCallingIdentity(() -> {
|
||||
try {
|
||||
return getContext().getPackageManager().getPackageInfoAsUser(
|
||||
packageName, PackageManager.GET_PERMISSIONS, userId);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.e(LOG_TAG, "Failed to get PackageInfo for package " + packageName, e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void recordAssociation(String priviledgedPackage, String deviceAddress) {
|
||||
@@ -222,13 +262,16 @@ public class CompanionDeviceManagerService extends SystemService {
|
||||
new Association(getUserId(), deviceAddress, priviledgedPackage)));
|
||||
}
|
||||
|
||||
private void updateAssociations(
|
||||
Function<ArrayList<Association>, ArrayList<Association>> update) {
|
||||
final int userId = getUserId();
|
||||
private void updateAssociations(Function<ArrayList<Association>, List<Association>> update) {
|
||||
updateAssociations(update, getUserId());
|
||||
}
|
||||
|
||||
private void updateAssociations(Function<ArrayList<Association>, List<Association>> update,
|
||||
int userId) {
|
||||
final AtomicFile file = getStorageFileForUser(userId);
|
||||
synchronized (file) {
|
||||
final ArrayList<Association> old = readAllAssociations(userId);
|
||||
final ArrayList<Association> associations = update.apply(old);
|
||||
final List<Association> associations = update.apply(old);
|
||||
if (Objects.equals(old, associations)) return;
|
||||
|
||||
file.write((out) -> {
|
||||
@@ -239,7 +282,7 @@ public class CompanionDeviceManagerService extends SystemService {
|
||||
xml.startDocument(null, true);
|
||||
xml.startTag(null, XML_TAG_ASSOCIATIONS);
|
||||
|
||||
for (int i = 0; i < ArrayUtils.size(associations); i++) {
|
||||
for (int i = 0; i < CollectionUtils.size(associations); i++) {
|
||||
Association association = associations.get(i);
|
||||
xml.startTag(null, XML_TAG_ASSOCIATION)
|
||||
.attribute(null, XML_ATTR_PACKAGE, association.companionAppPackage)
|
||||
|
||||
Reference in New Issue
Block a user