diff options
| author | 2021-06-22 00:11:11 +0000 | |
|---|---|---|
| committer | 2021-06-22 00:11:11 +0000 | |
| commit | a7ff24bf6b6cdac693814a751bad7d1125587f94 (patch) | |
| tree | 8cc4504fcdb19d5f16804c1a0eaa71e48395cac5 | |
| parent | b247011e666cac664531184bcb810e27170418bf (diff) | |
| parent | 80010e6d92515b5bde5b9bd84af2368048de4ca4 (diff) | |
Merge "Validate Computer functions" into sc-dev
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 326 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java | 179 |
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( |