summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lee Shombert <shombert@google.com> 2021-06-22 00:11:11 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-06-22 00:11:11 +0000
commita7ff24bf6b6cdac693814a751bad7d1125587f94 (patch)
tree8cc4504fcdb19d5f16804c1a0eaa71e48395cac5
parentb247011e666cac664531184bcb810e27170418bf (diff)
parent80010e6d92515b5bde5b9bd84af2368048de4ca4 (diff)
Merge "Validate Computer functions" into sc-dev
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java326
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java179
2 files changed, 391 insertions, 114 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 364ac42985f1..a70a1132360a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -436,8 +436,10 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.nio.charset.StandardCharsets;
import java.security.DigestException;
import java.security.DigestInputStream;
@@ -1918,14 +1920,65 @@ public class PackageManagerService extends IPackageManager.Stub
}
/**
- * A computer provides the functional interface to the snapshot.
+ * A {@link Computer} provides a set of functions that can operate on live data or snapshot
+ * data. At this time, the {@link Computer} is implemented by the
+ * {@link ComputerEngine}, which is in turn extended by {@link ComputerLocked}.
+ *
+ * New functions must be added carefully.
+ * <ol>
+ * <li> New functions must be true functions with respect to data collected in a
+ * {@link Snapshot}. Such data may never be modified from inside a {@link Computer}
+ * function.
+ * </li>
+ *
+ * <li> A new function must be implemented in {@link ComputerEngine}.
+ * </li>
+ *
+ * <li> A new function must be overridden in {@link ComputerLocked} if the function
+ * cannot safely access live data without holding the PackageManagerService lock. The
+ * form of the {@link ComputerLocked} function must be a single call to the
+ * {@link ComputerEngine} implementation, wrapped in a <code>synchronized</code>
+ * block. Functions in {@link ComputerLocked} should never include any other code.
+ * </li>
+ *
+ * Care must be taken when deciding if a function should be overridden in
+ * {@link ComputerLocked}. The complex lock relationships of PackageManagerService
+ * and other managers (like PermissionManager) mean deadlock is possible. On the
+ * other hand, not overriding in {@link ComputerLocked} may leave a function walking
+ * unstable data.
+ *
+ * To coax developers to consider such issues carefully, all methods in
+ * {@link Computer} must be annotated with <code>@LiveImplementation(override =
+ * MANDATORY)</code> or <code>LiveImplementation(locked = NOT_ALLOWED)</code>. A unit
+ * test verifies the annotation and that the annotation corresponds to the code in
+ * {@link ComputerEngine} and {@link ComputerLocked}.
*/
- private interface Computer {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ protected interface Computer {
+
+ /**
+ * Every method must be annotated.
+ */
+ @Target({ ElementType.METHOD })
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface LiveImplementation {
+ // A Computer method must be annotated with one of the following values:
+ // MANDATORY - the method must be overridden in ComputerEngineLive. The
+ // format of the override is a call to the super method, wrapped in a
+ // synchronization block.
+ // NOT_ALLOWED - the method may not appear in the live computer. It must
+ // be final in the ComputerEngine.
+ int MANDATORY = 1;
+ int NOT_ALLOWED = 2;
+ int override() default MANDATORY;
+ String rationale() default "";
+ }
/**
* Administrative statistics: record that the snapshot has been used. Every call
* to use() increments the usage counter.
*/
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
default void use() {
}
@@ -1933,95 +1986,154 @@ public class PackageManagerService extends IPackageManager.Stub
* Fetch the snapshot usage counter.
* @return The number of times this snapshot was used.
*/
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
default int getUsed() {
return 0;
}
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
@NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid,
int userId, boolean resolveForStart, boolean allowDynamicSplits);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
@NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
@NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType,
int flags, int userId, int callingUid, boolean includeInstantApps);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
String resolvedType, int flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
String instantAppPkgName);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ActivityInfo getActivityInfo(ComponentName component, int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
int filterCallingUid, int userId);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
AndroidPackage getPackage(String packageName);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
AndroidPackage getPackage(int uid);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
int filterCallingUid, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ApplicationInfo getApplicationInfo(String packageName, int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
int filterCallingUid, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ComponentName getDefaultHomeActivity(int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType,
int flags, int sourceUserId, int parentUserId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
Intent getHomeIntent();
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
String resolvedType, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos,
String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
boolean resolveForStart, int userId, Intent intent);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
PackageInfo getPackageInfo(String packageName, int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags,
int filterCallingUid, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
PackageSetting getPackageSetting(String packageName);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
PackageSetting getPackageSettingInternal(String packageName, int callingUid);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
int sourceUserId, int targetUserId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ServiceInfo getServiceInfo(ComponentName component, int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
String getInstantAppPackageName(int callingUid);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
String resolveExternalPackageNameLPr(AndroidPackage pkg);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
String resolveInternalPackageNameLPr(String packageName, long versionCode);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
String[] getPackagesForUid(int uid);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
UserInfo getProfileParent(int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean canViewInstantApps(int callingUid, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
int flags);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isCallerSameApp(String packageName, int uid);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
@ComponentType int type);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
String resolvedType, int flags);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isInstantApp(String packageName, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
@Nullable ComponentName component, @ComponentType int componentType, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid,
int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int checkUidPermission(String permName, int uid);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
int getPackageUidInternal(String packageName, int flags, int userId, int callingUid);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForApplication(int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForComponent(int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForPackage(int flags, int userId);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
boolean isImplicitImageCaptureIntentAndNotSetByDpc);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
boolean requirePermissionWhenSameUser, String message);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
SigningDetails getSigningDetails(@NonNull String packageName);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
SigningDetails getSigningDetails(int uid);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
boolean filterAppAccess(String packageName, int callingUid, int userId);
+ @LiveImplementation(override = LiveImplementation.MANDATORY)
void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
}
@@ -2030,7 +2142,8 @@ public class PackageManagerService extends IPackageManager.Stub
* is entirely self-contained - it has no implicit access to
* PackageManagerService.
*/
- private static class ComputerEngine implements Computer {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ protected static class ComputerEngine implements Computer {
// The administrative use counter.
private int mUsed = 0;
@@ -2076,7 +2189,7 @@ public class PackageManagerService extends IPackageManager.Stub
// PackageManagerService attributes that are primitives are referenced through the
// pms object directly. Primitives are the only attributes so referenced.
protected final PackageManagerService mService;
- protected boolean safeMode() {
+ private boolean safeMode() {
return mService.mSafeMode;
}
protected ComponentName resolveComponentName() {
@@ -2130,18 +2243,18 @@ public class PackageManagerService extends IPackageManager.Stub
/**
* Record that the snapshot was used.
*/
- public void use() {
+ public final void use() {
mUsed++;
}
/**
* Return the usage counter.
*/
- public int getUsed() {
+ public final int getUsed() {
return mUsed;
}
- public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
+ public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
int filterCallingUid, int userId, boolean resolveForStart,
boolean allowDynamicSplits) {
@@ -2240,14 +2353,14 @@ public class PackageManagerService extends IPackageManager.Stub
resolveForStart, userId, intent);
}
- public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
+ public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, int userId) {
return queryIntentActivitiesInternal(
intent, resolvedType, flags, 0 /*privateResolveFlags*/, Binder.getCallingUid(),
userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
}
- public @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
+ public final @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
String resolvedType, int flags, int userId, int callingUid,
boolean includeInstantApps) {
if (!mUserManager.exists(userId)) return Collections.emptyList();
@@ -2471,7 +2584,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
+ public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
}
@@ -2481,7 +2594,7 @@ public class PackageManagerService extends IPackageManager.Stub
* to clearing. Because it can only be provided by trusted code, its value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
- public ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
+ public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
int filterCallingUid, int userId) {
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId);
@@ -2535,8 +2648,8 @@ public class PackageManagerService extends IPackageManager.Stub
return pkg;
}
- public ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
- int filterCallingUid, int userId) {
+ public final ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName,
+ int flags, int filterCallingUid, int userId) {
if (!mUserManager.exists(userId)) return null;
PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
@@ -2563,7 +2676,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
+ public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
return getApplicationInfoInternal(packageName, flags, Binder.getCallingUid(), userId);
}
@@ -2573,7 +2686,7 @@ public class PackageManagerService extends IPackageManager.Stub
* to clearing. Because it can only be provided by trusted code, its value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
- public ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
+ public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
int filterCallingUid, int userId) {
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForApplication(flags, userId);
@@ -2765,7 +2878,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Report the 'Home' activity which is currently set as "always use this one". If non is set
* then reports the most likely home activity or null if there are more than one.
*/
- public ComponentName getDefaultHomeActivity(int userId) {
+ public final ComponentName getDefaultHomeActivity(int userId) {
List<ResolveInfo> allHomeCandidates = new ArrayList<>();
ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId);
if (cn != null) {
@@ -2793,7 +2906,7 @@ public class PackageManagerService extends IPackageManager.Stub
return lastComponent;
}
- public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+ public final ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
int userId) {
Intent intent = getHomeIntent();
List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
@@ -2822,7 +2935,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- public CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
+ public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
String resolvedType, int flags, int sourceUserId, int parentUserId) {
if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
sourceUserId)) {
@@ -2868,15 +2981,15 @@ public class PackageManagerService extends IPackageManager.Stub
return result;
}
- public Intent getHomeIntent() {
+ public final Intent getHomeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.addCategory(Intent.CATEGORY_DEFAULT);
return intent;
}
- public List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
- String resolvedType, int userId) {
+ public final List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(
+ Intent intent, String resolvedType, int userId) {
CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolver(userId);
if (resolver != null) {
return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
@@ -2895,7 +3008,8 @@ public class PackageManagerService extends IPackageManager.Stub
* @param intent
* @return A filtered list of resolved activities.
*/
- public List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos,
+ public final List<ResolveInfo> applyPostResolutionFilter(
+ @NonNull List<ResolveInfo> resolveInfos,
String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
boolean resolveForStart, int userId, Intent intent) {
final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
@@ -3041,7 +3155,7 @@ public class PackageManagerService extends IPackageManager.Stub
return resolveInfos;
}
- public List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
+ private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
int userId) {
final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;
@@ -3188,7 +3302,7 @@ public class PackageManagerService extends IPackageManager.Stub
return result;
}
- public PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
+ public final PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
if (ps == null) {
return null;
@@ -3258,7 +3372,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
+ public final PackageInfo getPackageInfo(String packageName, int flags, int userId) {
return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
flags, Binder.getCallingUid(), userId);
}
@@ -3269,7 +3383,7 @@ public class PackageManagerService extends IPackageManager.Stub
* to clearing. Because it can only be provided by trusted code, its value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
- public PackageInfo getPackageInfoInternal(String packageName, long versionCode,
+ public final PackageInfo getPackageInfoInternal(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForPackage(flags, userId);
@@ -3340,7 +3454,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Nullable
- public PackageSetting getPackageSetting(String packageName) {
+ public final PackageSetting getPackageSetting(String packageName) {
return getPackageSettingInternal(packageName, Binder.getCallingUid());
}
@@ -3350,7 +3464,7 @@ public class PackageManagerService extends IPackageManager.Stub
return mSettings.getPackageLPr(packageName);
}
- public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
+ public final ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
return ParceledListSlice.emptyList();
@@ -3489,7 +3603,7 @@ public class PackageManagerService extends IPackageManager.Stub
return new CrossProfileDomainInfo(forwardingInfo, highestApprovalLevel);
}
- public ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
+ public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
int sourceUserId, int targetUserId) {
ResolveInfo forwardingResolveInfo = new ResolveInfo();
final long ident = Binder.clearCallingIdentity();
@@ -3601,7 +3715,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
+ public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId);
@@ -3635,7 +3749,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Nullable
- public SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
+ public final SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
return getSharedLibraryInfo(name, version, mSharedLibraries, null);
}
@@ -3671,7 +3785,7 @@ public class PackageManagerService extends IPackageManager.Stub
return ownerUid;
}
- public String resolveExternalPackageNameLPr(AndroidPackage pkg) {
+ public final String resolveExternalPackageNameLPr(AndroidPackage pkg) {
if (pkg.getStaticSharedLibName() != null) {
return pkg.getManifestPackageName();
}
@@ -3745,7 +3859,7 @@ public class PackageManagerService extends IPackageManager.Stub
return packageName;
}
- public String resolveInternalPackageNameLPr(String packageName, long versionCode) {
+ public final String resolveInternalPackageNameLPr(String packageName, long versionCode) {
final int callingUid = Binder.getCallingUid();
return resolveInternalPackageNameInternalLocked(packageName, versionCode,
callingUid);
@@ -3766,7 +3880,7 @@ public class PackageManagerService extends IPackageManager.Stub
* calls to invalidateGetPackagesForUidCache() to locate the points at
* which the cache is invalidated.
*/
- public String[] getPackagesForUid(int uid) {
+ public final String[] getPackagesForUid(int uid) {
return getPackagesForUidInternal(uid, Binder.getCallingUid());
}
@@ -3807,7 +3921,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- public UserInfo getProfileParent(int userId) {
+ public final UserInfo getProfileParent(int userId) {
final long identity = Binder.clearCallingIdentity();
try {
return mUserManager.getProfileParent(userId);
@@ -3837,7 +3951,7 @@ public class PackageManagerService extends IPackageManager.Stub
* <li>The calling application is the default app prediction service.</li>
* </ol>
*/
- public boolean canViewInstantApps(int callingUid, int userId) {
+ public final boolean canViewInstantApps(int callingUid, int userId) {
if (callingUid < Process.FIRST_APPLICATION_UID) {
return true;
}
@@ -3861,8 +3975,8 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
- public boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
- int flags) {
+ public final boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid,
+ int userId, int flags) {
// Callers can access only the libs they depend on, otherwise they need to explicitly
// ask for the shared libraries given the caller is allowed to access all static libs.
if ((flags & PackageManager.MATCH_STATIC_SHARED_LIBRARIES) != 0) {
@@ -3945,13 +4059,13 @@ public class PackageManagerService extends IPackageManager.Stub
== PackageManager.PERMISSION_GRANTED;
}
- public boolean isCallerSameApp(String packageName, int uid) {
+ public final boolean isCallerSameApp(String packageName, int uid) {
AndroidPackage pkg = mPackages.get(packageName);
return pkg != null
&& UserHandle.getAppId(uid) == pkg.getUid();
}
- public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
+ public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
if (isComponentVisibleToInstantApp(component, TYPE_ACTIVITY)) {
return true;
}
@@ -3964,7 +4078,7 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
- public boolean isComponentVisibleToInstantApp(
+ public final boolean isComponentVisibleToInstantApp(
@Nullable ComponentName component, @ComponentType int type) {
if (type == TYPE_ACTIVITY) {
final ParsedActivity activity = mComponentResolver.getActivity(component);
@@ -4012,13 +4126,13 @@ public class PackageManagerService extends IPackageManager.Stub
* @return {@code true} if the intent is a camera intent and the persistent preferred
* activity was not set by the DPC.
*/
- public boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
- String resolvedType, int flags) {
+ public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
+ int userId, String resolvedType, int flags) {
return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
intent, userId, resolvedType, flags);
}
- public boolean isInstantApp(String packageName, int userId) {
+ public final boolean isInstantApp(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "isInstantApp");
@@ -4026,7 +4140,7 @@ public class PackageManagerService extends IPackageManager.Stub
return isInstantAppInternal(packageName, userId, callingUid);
}
- public boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
+ public final boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
int callingUid) {
if (HIDE_EPHEMERAL_APIS) {
return false;
@@ -4160,7 +4274,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- public boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
+ public final boolean isSameProfileGroup(@UserIdInt int callerUserId,
+ @UserIdInt int userId) {
final long identity = Binder.clearCallingIdentity();
try {
return UserManagerService.getInstance().isSameProfileGroup(callerUserId, userId);
@@ -4187,7 +4302,8 @@ public class PackageManagerService extends IPackageManager.Stub
*
* @see #canViewInstantApps(int, int)
*/
- public boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
+ public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
+ int callingUid,
@Nullable ComponentName component, @ComponentType int componentType, int userId) {
// if we're in an isolated process, get the real calling UID
if (Process.isIsolated(callingUid)) {
@@ -4247,7 +4363,7 @@ public class PackageManagerService extends IPackageManager.Stub
/**
* @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
*/
- public boolean shouldFilterApplicationLocked(
+ public final boolean shouldFilterApplicationLocked(
@Nullable PackageSetting ps, int callingUid, int userId) {
return shouldFilterApplicationLocked(ps, callingUid, null, TYPE_UNKNOWN, userId);
}
@@ -4255,8 +4371,8 @@ public class PackageManagerService extends IPackageManager.Stub
/**
* @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
*/
- public boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid,
- int userId) {
+ public final boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus,
+ int callingUid, int userId) {
boolean filterApp = true;
for (int index = sus.packages.size() - 1; index >= 0 && filterApp; index--) {
filterApp &= shouldFilterApplicationLocked(sus.packages.valueAt(index),
@@ -4280,7 +4396,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// NOTE: Can't remove without a major refactor. Keep around for now.
- public int checkUidPermission(String permName, int uid) {
+ public final int checkUidPermission(String permName, int uid) {
return mPermissionManager.checkUidPermission(uid, permName);
}
@@ -4330,21 +4446,21 @@ public class PackageManagerService extends IPackageManager.Stub
/**
* Update given flags when being used to request {@link ApplicationInfo}.
*/
- public int updateFlagsForApplication(int flags, int userId) {
+ public final int updateFlagsForApplication(int flags, int userId) {
return updateFlagsForPackage(flags, userId);
}
/**
* Update given flags when being used to request {@link ComponentInfo}.
*/
- public int updateFlagsForComponent(int flags, int userId) {
+ public final int updateFlagsForComponent(int flags, int userId) {
return updateFlags(flags, userId);
}
/**
* Update given flags when being used to request {@link PackageInfo}.
*/
- public int updateFlagsForPackage(int flags, int userId) {
+ public final int updateFlagsForPackage(int flags, int userId) {
final boolean isCallerSystemUser = UserHandle.getCallingUserId()
== UserHandle.USER_SYSTEM;
if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
@@ -4380,14 +4496,14 @@ public class PackageManagerService extends IPackageManager.Stub
* action and a {@code android.intent.category.BROWSABLE} category</li>
* </ul>
*/
- public int updateFlagsForResolve(int flags, int userId, int callingUid,
+ public final int updateFlagsForResolve(int flags, int userId, int callingUid,
boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
return updateFlagsForResolve(flags, userId, callingUid,
wantInstantApps, false /*onlyExposedExplicitly*/,
isImplicitImageCaptureIntentAndNotSetByDpc);
}
- public int updateFlagsForResolve(int flags, int userId, int callingUid,
+ public final int updateFlagsForResolve(int flags, int userId, int callingUid,
boolean wantInstantApps, boolean onlyExposedExplicitly,
boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
// Safe mode means we shouldn't match any third-party components
@@ -4429,7 +4545,7 @@ public class PackageManagerService extends IPackageManager.Stub
* @param checkShell whether to prevent shell from access if there's a debugging restriction
* @param message the message to log on security exception
*/
- public void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
+ public final void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message) {
if (userId < 0) {
throw new IllegalArgumentException("Invalid userId " + userId);
@@ -4467,7 +4583,7 @@ public class PackageManagerService extends IPackageManager.Stub
* @param checkShell whether to prevent shell from access if there's a debugging restriction
* @param message the message to log on security exception
*/
- public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
+ public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message) {
enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, false,
message);
@@ -4484,7 +4600,7 @@ public class PackageManagerService extends IPackageManager.Stub
* reference the same user.
* @param message the message to log on security exception
*/
- public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
+ public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
boolean requirePermissionWhenSameUser, String message) {
if (userId < 0) {
@@ -4736,31 +4852,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
/**
- * The live computer differs from the ComputerEngine in the methods that fetch data
- * from PackageManagerService.
- **/
- private static class ComputerEngineLive extends ComputerEngine {
- ComputerEngineLive(Snapshot args) {
- super(args);
- }
- protected ComponentName resolveComponentName() {
- return mService.mResolveComponentName;
- }
- protected ActivityInfo instantAppInstallerActivity() {
- return mService.mInstantAppInstallerActivity;
- }
- protected ApplicationInfo androidApplication() {
- return mService.mAndroidApplication;
- }
- }
-
- /**
- * This subclass is the external interface to the live computer. For each
- * interface, it takes the PM lock and then delegates to the live
- * computer engine. This is required because there are no locks taken in
- * the engine itself.
+ * This subclass is the external interface to the live computer. Some internal helper
+ * methods are overridden to fetch live data instead of snapshot data. For each
+ * Computer interface that is overridden in this class, the override takes the PM lock
+ * and then delegates to the live computer engine. This is required because there are
+ * no locks taken in the engine itself.
*/
- private static class ComputerLocked extends ComputerEngineLive {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ protected static class ComputerLocked extends ComputerEngine {
private final Object mLock;
ComputerLocked(Snapshot args) {
@@ -4768,18 +4867,17 @@ public class PackageManagerService extends IPackageManager.Stub
mLock = mService.mLock;
}
- /**
- * Explicilty snapshot {@link Settings#mPackages} for cases where the caller must not lock
- * in order to get package data. It is expected that the caller locks itself to be able
- * to block on changes to the package data and bring itself up to date once the change
- * propagates to it. Use with heavy caution.
- * @return
- */
- private Map<String, PackageSetting> snapshotPackageSettings() {
- return mSettings.snapshot().mPackages;
+ protected final ComponentName resolveComponentName() {
+ return mService.mResolveComponentName;
+ }
+ protected final ActivityInfo instantAppInstallerActivity() {
+ return mService.mInstantAppInstallerActivity;
+ }
+ protected final ApplicationInfo androidApplication() {
+ return mService.mAndroidApplication;
}
- public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
+ public final @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
String resolvedType, int flags, int userId, int callingUid,
String instantAppPkgName) {
synchronized (mLock) {
@@ -4787,8 +4885,8 @@ public class PackageManagerService extends IPackageManager.Stub
callingUid, instantAppPkgName);
}
}
- public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
- String resolvedType, int flags, int filterCallingUid, int userId,
+ public final @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
+ Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
String instantAppPkgName) {
synchronized (mLock) {
@@ -4797,31 +4895,31 @@ public class PackageManagerService extends IPackageManager.Stub
instantAppPkgName);
}
}
- public ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
+ public final ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
int filterCallingUid, int userId) {
synchronized (mLock) {
return super.getActivityInfoInternalBody(component, flags, filterCallingUid,
userId);
}
}
- public AndroidPackage getPackage(String packageName) {
+ public final AndroidPackage getPackage(String packageName) {
synchronized (mLock) {
return super.getPackage(packageName);
}
}
- public AndroidPackage getPackage(int uid) {
+ public final AndroidPackage getPackage(int uid) {
synchronized (mLock) {
return super.getPackage(uid);
}
}
- public ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
+ public final ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
int filterCallingUid, int userId) {
synchronized (mLock) {
return super.getApplicationInfoInternalBody(packageName, flags, filterCallingUid,
userId);
}
}
- public ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
+ public final ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
Intent intent, int matchFlags, List<ResolveInfo> candidates,
CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
synchronized (mLock) {
@@ -4829,49 +4927,49 @@ public class PackageManagerService extends IPackageManager.Stub
matchFlags, candidates, xpDomainInfo, userId, debug);
}
}
- public PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
+ public final PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
synchronized (mLock) {
return super.getPackageInfoInternalBody(packageName, versionCode, flags,
filterCallingUid, userId);
}
}
- public PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
+ public final PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
synchronized (mLock) {
return super.getPackageSettingInternal(packageName, callingUid);
}
}
- public ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
+ public final ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
int callingUid) {
synchronized (mLock) {
return super.getInstalledPackagesBody(flags, userId, callingUid);
}
}
- public ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
+ public final ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
int callingUid) {
synchronized (mLock) {
return super.getServiceInfoBody(component, flags, userId, callingUid);
}
}
- public String getInstantAppPackageName(int callingUid) {
+ public final String getInstantAppPackageName(int callingUid) {
synchronized (mLock) {
return super.getInstantAppPackageName(callingUid);
}
}
- public String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
+ public final String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
boolean isCallerInstantApp) {
synchronized (mLock) {
return super.getPackagesForUidInternalBody(callingUid, userId, appId,
isCallerInstantApp);
}
}
- public boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
+ public final boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
int callingUid) {
synchronized (mLock) {
return super.isInstantAppInternalBody(packageName, userId, callingUid);
}
}
- public boolean isInstantAppResolutionAllowedBody(Intent intent,
+ public final boolean isInstantAppResolutionAllowedBody(Intent intent,
List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
int flags) {
synchronized (mLock) {
@@ -4879,33 +4977,33 @@ public class PackageManagerService extends IPackageManager.Stub
skipPackageCheck, flags);
}
}
- public int getPackageUidInternal(String packageName, int flags, int userId,
+ public final int getPackageUidInternal(String packageName, int flags, int userId,
int callingUid) {
synchronized (mLock) {
return super.getPackageUidInternal(packageName, flags, userId, callingUid);
}
}
- public SigningDetails getSigningDetails(@NonNull String packageName) {
+ public final SigningDetails getSigningDetails(@NonNull String packageName) {
synchronized (mLock) {
return super.getSigningDetails(packageName);
}
}
- public SigningDetails getSigningDetails(int uid) {
+ public final SigningDetails getSigningDetails(int uid) {
synchronized (mLock) {
return super.getSigningDetails(uid);
}
}
- public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+ public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
synchronized (mLock) {
return super.filterAppAccess(pkg, callingUid, userId);
}
}
- public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ public final boolean filterAppAccess(String packageName, int callingUid, int userId) {
synchronized (mLock) {
return super.filterAppAccess(packageName, callingUid, userId);
}
}
- public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
+ public final void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
synchronized (mLock) {
super.dump(type, fd, pw, dumpState);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 558fb309ad98..976a588273a7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -18,7 +18,11 @@ package com.android.server.pm;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.fail;
+
import static java.lang.reflect.Modifier.isFinal;
+import static java.lang.reflect.Modifier.isPrivate;
+import static java.lang.reflect.Modifier.isProtected;
import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isStatic;
@@ -44,9 +48,12 @@ import org.junit.runner.RunWith;
import java.io.File;
import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
@@ -393,6 +400,178 @@ public class PackageManagerServiceTest {
Assert.assertEquals(3600000003L, multiPackage[1].timeouts.maxPendingTimeUs);
}
+ // Report an error from the Computer structure validation test.
+ private void flag(String name, String msg) {
+ fail(name + " " + msg);
+ }
+
+ // Return a string that identifies a Method. This is not very efficient but it is not
+ // called very often.
+ private String displayName(Method m) {
+ String r = m.getName();
+ String p = Arrays.toString(m.getGenericParameterTypes())
+ .replaceAll("([a-zA-Z0-9]+\\.)+", "")
+ .replace("class ", "")
+ .replaceAll("^\\[", "(")
+ .replaceAll("\\]$", ")");
+ return r + p;
+ }
+
+ // Match a method to an array of Methods. Matching is on method signature: name and
+ // parameter types. If a method in the declared array matches, return it. Otherwise
+ // return null.
+ private Method matchMethod(Method m, Method[] declared) {
+ String n = m.getName();
+ Type[] t = m.getGenericParameterTypes();
+ for (int i = 0; i < declared.length; i++) {
+ Method l = declared[i];
+ if (l != null && l.getName().equals(n)
+ && Arrays.equals(l.getGenericParameterTypes(), t)) {
+ Method result = l;
+ // Set the method to null since it has been visited already.
+ declared[i] = null;
+ return result;
+ }
+ }
+ return null;
+ }
+
+ // Return the boolean locked value. A null return means the annotation was not
+ // found. This method will fail if the annotation is found but is not one of the
+ // known constants.
+ private Boolean getOverride(Method m) {
+ final String name = "Computer." + displayName(m);
+ final PackageManagerService.Computer.LiveImplementation annotation =
+ m.getAnnotation(PackageManagerService.Computer.LiveImplementation.class);
+ if (annotation == null) {
+ return null;
+ }
+ final int override = annotation.override();
+ if (override == PackageManagerService.Computer.LiveImplementation.MANDATORY) {
+ return true;
+ } else if (override == PackageManagerService.Computer.LiveImplementation.NOT_ALLOWED) {
+ return false;
+ } else {
+ flag(name, "invalid Live value: " + override);
+ return null;
+ }
+ }
+
+ @Test
+ public void testComputerStructure() {
+ // Verify that Copmuter methods are properly annotated and that ComputerLocked is
+ // properly populated per annotations.
+ // Call PackageManagerService.validateComputer();
+ Class base = PackageManagerService.Computer.class;
+
+ HashMap<Method, Boolean> methodType = new HashMap<>();
+
+ // Verify that all Computer methods are annotated and that the annotation
+ // parameter locked() is valid.
+ for (Method m : base.getDeclaredMethods()) {
+ final String name = "Computer." + displayName(m);
+ Boolean override = getOverride(m);
+ if (override == null) {
+ flag(name, "missing required Live annotation");
+ }
+ methodType.put(m, override);
+ }
+
+ Class coreClass = PackageManagerService.ComputerEngine.class;
+ final Method[] coreMethods = coreClass.getDeclaredMethods();
+
+ // Examine every method in the core. If it inherits from a base method it must be
+ // "public final" if the base is NOT_ALLOWED or "public" if the base is MANDATORY.
+ // If the core method does not inherit from the base then it must be either
+ // private or protected.
+ for (Method m : base.getDeclaredMethods()) {
+ String name = "Computer." + displayName(m);
+ final boolean locked = methodType.get(m);
+ final Method core = matchMethod(m, coreMethods);
+ if (core == null) {
+ flag(name, "not overridden in ComputerEngine");
+ continue;
+ }
+ name = "ComputerEngine." + displayName(m);
+ final int modifiers = core.getModifiers();
+ if (!locked) {
+ if (!isPublic(modifiers)) {
+ flag(name, "is not public");
+ }
+ if (!isFinal(modifiers)) {
+ flag(name, "is not final");
+ }
+ }
+ }
+ // Any methods left in the coreMethods array must be private or protected.
+ // Protected methods must be overridden (and final) in the live list.
+ Method[] coreHelpers = new Method[coreMethods.length];
+ int coreIndex = 0;
+ for (Method m : coreMethods) {
+ if (m != null) {
+ final String name = "ComputerEngine." + displayName(m);
+ final int modifiers = m.getModifiers();
+ if (isPrivate(modifiers)) {
+ // Okay
+ } else if (isProtected(modifiers)) {
+ coreHelpers[coreIndex++] = m;
+ } else {
+ flag(name, "is neither private nor protected");
+ }
+ }
+ }
+
+ Class liveClass = PackageManagerService.ComputerLocked.class;
+ final Method[] liveMethods = liveClass.getDeclaredMethods();
+
+ // Examine every method in the live list. Every method must be final and must
+ // inherit either from base or core. If the method inherits from a base method
+ // then the base must be MANDATORY.
+ for (Method m : base.getDeclaredMethods()) {
+ String name = "Computer." + displayName(m);
+ final boolean locked = methodType.get(m);
+ final Method live = matchMethod(m, liveMethods);
+ if (live == null) {
+ if (locked) {
+ flag(name, "not overridden in ComputerLocked");
+ }
+ continue;
+ }
+ if (!locked) {
+ flag(name, "improperly overridden in ComputerLocked");
+ continue;
+ }
+
+ name = "ComputerLocked." + displayName(m);
+ final int modifiers = live.getModifiers();
+ if (!locked) {
+ if (!isPublic(modifiers)) {
+ flag(name, "is not public");
+ }
+ if (!isFinal(modifiers)) {
+ flag(name, "is not final");
+ }
+ }
+ }
+ for (Method m : coreHelpers) {
+ if (m == null) {
+ continue;
+ }
+ String name = "ComputerLocked." + displayName(m);
+ final Method live = matchMethod(m, liveMethods);
+ if (live == null) {
+ flag(name, "is not overridden in ComputerLocked");
+ continue;
+ }
+ }
+ for (Method m : liveMethods) {
+ if (m != null) {
+ String name = "ComputerLocked." + displayName(m);
+ flag(name, "illegal local method");
+ }
+ }
+ }
+
private static PerPackageReadTimeouts[] getPerPackageReadTimeouts(String knownDigestersList) {
final String defaultTimeouts = "3600000001:3600000002:3600000003";
List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList(