Implment get/query APIs for properties
Bug: 169258655 Test: atest CtsContentTestCases:PackageManagerGetPropertyTest Test: atest CtsContentTestCases:PackageManagerQueryPropertyTest Change-Id: I91d58cd42e7f1f10b0e494ff9f318a9e3fa073db
This commit is contained in:
@@ -12105,6 +12105,8 @@ package android.content.pm {
|
||||
method public abstract android.content.pm.PermissionInfo getPermissionInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method @Deprecated public abstract int getPreferredActivities(@NonNull java.util.List<android.content.IntentFilter>, @NonNull java.util.List<android.content.ComponentName>, @Nullable String);
|
||||
method @Deprecated @NonNull public abstract java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
|
||||
method @NonNull public android.content.pm.PackageManager.Property getProperty(@NonNull String, @NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method @NonNull public android.content.pm.PackageManager.Property getProperty(@NonNull String, @NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method @NonNull public abstract android.content.pm.ProviderInfo getProviderInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method @NonNull public abstract android.content.pm.ActivityInfo getReceiverInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method @NonNull public abstract android.content.res.Resources getResourcesForActivity(@NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
@@ -12137,6 +12139,8 @@ package android.content.pm {
|
||||
method public boolean isPackageSuspended();
|
||||
method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String);
|
||||
method public abstract boolean isSafeMode();
|
||||
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryActivityProperty(@NonNull String);
|
||||
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryApplicationProperty(@NonNull String);
|
||||
method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(@NonNull android.content.Intent, int);
|
||||
method @NonNull public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(@Nullable String, int, int);
|
||||
method @NonNull public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(@NonNull String, int);
|
||||
@@ -12145,6 +12149,9 @@ package android.content.pm {
|
||||
method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(@NonNull android.content.Intent, int);
|
||||
method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(@NonNull android.content.Intent, int);
|
||||
method @NonNull public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryProviderProperty(@NonNull String);
|
||||
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryReceiverProperty(@NonNull String);
|
||||
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryServiceProperty(@NonNull String);
|
||||
method @Deprecated public abstract void removePackageFromPreferred(@NonNull String);
|
||||
method public abstract void removePermission(@NonNull String);
|
||||
method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean removeWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int);
|
||||
|
||||
@@ -58,6 +58,8 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageItemInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.PackageManager.Property;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.PermissionGroupInfo;
|
||||
import android.content.pm.PermissionInfo;
|
||||
@@ -3551,4 +3553,112 @@ public class ApplicationPackageManager extends PackageManager {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property getProperty(String propertyName, String packageName)
|
||||
throws NameNotFoundException {
|
||||
Objects.requireNonNull(packageName);
|
||||
Objects.requireNonNull(propertyName);
|
||||
try {
|
||||
final Property property = mPM.getProperty(propertyName, packageName, null);
|
||||
if (property == null) {
|
||||
throw new NameNotFoundException();
|
||||
}
|
||||
return property;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property getProperty(String propertyName, ComponentName component)
|
||||
throws NameNotFoundException {
|
||||
Objects.requireNonNull(component);
|
||||
Objects.requireNonNull(propertyName);
|
||||
try {
|
||||
final Property property = mPM.getProperty(
|
||||
propertyName, component.getPackageName(), component.getClassName());
|
||||
if (property == null) {
|
||||
throw new NameNotFoundException();
|
||||
}
|
||||
return property;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Property> queryApplicationProperty(String propertyName) {
|
||||
Objects.requireNonNull(propertyName);
|
||||
try {
|
||||
final ParceledListSlice<Property> parceledList =
|
||||
mPM.queryProperty(propertyName, TYPE_APPLICATION);
|
||||
if (parceledList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return parceledList.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Property> queryActivityProperty(String propertyName) {
|
||||
Objects.requireNonNull(propertyName);
|
||||
try {
|
||||
final ParceledListSlice<Property> parceledList =
|
||||
mPM.queryProperty(propertyName, TYPE_ACTIVITY);
|
||||
if (parceledList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return parceledList.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Property> queryProviderProperty(String propertyName) {
|
||||
Objects.requireNonNull(propertyName);
|
||||
try {
|
||||
final ParceledListSlice<Property> parceledList =
|
||||
mPM.queryProperty(propertyName, TYPE_PROVIDER);
|
||||
if (parceledList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return parceledList.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Property> queryReceiverProperty(String propertyName) {
|
||||
Objects.requireNonNull(propertyName);
|
||||
try {
|
||||
final ParceledListSlice<Property> parceledList =
|
||||
mPM.queryProperty(propertyName, TYPE_RECEIVER);
|
||||
if (parceledList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return parceledList.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Property> queryServiceProperty(String propertyName) {
|
||||
Objects.requireNonNull(propertyName);
|
||||
try {
|
||||
final ParceledListSlice<Property> parceledList =
|
||||
mPM.queryProperty(propertyName, TYPE_SERVICE);
|
||||
if (parceledList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return parceledList.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import android.content.pm.InstrumentationInfo;
|
||||
import android.content.pm.KeySet;
|
||||
import android.content.pm.ModuleInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.PermissionGroupInfo;
|
||||
@@ -797,4 +798,7 @@ interface IPackageManager {
|
||||
IBinder getHoldLockToken();
|
||||
|
||||
void holdLock(in IBinder token, in int durationMs);
|
||||
|
||||
PackageManager.Property getProperty(String propertyName, String packageName, String className);
|
||||
ParceledListSlice queryProperty(String propertyName, int componentType);
|
||||
}
|
||||
|
||||
20
core/java/android/content/pm/PackageManager.aidl
Normal file
20
core/java/android/content/pm/PackageManager.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
**
|
||||
** Copyright 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 android.content.pm;
|
||||
|
||||
parcelable PackageManager.Property;
|
||||
@@ -311,6 +311,8 @@ public abstract class PackageManager {
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(mName);
|
||||
dest.writeInt(mType);
|
||||
dest.writeString(mPackageName);
|
||||
dest.writeString(mClassName);
|
||||
if (mType == TYPE_BOOLEAN) {
|
||||
dest.writeBoolean(mBooleanValue);
|
||||
} else if (mType == TYPE_FLOAT) {
|
||||
@@ -322,8 +324,6 @@ public abstract class PackageManager {
|
||||
} else if (mType == TYPE_STRING) {
|
||||
dest.writeString(mStringValue);
|
||||
}
|
||||
dest.writeString(mPackageName);
|
||||
dest.writeString(mClassName);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -370,6 +370,41 @@ public abstract class PackageManager {
|
||||
public void onPermissionsChanged(int uid);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static final int TYPE_UNKNOWN = 0;
|
||||
/** @hide */
|
||||
public static final int TYPE_ACTIVITY = 1;
|
||||
/** @hide */
|
||||
public static final int TYPE_RECEIVER = 2;
|
||||
/** @hide */
|
||||
public static final int TYPE_SERVICE = 3;
|
||||
/** @hide */
|
||||
public static final int TYPE_PROVIDER = 4;
|
||||
/** @hide */
|
||||
public static final int TYPE_APPLICATION = 5;
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "TYPE_" }, value = {
|
||||
TYPE_UNKNOWN,
|
||||
TYPE_ACTIVITY,
|
||||
TYPE_RECEIVER,
|
||||
TYPE_SERVICE,
|
||||
TYPE_PROVIDER,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ComponentType {}
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "TYPE_" }, value = {
|
||||
TYPE_UNKNOWN,
|
||||
TYPE_ACTIVITY,
|
||||
TYPE_RECEIVER,
|
||||
TYPE_SERVICE,
|
||||
TYPE_PROVIDER,
|
||||
TYPE_APPLICATION,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface PropertyLocation {}
|
||||
|
||||
/**
|
||||
* As a guiding principle:
|
||||
* <p>
|
||||
@@ -8601,6 +8636,88 @@ public abstract class PackageManager {
|
||||
throw new UnsupportedOperationException(
|
||||
"getMimeGroup not implemented in subclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property defined in the given package's <appliction> tag.
|
||||
*
|
||||
* @throws NameNotFoundException if either the given package is not installed or if the
|
||||
* given property is not defined within the <application> tag.
|
||||
*/
|
||||
@NonNull
|
||||
public Property getProperty(@NonNull String propertyName, @NonNull String packageName)
|
||||
throws NameNotFoundException {
|
||||
throw new UnsupportedOperationException(
|
||||
"getProperty not implemented in subclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property defined in the given component declaration.
|
||||
*
|
||||
* @throws NameNotFoundException if either the given component does not exist or if the
|
||||
* given property is not defined within the component declaration.
|
||||
*/
|
||||
@NonNull
|
||||
public Property getProperty(@NonNull String propertyName, @NonNull ComponentName component)
|
||||
throws NameNotFoundException {
|
||||
throw new UnsupportedOperationException(
|
||||
"getProperty not implemented in subclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property definition for all <application> tags.
|
||||
* <p>If the property is not defined with any <application> tag,
|
||||
* returns and empty list.
|
||||
*/
|
||||
@NonNull
|
||||
public List<Property> queryApplicationProperty(@NonNull String propertyName) {
|
||||
throw new UnsupportedOperationException(
|
||||
"qeuryApplicationProperty not implemented in subclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property definition for all <activity> and <activity-alias> tags.
|
||||
* <p>If the property is not defined with any <activity> and <activity-alias> tag,
|
||||
* returns and empty list.
|
||||
*/
|
||||
@NonNull
|
||||
public List<Property> queryActivityProperty(@NonNull String propertyName) {
|
||||
throw new UnsupportedOperationException(
|
||||
"qeuryActivityProperty not implemented in subclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property definition for all <provider> tags.
|
||||
* <p>If the property is not defined with any <provider> tag,
|
||||
* returns and empty list.
|
||||
*/
|
||||
@NonNull
|
||||
public List<Property> queryProviderProperty(@NonNull String propertyName) {
|
||||
throw new UnsupportedOperationException(
|
||||
"qeuryProviderProperty not implemented in subclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property definition for all <receiver> tags.
|
||||
* <p>If the property is not defined with any <receiver> tag,
|
||||
* returns and empty list.
|
||||
*/
|
||||
@NonNull
|
||||
public List<Property> queryReceiverProperty(@NonNull String propertyName) {
|
||||
throw new UnsupportedOperationException(
|
||||
"qeuryReceiverProperty not implemented in subclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property definition for all <service> tags.
|
||||
* <p>If the property is not defined with any <service> tag,
|
||||
* returns and empty list.
|
||||
*/
|
||||
@NonNull
|
||||
public List<Property> queryServiceProperty(@NonNull String propertyName) {
|
||||
throw new UnsupportedOperationException(
|
||||
"qeuryServiceProperty not implemented in subclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants implicit visibility of the package that provides an authority to a querying UID.
|
||||
*
|
||||
|
||||
@@ -94,6 +94,11 @@ import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
|
||||
import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.content.pm.PackageManager.RESTRICTION_NONE;
|
||||
import static android.content.pm.PackageManager.TYPE_ACTIVITY;
|
||||
import static android.content.pm.PackageManager.TYPE_PROVIDER;
|
||||
import static android.content.pm.PackageManager.TYPE_RECEIVER;
|
||||
import static android.content.pm.PackageManager.TYPE_SERVICE;
|
||||
import static android.content.pm.PackageManager.TYPE_UNKNOWN;
|
||||
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
|
||||
import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
|
||||
import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
|
||||
@@ -195,8 +200,11 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageInfoLite;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.ComponentType;
|
||||
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
|
||||
import android.content.pm.PackageManager.ModuleInfoFlags;
|
||||
import android.content.pm.PackageManager.Property;
|
||||
import android.content.pm.PackageManager.PropertyLocation;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.PackageManagerInternal.PackageListObserver;
|
||||
import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
|
||||
@@ -339,7 +347,6 @@ import com.android.internal.telephony.CarrierAppUtils;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.ConcurrentUtils;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Preconditions;
|
||||
@@ -394,7 +401,6 @@ import libcore.util.HexEncoding;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -572,21 +578,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
private static final int[] EMPTY_INT_ARRAY = new int[0];
|
||||
|
||||
private static final int TYPE_UNKNOWN = 0;
|
||||
private static final int TYPE_ACTIVITY = 1;
|
||||
private static final int TYPE_RECEIVER = 2;
|
||||
private static final int TYPE_SERVICE = 3;
|
||||
private static final int TYPE_PROVIDER = 4;
|
||||
@IntDef(prefix = { "TYPE_" }, value = {
|
||||
TYPE_UNKNOWN,
|
||||
TYPE_ACTIVITY,
|
||||
TYPE_RECEIVER,
|
||||
TYPE_SERVICE,
|
||||
TYPE_PROVIDER,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ComponentType {}
|
||||
|
||||
/**
|
||||
* Timeout (in milliseconds) after which the watchdog should declare that
|
||||
* our handler thread is wedged. The usual default for such things is one
|
||||
@@ -1317,6 +1308,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
private final IncrementalManager mIncrementalManager;
|
||||
|
||||
private final PackageProperty mPackageProperty = new PackageProperty();
|
||||
|
||||
private static class IFVerificationParams {
|
||||
String packageName;
|
||||
boolean hasDomainUrls;
|
||||
@@ -12708,6 +12701,37 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property getProperty(String propertyName, String packageName, String className) {
|
||||
Objects.requireNonNull(propertyName);
|
||||
Objects.requireNonNull(packageName);
|
||||
synchronized (mLock) {
|
||||
final PackageSetting ps = getPackageSetting(packageName);
|
||||
if (shouldFilterApplicationLocked(ps, Binder.getCallingUid(),
|
||||
UserHandle.getCallingUserId())) {
|
||||
return null;
|
||||
}
|
||||
return mPackageProperty.getProperty(propertyName, packageName, className);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParceledListSlice<Property> queryProperty(
|
||||
String propertyName, @PropertyLocation int componentType) {
|
||||
Objects.requireNonNull(propertyName);
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingUserId = UserHandle.getCallingUserId();
|
||||
final List<Property> result =
|
||||
mPackageProperty.queryProperty(propertyName, componentType, packageName -> {
|
||||
final PackageSetting ps = getPackageSetting(packageName);
|
||||
return shouldFilterApplicationLocked(ps, callingUid, callingUserId);
|
||||
});
|
||||
if (result == null) {
|
||||
return ParceledListSlice.emptyList();
|
||||
}
|
||||
return new ParceledListSlice<>(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a scanned package to the system. When this method is finished, the package will
|
||||
* be available for query, resolution, etc...
|
||||
@@ -12834,6 +12858,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
final boolean isReplace =
|
||||
reconciledPkg.prepareResult != null && reconciledPkg.prepareResult.replace;
|
||||
mAppsFilter.addPackage(pkgSetting, isReplace);
|
||||
mPackageProperty.addAllProperties(pkg);
|
||||
|
||||
int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
|
||||
StringBuilder r = null;
|
||||
@@ -12978,6 +13003,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
private void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) {
|
||||
mComponentResolver.removeAllComponents(pkg, chatty);
|
||||
mPermissionManager.onPackageRemoved(pkg);
|
||||
mPackageProperty.removeAllProperties(pkg);
|
||||
|
||||
final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations());
|
||||
StringBuilder r = null;
|
||||
|
||||
287
services/core/java/com/android/server/pm/PackageProperty.java
Normal file
287
services/core/java/com/android/server/pm/PackageProperty.java
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* 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.android.server.pm;
|
||||
|
||||
import static android.content.pm.PackageManager.TYPE_ACTIVITY;
|
||||
import static android.content.pm.PackageManager.TYPE_APPLICATION;
|
||||
import static android.content.pm.PackageManager.TYPE_PROVIDER;
|
||||
import static android.content.pm.PackageManager.TYPE_RECEIVER;
|
||||
import static android.content.pm.PackageManager.TYPE_SERVICE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.Property;
|
||||
import android.content.pm.PackageManager.PropertyLocation;
|
||||
import android.content.pm.parsing.component.ParsedComponent;
|
||||
import android.os.Binder;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Manages properties defined within a package using the <property> tag.
|
||||
*/
|
||||
public class PackageProperty {
|
||||
/**
|
||||
* Mapping of property name to all defined defined properties.
|
||||
* <p>This is a mapping of property name --> package map. The package
|
||||
* map is a mapping of package name -> list of properties.
|
||||
*/
|
||||
private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mApplicationProperties;
|
||||
private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mActivityProperties;
|
||||
private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mProviderProperties;
|
||||
private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mReceiverProperties;
|
||||
private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mServiceProperties;
|
||||
|
||||
/**
|
||||
* If the provided component is {@code null}, returns the property defined on the
|
||||
* application. Otherwise, returns the property defined on the component.
|
||||
*/
|
||||
public Property getProperty(@NonNull String propertyName, @NonNull String packageName,
|
||||
@Nullable String className) {
|
||||
if (className == null) {
|
||||
return getApplicationProperty(propertyName, packageName);
|
||||
}
|
||||
return getComponentProperty(propertyName, packageName, className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all properties defined at the given location.
|
||||
* <p>Valid locations are {@link PackageManager#TYPE_APPLICATION},
|
||||
* {@link PackageManager#TYPE_ACTIVITY}, {@link PackageManager#TYPE_PROVIDER},
|
||||
* {@link PackageManager#TYPE_RECEIVER}, or {@link PackageManager#TYPE_SERVICE}.
|
||||
*/
|
||||
public List<Property> queryProperty(@NonNull String propertyName,
|
||||
@PropertyLocation int componentType, Predicate<String> filter) {
|
||||
final ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyMap;
|
||||
if (componentType == TYPE_APPLICATION) {
|
||||
propertyMap = mApplicationProperties;
|
||||
} else if (componentType == TYPE_ACTIVITY) {
|
||||
propertyMap = mActivityProperties;
|
||||
} else if (componentType == TYPE_PROVIDER) {
|
||||
propertyMap = mProviderProperties;
|
||||
} else if (componentType == TYPE_RECEIVER) {
|
||||
propertyMap = mReceiverProperties;
|
||||
} else if (componentType == TYPE_SERVICE) {
|
||||
propertyMap = mServiceProperties;
|
||||
} else {
|
||||
propertyMap = null;
|
||||
}
|
||||
if (propertyMap == null) {
|
||||
return null;
|
||||
}
|
||||
final ArrayMap<String, ArrayList<Property>> packagePropertyMap =
|
||||
propertyMap.get(propertyName);
|
||||
if (packagePropertyMap == null) {
|
||||
return null;
|
||||
}
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingUserId = UserHandle.getCallingUserId();
|
||||
final int mapSize = packagePropertyMap.size();
|
||||
final List<Property> result = new ArrayList<>(mapSize);
|
||||
for (int i = 0; i < mapSize; i++) {
|
||||
final String packageName = packagePropertyMap.keyAt(i);
|
||||
if (filter.test(packageName)) {
|
||||
continue;
|
||||
}
|
||||
result.addAll(packagePropertyMap.valueAt(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Adds all properties defined for the given package */
|
||||
void addAllProperties(AndroidPackage pkg) {
|
||||
mApplicationProperties = addProperties(pkg.getProperties(), mApplicationProperties);
|
||||
mActivityProperties = addComponentProperties(pkg.getActivities(), mActivityProperties);
|
||||
mProviderProperties = addComponentProperties(pkg.getProviders(), mProviderProperties);
|
||||
mReceiverProperties = addComponentProperties(pkg.getReceivers(), mReceiverProperties);
|
||||
mServiceProperties = addComponentProperties(pkg.getServices(), mServiceProperties);
|
||||
}
|
||||
|
||||
/** Adds all properties defined for the given package */
|
||||
void removeAllProperties(AndroidPackage pkg) {
|
||||
mApplicationProperties = removeProperties(pkg.getProperties(), mApplicationProperties);
|
||||
mActivityProperties = removeComponentProperties(pkg.getActivities(), mActivityProperties);
|
||||
mProviderProperties = removeComponentProperties(pkg.getProviders(), mProviderProperties);
|
||||
mReceiverProperties = removeComponentProperties(pkg.getReceivers(), mReceiverProperties);
|
||||
mServiceProperties = removeComponentProperties(pkg.getServices(), mServiceProperties);
|
||||
}
|
||||
|
||||
/** Add the properties defined on the given components to the property collection */
|
||||
private static <T extends ParsedComponent>
|
||||
ArrayMap<String, ArrayMap<String, ArrayList<Property>>> addComponentProperties(
|
||||
@NonNull List<T> components,
|
||||
@Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection) {
|
||||
ArrayMap<String, ArrayMap<String, ArrayList<Property>>> returnCollection =
|
||||
propertyCollection;
|
||||
final int componentsSize = components.size();
|
||||
for (int i = 0; i < componentsSize; i++) {
|
||||
final Map<String, Property> properties = components.get(i).getProperties();
|
||||
if (properties.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
returnCollection = addProperties(properties, returnCollection);
|
||||
}
|
||||
return returnCollection;
|
||||
}
|
||||
|
||||
/** Add the given properties to the property collection */
|
||||
private static ArrayMap<String, ArrayMap<String, ArrayList<Property>>> addProperties(
|
||||
@NonNull Map<String, Property> properties,
|
||||
@Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection) {
|
||||
if (properties.size() == 0) {
|
||||
return propertyCollection;
|
||||
}
|
||||
final ArrayMap<String, ArrayMap<String, ArrayList<Property>>> returnCollection =
|
||||
propertyCollection == null ? new ArrayMap<>(10) : propertyCollection;
|
||||
final Iterator<Property> iter = properties.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Property property = iter.next();
|
||||
final String propertyName = property.getName();
|
||||
final String packageName = property.getPackageName();
|
||||
ArrayMap<String, ArrayList<Property>> propertyMap = returnCollection.get(propertyName);
|
||||
if (propertyMap == null) {
|
||||
propertyMap = new ArrayMap<>();
|
||||
returnCollection.put(propertyName, propertyMap);
|
||||
}
|
||||
ArrayList<Property> packageProperties = propertyMap.get(packageName);
|
||||
if (packageProperties == null) {
|
||||
packageProperties = new ArrayList<>(properties.size());
|
||||
propertyMap.put(packageName, packageProperties);
|
||||
}
|
||||
packageProperties.add(property);
|
||||
}
|
||||
return returnCollection;
|
||||
}
|
||||
|
||||
/** Removes the properties defined on the given components from the property collection */
|
||||
private static <T extends ParsedComponent>
|
||||
ArrayMap<String, ArrayMap<String, ArrayList<Property>>> removeComponentProperties(
|
||||
@NonNull List<T> components,
|
||||
@Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection) {
|
||||
ArrayMap<String, ArrayMap<String, ArrayList<Property>>> returnCollection =
|
||||
propertyCollection;
|
||||
final int componentsSize = components.size();
|
||||
for (int i = 0; returnCollection != null && i < componentsSize; i++) {
|
||||
final Map<String, Property> properties = components.get(i).getProperties();
|
||||
if (properties.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
returnCollection = removeProperties(properties, returnCollection);
|
||||
}
|
||||
return returnCollection;
|
||||
}
|
||||
|
||||
/** Removes the given properties from the property collection */
|
||||
private static ArrayMap<String, ArrayMap<String, ArrayList<Property>>> removeProperties(
|
||||
@NonNull Map<String, Property> properties,
|
||||
@Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection) {
|
||||
if (propertyCollection == null) {
|
||||
return null;
|
||||
}
|
||||
final Iterator<Property> iter = properties.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Property property = iter.next();
|
||||
final String propertyName = property.getName();
|
||||
final String packageName = property.getPackageName();
|
||||
ArrayMap<String, ArrayList<Property>> propertyMap =
|
||||
propertyCollection.get(propertyName);
|
||||
if (propertyMap == null) {
|
||||
// error
|
||||
continue;
|
||||
}
|
||||
ArrayList<Property> packageProperties = propertyMap.get(packageName);
|
||||
if (packageProperties == null) {
|
||||
//error
|
||||
continue;
|
||||
}
|
||||
packageProperties.remove(property);
|
||||
|
||||
// clean up empty structures
|
||||
if (packageProperties.size() == 0) {
|
||||
propertyMap.remove(packageName);
|
||||
}
|
||||
if (propertyMap.size() == 0) {
|
||||
propertyCollection.remove(propertyName);
|
||||
}
|
||||
}
|
||||
if (propertyCollection.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
return propertyCollection;
|
||||
}
|
||||
|
||||
private static Property getProperty(String propertyName, String packageName, String className,
|
||||
ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyMap) {
|
||||
final ArrayMap<String, ArrayList<Property>> packagePropertyMap =
|
||||
propertyMap.get(propertyName);
|
||||
if (packagePropertyMap == null) {
|
||||
return null;
|
||||
}
|
||||
final List<Property> propertyList = packagePropertyMap.get(packageName);
|
||||
if (propertyList == null) {
|
||||
return null;
|
||||
}
|
||||
for (int i = propertyList.size() - 1; i >= 0; i--) {
|
||||
final Property property = propertyList.get(i);
|
||||
if (Objects.equals(className, property.getClassName())) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Property getComponentProperty(
|
||||
String propertyName, String packageName, String className) {
|
||||
Property property = null;
|
||||
if (property == null && mActivityProperties != null) {
|
||||
property = getProperty(propertyName, packageName, className, mActivityProperties);
|
||||
}
|
||||
if (property == null && mProviderProperties != null) {
|
||||
property = getProperty(propertyName, packageName, className, mProviderProperties);
|
||||
}
|
||||
if (property == null && mReceiverProperties != null) {
|
||||
property = getProperty(propertyName, packageName, className, mReceiverProperties);
|
||||
}
|
||||
if (property == null && mServiceProperties != null) {
|
||||
property = getProperty(propertyName, packageName, className, mServiceProperties);
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
private Property getApplicationProperty(String propertyName, String packageName) {
|
||||
final ArrayMap<String, ArrayList<Property>> packagePropertyMap =
|
||||
mApplicationProperties.get(propertyName);
|
||||
if (packagePropertyMap == null) {
|
||||
return null;
|
||||
}
|
||||
final List<Property> propertyList = packagePropertyMap.get(packageName);
|
||||
if (propertyList == null) {
|
||||
return null;
|
||||
}
|
||||
return propertyList.get(0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user