diff options
462 files changed, 25939 insertions, 18542 deletions
diff --git a/Android.bp b/Android.bp index b3c9e2a720f6..ce4709752cdb 100644 --- a/Android.bp +++ b/Android.bp @@ -327,7 +327,6 @@ java_defaults { "rs/java", "sax/java", "telecomm/java", - "wifi/aidl-export", ], }, } @@ -393,7 +392,7 @@ java_defaults { exclude_srcs: [ // See comment on framework-atb-backward-compatibility module below - "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java", + "core/java/android/content/pm/AndroidTestBaseUpdater.java", ], sdk_version: "core_platform", @@ -597,7 +596,7 @@ java_library { installable: true, libs: ["app-compat-annotations"], srcs: [ - "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java", + "core/java/android/content/pm/AndroidTestBaseUpdater.java", ], } @@ -688,6 +687,7 @@ filegroup { srcs: [ "core/java/android/annotation/CallbackExecutor.java", "core/java/android/annotation/CheckResult.java", + "core/java/android/annotation/CurrentTimeMillisLong.java", "core/java/android/annotation/IntDef.java", "core/java/android/annotation/IntRange.java", "core/java/android/annotation/NonNull.java", @@ -1029,22 +1029,6 @@ aidl_interface { }, } - -subdirs = [ - "cmds/*", - "core/*", - "libs/*", - "media/*", - "proto", - "tools/*", - "native/android", - "native/graphics/jni", -] - -optional_subdirs = [ - "core/tests/utiltests/jni", -] - // TODO(b/77285514): remove this once the last few hidl interfaces have been // updated to use hwbinder.stubs. java_library { @@ -1127,7 +1111,6 @@ filegroup { srcs: [ ":framework-annotations", "core/java/android/annotation/BytesLong.java", - "core/java/android/annotation/CurrentTimeMillisLong.java", "core/java/android/annotation/CurrentTimeSecondsLong.java", "core/java/android/annotation/DurationMillisLong.java", ], @@ -1327,7 +1310,6 @@ java_library { libs: [ "framework-minus-apex", "unsupportedappusage", - "ike-stubs", ], static_libs: [ "libphonenumber-platform", diff --git a/StubLibraries.bp b/StubLibraries.bp index 4616ced1226c..7f23df74d2da 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -49,7 +49,6 @@ stubs_defaults { ":opt-net-voip-srcs", ":core-current-stubs-source", ":core_public_api_files", - ":ike-api-srcs", ], // TODO(b/147699819): remove below aidl includes. aidl: { diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java index 7b3764a999f7..aae33d7b0a89 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -96,10 +96,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.Random; import java.util.Set; /** @@ -122,8 +124,15 @@ public class BlobStoreManagerService extends SystemService { // Contains all ids that are currently in use. @GuardedBy("mBlobsLock") + private final ArraySet<Long> mActiveBlobIds = new ArraySet<>(); + // Contains all ids that are currently in use and those that were in use but got deleted in the + // current boot session. + @GuardedBy("mBlobsLock") private final ArraySet<Long> mKnownBlobIds = new ArraySet<>(); + // Random number generator for new session ids. + private final Random mRandom = new SecureRandom(); + private final Context mContext; private final Handler mHandler; private final Injector mInjector; @@ -181,7 +190,16 @@ public class BlobStoreManagerService extends SystemService { @GuardedBy("mBlobsLock") private long generateNextSessionIdLocked() { - return ++mCurrentMaxSessionId; + // Logic borrowed from PackageInstallerService. + int n = 0; + long sessionId; + do { + sessionId = Math.abs(mRandom.nextLong()); + if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != 0) { + return sessionId; + } + } while (n++ < 32); + throw new IllegalStateException("Failed to allocate session ID"); } private void registerReceivers() { @@ -228,15 +246,22 @@ public class BlobStoreManagerService extends SystemService { } @VisibleForTesting - void addKnownIdsForTest(long... knownIds) { + void addActiveIdsForTest(long... activeIds) { synchronized (mBlobsLock) { - for (long id : knownIds) { - mKnownBlobIds.add(id); + for (long id : activeIds) { + addActiveBlobIdLocked(id); } } } @VisibleForTesting + Set<Long> getActiveIdsForTest() { + synchronized (mBlobsLock) { + return mActiveBlobIds; + } + } + + @VisibleForTesting Set<Long> getKnownIdsForTest() { synchronized (mBlobsLock) { return mKnownBlobIds; @@ -246,7 +271,7 @@ public class BlobStoreManagerService extends SystemService { @GuardedBy("mBlobsLock") private void addSessionForUserLocked(BlobStoreSession session, int userId) { getUserSessionsLocked(userId).put(session.getSessionId(), session); - mKnownBlobIds.add(session.getSessionId()); + addActiveBlobIdLocked(session.getSessionId()); } @GuardedBy("mBlobsLock") @@ -258,7 +283,13 @@ public class BlobStoreManagerService extends SystemService { private void addBlobForUserLocked(BlobMetadata blobMetadata, ArrayMap<BlobHandle, BlobMetadata> userBlobs) { userBlobs.put(blobMetadata.getBlobHandle(), blobMetadata); - mKnownBlobIds.add(blobMetadata.getBlobId()); + addActiveBlobIdLocked(blobMetadata.getBlobId()); + } + + @GuardedBy("mBlobsLock") + private void addActiveBlobIdLocked(long id) { + mActiveBlobIds.add(id); + mKnownBlobIds.add(id); } private long createSessionInternal(BlobHandle blobHandle, @@ -385,24 +416,27 @@ public class BlobStoreManagerService extends SystemService { } private void onStateChangedInternal(@NonNull BlobStoreSession session) { - synchronized (mBlobsLock) { - switch (session.getState()) { - case STATE_ABANDONED: - case STATE_VERIFIED_INVALID: - session.getSessionFile().delete(); + switch (session.getState()) { + case STATE_ABANDONED: + case STATE_VERIFIED_INVALID: + session.getSessionFile().delete(); + synchronized (mBlobsLock) { getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid())) .remove(session.getSessionId()); - mKnownBlobIds.remove(session.getSessionId()); + mActiveBlobIds.remove(session.getSessionId()); if (LOGV) { Slog.v(TAG, "Session is invalid; deleted " + session); } - break; - case STATE_COMMITTED: - session.verifyBlobData(); - break; - case STATE_VERIFIED_VALID: + } + break; + case STATE_COMMITTED: + session.verifyBlobData(); + break; + case STATE_VERIFIED_VALID: + synchronized (mBlobsLock) { final int userId = UserHandle.getUserId(session.getOwnerUid()); - final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId); + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked( + userId); BlobMetadata blob = userBlobs.get(session.getBlobHandle()); if (blob == null) { blob = new BlobMetadata(mContext, @@ -425,11 +459,13 @@ public class BlobStoreManagerService extends SystemService { if (LOGV) { Slog.v(TAG, "Successfully committed session " + session); } - break; - default: - Slog.wtf(TAG, "Invalid session state: " - + stateToString(session.getState())); - } + } + break; + default: + Slog.wtf(TAG, "Invalid session state: " + + stateToString(session.getState())); + } + synchronized (mBlobsLock) { try { writeBlobSessionsLocked(); } catch (Exception e) { @@ -486,6 +522,9 @@ public class BlobStoreManagerService extends SystemService { if (sessionsIndexFile == null) { Slog.wtf(TAG, "Error creating sessions index file"); return; + } else if (!sessionsIndexFile.exists()) { + Slog.w(TAG, "Sessions index file not available: " + sessionsIndexFile.getBaseFile()); + return; } mSessions.clear(); @@ -575,6 +614,9 @@ public class BlobStoreManagerService extends SystemService { if (blobsIndexFile == null) { Slog.wtf(TAG, "Error creating blobs index file"); return; + } else if (!blobsIndexFile.exists()) { + Slog.w(TAG, "Blobs index file not available: " + blobsIndexFile.getBaseFile()); + return; } mBlobsMap.clear(); @@ -699,7 +741,7 @@ public class BlobStoreManagerService extends SystemService { if (session.getOwnerUid() == uid && session.getOwnerPackageName().equals(packageName)) { session.getSessionFile().delete(); - mKnownBlobIds.remove(session.getSessionId()); + mActiveBlobIds.remove(session.getSessionId()); indicesToRemove.add(i); } } @@ -719,7 +761,7 @@ public class BlobStoreManagerService extends SystemService { // Delete the blob if it doesn't have any active leases. if (!blobMetadata.hasLeases()) { blobMetadata.getBlobFile().delete(); - mKnownBlobIds.remove(blobMetadata.getBlobId()); + mActiveBlobIds.remove(blobMetadata.getBlobId()); indicesToRemove.add(i); } } @@ -742,7 +784,7 @@ public class BlobStoreManagerService extends SystemService { for (int i = 0, count = userSessions.size(); i < count; ++i) { final BlobStoreSession session = userSessions.valueAt(i); session.getSessionFile().delete(); - mKnownBlobIds.remove(session.getSessionId()); + mActiveBlobIds.remove(session.getSessionId()); } } @@ -752,7 +794,7 @@ public class BlobStoreManagerService extends SystemService { for (int i = 0, count = userBlobs.size(); i < count; ++i) { final BlobMetadata blobMetadata = userBlobs.valueAt(i); blobMetadata.getBlobFile().delete(); - mKnownBlobIds.remove(blobMetadata.getBlobId()); + mActiveBlobIds.remove(blobMetadata.getBlobId()); } } if (LOGV) { @@ -772,7 +814,7 @@ public class BlobStoreManagerService extends SystemService { for (File file : blobsDir.listFiles()) { try { final long id = Long.parseLong(file.getName()); - if (mKnownBlobIds.indexOf(id) < 0) { + if (mActiveBlobIds.indexOf(id) < 0) { filesToDelete.add(file); deletedBlobIds.add(id); } @@ -807,7 +849,7 @@ public class BlobStoreManagerService extends SystemService { if (shouldRemove) { blobMetadata.getBlobFile().delete(); - mKnownBlobIds.remove(blobMetadata.getBlobId()); + mActiveBlobIds.remove(blobMetadata.getBlobId()); deletedBlobIds.add(blobMetadata.getBlobId()); } return shouldRemove; @@ -837,7 +879,7 @@ public class BlobStoreManagerService extends SystemService { if (shouldRemove) { blobStoreSession.getSessionFile().delete(); - mKnownBlobIds.remove(blobStoreSession.getSessionId()); + mActiveBlobIds.remove(blobStoreSession.getSessionId()); indicesToRemove.add(j); deletedBlobIds.add(blobStoreSession.getSessionId()); } @@ -884,7 +926,7 @@ public class BlobStoreManagerService extends SystemService { } blobMetadata.getBlobFile().delete(); userBlobs.remove(blobHandle); - mKnownBlobIds.remove(blobMetadata.getBlobId()); + mActiveBlobIds.remove(blobMetadata.getBlobId()); writeBlobsInfoAsync(); } } diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java index dc72d6d9c4b3..f8b598a43db6 100644 --- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java @@ -147,7 +147,7 @@ public interface AppStandbyInternal { void postReportExemptedSyncStart(String packageName, int userId); - void dumpUser(IndentingPrintWriter idpw, int userId, String pkg); + void dumpUser(IndentingPrintWriter idpw, int userId, List<String> pkgs); void dumpState(String[] args, PrintWriter pw); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index 789f20b44ce0..b63cc1918a7a 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -39,6 +39,7 @@ import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import com.android.server.job.GrantedUriPermissions; @@ -97,6 +98,15 @@ public final class JobStatus { | CONSTRAINT_IDLE; /** + * Standard media URIs that contain the media files that might be important to the user. + * @see #mHasMediaBackupExemption + */ + private static final Uri[] MEDIA_URIS_FOR_STANDBY_EXEMPTION = { + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + MediaStore.Video.Media.EXTERNAL_CONTENT_URI, + }; + + /** * The constraints that we want to log to statsd. * * Constraints that can be inferred from other atoms have been excluded to avoid logging too @@ -441,13 +451,13 @@ public final class JobStatus { if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) { requiredConstraints |= CONSTRAINT_DEADLINE; } - boolean mediaOnly = false; + boolean exemptedMediaUrisOnly = false; if (job.getTriggerContentUris() != null) { requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER; - mediaOnly = true; + exemptedMediaUrisOnly = true; for (JobInfo.TriggerContentUri uri : job.getTriggerContentUris()) { - if (!MediaStore.AUTHORITY.equals(uri.getUri().getAuthority())) { - mediaOnly = false; + if (!ArrayUtils.contains(MEDIA_URIS_FOR_STANDBY_EXEMPTION, uri.getUri())) { + exemptedMediaUrisOnly = false; break; } } @@ -475,8 +485,8 @@ public final class JobStatus { job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid); } final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class); - mHasMediaBackupExemption = !job.hasLateConstraint() && mediaOnly && requiresNetwork - && this.sourcePackageName.equals(jsi.getMediaBackupPackage()); + mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly + && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage()); } /** Copy constructor: used specifically when cloning JobStatus objects for persistence, diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java index 9d6e012da89b..932c25d7bd0e 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java @@ -41,6 +41,7 @@ import android.util.TimeUtils; import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; @@ -58,6 +59,7 @@ import java.io.FileReader; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.List; /** * Keeps track of recent active state changes in apps. @@ -721,7 +723,7 @@ public class AppIdleHistory { } } - public void dump(IndentingPrintWriter idpw, int userId, String pkg) { + public void dump(IndentingPrintWriter idpw, int userId, List<String> pkgs) { idpw.println("App Standby States:"); idpw.increaseIndent(); ArrayMap<String, AppUsageHistory> userHistory = mIdleHistory.get(userId); @@ -733,7 +735,7 @@ public class AppIdleHistory { for (int p = 0; p < P; p++) { final String packageName = userHistory.keyAt(p); final AppUsageHistory appUsageHistory = userHistory.valueAt(p); - if (pkg != null && !pkg.equals(packageName)) { + if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(packageName)) { continue; } idpw.print("package=" + packageName); diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index e343478ec61f..a4ab31d7b49a 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -65,6 +65,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; +import android.content.pm.CrossProfileAppsInternal; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; @@ -283,6 +284,12 @@ public class AppStandbyController implements AppStandbyInternal { * start is the first usage of the app */ long mInitialForegroundServiceStartTimeoutMillis; + /** + * User usage that would elevate an app's standby bucket will also elevate the standby bucket of + * cross profile connected apps. Explicit standby bucket setting via + * {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated. + */ + boolean mLinkCrossProfileApps; private volatile boolean mAppIdleEnabled; private boolean mIsCharging; @@ -445,10 +452,12 @@ public class AppStandbyController implements AppStandbyInternal { continue; } if (!packageName.equals(providerPkgName)) { + final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, + userId); synchronized (mAppIdleLock) { - reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_ACTIVE, - REASON_SUB_USAGE_SYNC_ADAPTER, elapsedRealtime, - mSyncAdapterTimeoutMillis); + reportNoninteractiveUsageCrossUserLocked(packageName, userId, + STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER, + elapsedRealtime, mSyncAdapterTimeoutMillis, linkedProfiles); } } } catch (PackageManager.NameNotFoundException e) { @@ -477,10 +486,10 @@ public class AppStandbyController implements AppStandbyInternal { } final long elapsedRealtime = mInjector.elapsedRealtime(); - + final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId); synchronized (mAppIdleLock) { - reportNoninteractiveUsageLocked(packageName, userId, bucketToPromote, - usageReason, elapsedRealtime, durationMillis); + reportNoninteractiveUsageCrossUserLocked(packageName, userId, bucketToPromote, + usageReason, elapsedRealtime, durationMillis, linkedProfiles); } } @@ -492,10 +501,11 @@ public class AppStandbyController implements AppStandbyInternal { final int currentBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime); if (currentBucket == STANDBY_BUCKET_NEVER) { + final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId); // Bring the app out of the never bucket - reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_WORKING_SET, - REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED, elapsedRealtime, - mUnexemptedSyncScheduledTimeoutMillis); + reportNoninteractiveUsageCrossUserLocked(packageName, userId, + STANDBY_BUCKET_WORKING_SET, REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED, + elapsedRealtime, mUnexemptedSyncScheduledTimeoutMillis, linkedProfiles); } } } @@ -504,14 +514,39 @@ public class AppStandbyController implements AppStandbyInternal { if (!mAppIdleEnabled) return; final long elapsedRealtime = mInjector.elapsedRealtime(); - + final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId); synchronized (mAppIdleLock) { - reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_ACTIVE, + reportNoninteractiveUsageCrossUserLocked(packageName, userId, STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_EXEMPTED_SYNC_START, elapsedRealtime, - mExemptedSyncStartTimeoutMillis); + mExemptedSyncStartTimeoutMillis, linkedProfiles); + } + } + + /** + * Helper method to report indirect user usage of an app and handle reporting the usage + * against cross profile connected apps. <br> + * Use {@link #reportNoninteractiveUsageLocked(String, int, int, int, long, long)} if + * cross profile connected apps do not need to be handled. + */ + private void reportNoninteractiveUsageCrossUserLocked(String packageName, int userId, + int bucket, int subReason, long elapsedRealtime, long nextCheckDelay, + List<UserHandle> otherProfiles) { + reportNoninteractiveUsageLocked(packageName, userId, bucket, subReason, elapsedRealtime, + nextCheckDelay); + final int size = otherProfiles.size(); + for (int profileIndex = 0; profileIndex < size; profileIndex++) { + final int otherUserId = otherProfiles.get(profileIndex).getIdentifier(); + reportNoninteractiveUsageLocked(packageName, otherUserId, bucket, subReason, + elapsedRealtime, nextCheckDelay); } } + /** + * Helper method to report indirect user usage of an app. <br> + * Use + * {@link #reportNoninteractiveUsageCrossUserLocked(String, int, int, int, long, long, List)} + * if cross profile connected apps need to be handled. + */ private void reportNoninteractiveUsageLocked(String packageName, int userId, int bucket, int subReason, long elapsedRealtime, long nextCheckDelay) { final AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, bucket, @@ -766,8 +801,16 @@ public class AppStandbyController implements AppStandbyInternal { || eventType == UsageEvents.Event.SLICE_PINNED || eventType == UsageEvents.Event.SLICE_PINNED_PRIV || eventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) { + final String pkg = event.getPackageName(); + final List<UserHandle> linkedProfiles = getCrossProfileTargets(pkg, userId); synchronized (mAppIdleLock) { - reportEventLocked(event.getPackageName(), eventType, elapsedRealtime, userId); + reportEventLocked(pkg, eventType, elapsedRealtime, userId); + + final int size = linkedProfiles.size(); + for (int profileIndex = 0; profileIndex < size; profileIndex++) { + final int linkedUserId = linkedProfiles.get(profileIndex).getIdentifier(); + reportEventLocked(pkg, eventType, elapsedRealtime, linkedUserId); + } } } } @@ -826,6 +869,16 @@ public class AppStandbyController implements AppStandbyInternal { } } + /** + * Note: don't call this with the lock held since it makes calls to other system services. + */ + private @NonNull List<UserHandle> getCrossProfileTargets(String pkg, int userId) { + synchronized (mAppIdleLock) { + if (!mLinkCrossProfileApps) return Collections.emptyList(); + } + return mInjector.getValidCrossProfileTargets(pkg, userId); + } + private int usageEventToSubReason(int eventType) { switch (eventType) { case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND; @@ -1505,9 +1558,9 @@ public class AppStandbyController implements AppStandbyInternal { } @Override - public void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) { + public void dumpUser(IndentingPrintWriter idpw, int userId, List<String> pkgs) { synchronized (mAppIdleLock) { - mAppIdleHistory.dump(idpw, userId, pkg); + mAppIdleHistory.dump(idpw, userId, pkgs); } } @@ -1589,6 +1642,7 @@ public class AppStandbyController implements AppStandbyInternal { private PackageManagerInternal mPackageManagerInternal; private DisplayManager mDisplayManager; private PowerManager mPowerManager; + private CrossProfileAppsInternal mCrossProfileAppsInternal; int mBootPhase; /** * The minimum amount of time required since the last user interaction before an app can be @@ -1620,6 +1674,8 @@ public class AppStandbyController implements AppStandbyInternal { Context.DISPLAY_SERVICE); mPowerManager = mContext.getSystemService(PowerManager.class); mBatteryManager = mContext.getSystemService(BatteryManager.class); + mCrossProfileAppsInternal = LocalServices.getService( + CrossProfileAppsInternal.class); final ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); @@ -1727,6 +1783,17 @@ public class AppStandbyController implements AppStandbyInternal { public boolean isDeviceIdleMode() { return mPowerManager.isDeviceIdleMode(); } + + public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) { + final int uid = mPackageManagerInternal.getPackageUidInternal(pkg, 0, userId); + if (uid < 0 + || !mPackageManagerInternal.getPackage(uid).isCrossProfile() + || !mCrossProfileAppsInternal + .verifyUidHasInteractAcrossProfilePermission(pkg, uid)) { + return Collections.emptyList(); + } + return mCrossProfileAppsInternal.getTargetUserProfiles(pkg, userId); + } } class AppStandbyHandler extends Handler { @@ -1857,6 +1924,8 @@ public class AppStandbyController implements AppStandbyInternal { "initial_foreground_service_start_duration"; private static final String KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS = "auto_restricted_bucket_delay_ms"; + private static final String KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = + "cross_profile_apps_share_standby_buckets"; public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR; public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR; public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR; @@ -1868,6 +1937,7 @@ public class AppStandbyController implements AppStandbyInternal { public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE; public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE; public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS = ONE_DAY; + public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -1973,6 +2043,10 @@ public class AppStandbyController implements AppStandbyInternal { mParser.getDurationMillis(KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS)); + + mLinkCrossProfileApps = mParser.getBoolean( + KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS, + DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS); } // Check if app_idle_enabled has changed. Do this after getting the rest of the settings diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index 7d18578aff66..1ae0c22541c2 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -375,13 +375,13 @@ public final class MediaParser { } /** - * Thrown if all extractors implementations provided to {@link #create} failed to sniff the - * input content. + * Thrown if all parser implementations provided to {@link #create} failed to sniff the input + * content. */ public static final class UnrecognizedInputFormatException extends IOException { /** - * Creates a new instance which signals that the extractors with the given names failed to + * Creates a new instance which signals that the parsers with the given names failed to * parse the input. */ @NonNull @@ -389,7 +389,7 @@ public final class MediaParser { private static UnrecognizedInputFormatException createForExtractors( @NonNull String... extractorNames) { StringBuilder builder = new StringBuilder(); - builder.append("None of the available extractors ( "); + builder.append("None of the available parsers ( "); builder.append(extractorNames[0]); for (int i = 1; i < extractorNames.length; i++) { builder.append(", "); @@ -411,10 +411,10 @@ public final class MediaParser { // Instance creation methods. /** - * Creates an instance backed by the extractor with the given {@code name}. The returned - * instance will attempt extraction without sniffing the content. + * Creates an instance backed by the parser with the given {@code name}. The returned instance + * will attempt parsing without sniffing the content. * - * @param name The name of the extractor that will be associated with the created instance. + * @param name The name of the parser that will be associated with the created instance. * @param outputConsumer The {@link OutputConsumer} to which track data and samples are pushed. * @return A new instance. * @throws IllegalArgumentException If an invalid name is provided. @@ -428,42 +428,42 @@ public final class MediaParser { } /** - * Creates an instance whose backing extractor will be selected by sniffing the content during - * the first {@link #advance} call. Extractor implementations will sniff the content in order of - * appearance in {@code extractorNames}. + * Creates an instance whose backing parser will be selected by sniffing the content during the + * first {@link #advance} call. Parser implementations will sniff the content in order of + * appearance in {@code parserNames}. * * @param outputConsumer The {@link OutputConsumer} to which extracted data is output. - * @param extractorNames The names of the extractors to sniff the content with. If empty, a - * default array of names is used. + * @param parserNames The names of the parsers to sniff the content with. If empty, a default + * array of names is used. * @return A new instance. */ @NonNull public static MediaParser create( - @NonNull OutputConsumer outputConsumer, @NonNull String... extractorNames) { - assertValidNames(extractorNames); - if (extractorNames.length == 0) { - extractorNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]); + @NonNull OutputConsumer outputConsumer, @NonNull String... parserNames) { + assertValidNames(parserNames); + if (parserNames.length == 0) { + parserNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]); } - return new MediaParser(outputConsumer, /* sniff= */ true, extractorNames); + return new MediaParser(outputConsumer, /* sniff= */ true, parserNames); } // Misc static methods. /** - * Returns an immutable list with the names of the extractors that are suitable for container + * Returns an immutable list with the names of the parsers that are suitable for container * formats with the given {@link MediaFormat}. * * <p>TODO: List which properties are taken into account. E.g. MimeType. */ @NonNull - public static List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) { + public static List<String> getParserNames(@NonNull MediaFormat mediaFormat) { throw new UnsupportedOperationException(); } // Private fields. private final OutputConsumer mOutputConsumer; - private final String[] mExtractorNamesPool; + private final String[] mParserNamesPool; private final PositionHolder mPositionHolder; private final InputReadingDataSource mDataSource; private final ExtractorInputAdapter mScratchExtractorInputAdapter; @@ -477,18 +477,18 @@ public final class MediaParser { // Public methods. /** - * Returns the name of the backing extractor implementation. + * Returns the name of the backing parser implementation. * * <p>If this instance was creating using {@link #createByName}, the provided name is returned. * If this instance was created using {@link #create}, this method will return null until the - * first call to {@link #advance}, after which the name of the backing extractor implementation - * is returned. + * first call to {@link #advance}, after which the name of the backing parser implementation is + * returned. * - * @return The name of the backing extractor implementation, or null if the backing extractor + * @return The name of the backing parser implementation, or null if the backing parser * implementation has not yet been selected. */ @Nullable - public String getExtractorName() { + public String getParserName() { return mExtractorName; } @@ -499,7 +499,7 @@ public final class MediaParser { * <p>This method will block until some progress has been made. * * <p>If this instance was created using {@link #create}. the first call to this method will - * sniff the content with the extractors with the provided names. + * sniff the content with the parsers with the provided names. * * @param seekableInputReader The {@link SeekableInputReader} from which to obtain the media * container data. @@ -520,13 +520,15 @@ public final class MediaParser { } mDataSource.mInputReader = seekableInputReader; - if (mExtractor == null) { - for (String extractorName : mExtractorNamesPool) { - Extractor extractor = - EXTRACTOR_FACTORIES_BY_NAME.get(extractorName).createInstance(); + // TODO: Apply parameters when creating extractor instances. + if (mExtractorName != null) { + mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance(); + } else if (mExtractor == null) { + for (String parserName : mParserNamesPool) { + Extractor extractor = EXTRACTOR_FACTORIES_BY_NAME.get(parserName).createInstance(); try { if (extractor.sniff(mExtractorInput)) { - mExtractorName = extractorName; + mExtractorName = parserName; mExtractor = extractor; mExtractor.init(new ExtractorOutputAdapter()); break; @@ -540,7 +542,7 @@ public final class MediaParser { } } if (mExtractor == null) { - throw UnrecognizedInputFormatException.createForExtractors(mExtractorNamesPool); + throw UnrecognizedInputFormatException.createForExtractors(mParserNamesPool); } return true; } @@ -586,22 +588,21 @@ public final class MediaParser { * Releases any acquired resources. * * <p>After calling this method, this instance becomes unusable and no other methods should be - * invoked. DESIGN NOTE: Should be removed. There shouldn't be any resource for releasing. + * invoked. */ public void release() { + // TODO: Dump media metrics here. mExtractorInput = null; mExtractor = null; } // Private methods. - private MediaParser( - OutputConsumer outputConsumer, boolean sniff, String... extractorNamesPool) { + private MediaParser(OutputConsumer outputConsumer, boolean sniff, String... parserNamesPool) { mOutputConsumer = outputConsumer; - mExtractorNamesPool = extractorNamesPool; + mParserNamesPool = parserNamesPool; if (!sniff) { - mExtractorName = extractorNamesPool[0]; - mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance(); + mExtractorName = parserNamesPool[0]; } mPositionHolder = new PositionHolder(); mDataSource = new InputReadingDataSource(); @@ -921,7 +922,7 @@ public final class MediaParser { throw new IllegalArgumentException( "Invalid extractor name: " + name - + ". Supported extractors are: " + + ". Supported parsers are: " + TextUtils.join(", ", EXTRACTOR_FACTORIES_BY_NAME.keySet()) + "."); } @@ -933,20 +934,20 @@ public final class MediaParser { static { // Using a LinkedHashMap to keep the insertion order when iterating over the keys. LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>(); - extractorFactoriesByName.put("exo.Ac3Extractor", Ac3Extractor::new); - extractorFactoriesByName.put("exo.Ac4Extractor", Ac4Extractor::new); - extractorFactoriesByName.put("exo.AdtsExtractor", AdtsExtractor::new); - extractorFactoriesByName.put("exo.AmrExtractor", AmrExtractor::new); - extractorFactoriesByName.put("exo.FlacExtractor", FlacExtractor::new); - extractorFactoriesByName.put("exo.FlvExtractor", FlvExtractor::new); - extractorFactoriesByName.put("exo.FragmentedMp4Extractor", FragmentedMp4Extractor::new); - extractorFactoriesByName.put("exo.MatroskaExtractor", MatroskaExtractor::new); - extractorFactoriesByName.put("exo.Mp3Extractor", Mp3Extractor::new); - extractorFactoriesByName.put("exo.Mp4Extractor", Mp4Extractor::new); - extractorFactoriesByName.put("exo.OggExtractor", OggExtractor::new); - extractorFactoriesByName.put("exo.PsExtractor", PsExtractor::new); - extractorFactoriesByName.put("exo.TsExtractor", TsExtractor::new); - extractorFactoriesByName.put("exo.WavExtractor", WavExtractor::new); + extractorFactoriesByName.put("exo.Ac3Parser", Ac3Extractor::new); + extractorFactoriesByName.put("exo.Ac4Parser", Ac4Extractor::new); + extractorFactoriesByName.put("exo.AdtsParser", AdtsExtractor::new); + extractorFactoriesByName.put("exo.AmrParser", AmrExtractor::new); + extractorFactoriesByName.put("exo.FlacParser", FlacExtractor::new); + extractorFactoriesByName.put("exo.FlvParser", FlvExtractor::new); + extractorFactoriesByName.put("exo.FragmentedMp4Parser", FragmentedMp4Extractor::new); + extractorFactoriesByName.put("exo.MatroskaParser", MatroskaExtractor::new); + extractorFactoriesByName.put("exo.Mp3Parser", Mp3Extractor::new); + extractorFactoriesByName.put("exo.Mp4Parser", Mp4Extractor::new); + extractorFactoriesByName.put("exo.OggParser", OggExtractor::new); + extractorFactoriesByName.put("exo.PsParser", PsExtractor::new); + extractorFactoriesByName.put("exo.TsParser", TsExtractor::new); + extractorFactoriesByName.put("exo.WavParser", WavExtractor::new); EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName); } } diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java index 6c7f82a11908..0d163cf55e4e 100644 --- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java +++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java @@ -40,7 +40,7 @@ public interface RuntimePermissionsPersistence { * @return the runtime permissions read */ @Nullable - RuntimePermissionsState read(@NonNull UserHandle user); + RuntimePermissionsState readAsUser(@NonNull UserHandle user); /** * Write the runtime permissions to persistence. @@ -50,7 +50,7 @@ public interface RuntimePermissionsPersistence { * @param runtimePermissions the runtime permissions to write * @param user the user to write for */ - void write(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user); + void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user); /** * Delete the runtime permissions from persistence. @@ -59,7 +59,7 @@ public interface RuntimePermissionsPersistence { * * @param user the user to delete for */ - void delete(@NonNull UserHandle user); + void deleteAsUser(@NonNull UserHandle user); /** * Create a new instance of {@link RuntimePermissionsPersistence} implementation. diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java index 90b1c4b6ff5f..205ffc297945 100644 --- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java +++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java @@ -67,7 +67,7 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers @Nullable @Override - public RuntimePermissionsState read(@NonNull UserHandle user) { + public RuntimePermissionsState readAsUser(@NonNull UserHandle user) { File file = getFile(user); try (FileInputStream inputStream = new AtomicFile(file).openRead()) { XmlPullParser parser = Xml.newPullParser(); @@ -172,7 +172,7 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers } @Override - public void write(@NonNull RuntimePermissionsState runtimePermissions, + public void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user) { File file = getFile(user); AtomicFile atomicFile = new AtomicFile(file); @@ -252,7 +252,7 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers } @Override - public void delete(@NonNull UserHandle user) { + public void deleteAsUser(@NonNull UserHandle user) { getFile(user).delete(); } diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java index 2908a3872df9..64d6545c87cf 100644 --- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java +++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java @@ -40,7 +40,7 @@ public interface RolesPersistence { * @return the roles read */ @Nullable - RolesState read(@NonNull UserHandle user); + RolesState readAsUser(@NonNull UserHandle user); /** * Write the roles to persistence. @@ -50,7 +50,7 @@ public interface RolesPersistence { * @param roles the roles to write * @param user the user to write for */ - void write(@NonNull RolesState roles, @NonNull UserHandle user); + void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user); /** * Delete the roles from persistence. @@ -59,7 +59,7 @@ public interface RolesPersistence { * * @param user the user to delete for */ - void delete(@NonNull UserHandle user); + void deleteAsUser(@NonNull UserHandle user); /** * Create a new instance of {@link RolesPersistence} implementation. diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java index 06fad77c495c..3031c8213982 100644 --- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java +++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java @@ -65,7 +65,7 @@ public class RolesPersistenceImpl implements RolesPersistence { @Nullable @Override - public RolesState read(@NonNull UserHandle user) { + public RolesState readAsUser(@NonNull UserHandle user) { File file = getFile(user); try (FileInputStream inputStream = new AtomicFile(file).openRead()) { XmlPullParser parser = Xml.newPullParser(); @@ -146,8 +146,7 @@ public class RolesPersistenceImpl implements RolesPersistence { } @Override - public void write(@NonNull RolesState roles, - @NonNull UserHandle user) { + public void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user) { File file = getFile(user); AtomicFile atomicFile = new AtomicFile(file); FileOutputStream outputStream = null; @@ -206,7 +205,7 @@ public class RolesPersistenceImpl implements RolesPersistence { } @Override - public void delete(@NonNull UserHandle user) { + public void deleteAsUser(@NonNull UserHandle user) { getFile(user).delete(); } diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp index 0e9311034ee0..2f3e2acb5d7a 100644 --- a/apex/statsd/Android.bp +++ b/apex/statsd/Android.bp @@ -21,14 +21,16 @@ apex { apex_defaults { native_shared_libs: [ "libstats_jni", + "libstatspull", + "libstatssocket", ], - // binaries: ["vold"], + binaries: ["statsd"], java_libs: [ "framework-statsd", "service-statsd", ], compile_multilib: "both", - // prebuilts: ["my_prebuilt"], + prebuilts: ["com.android.os.statsd.init.rc"], name: "com.android.os.statsd-defaults", key: "com.android.os.statsd.key", certificate: ":com.android.os.statsd.certificate", @@ -47,6 +49,12 @@ android_app_certificate { certificate: "com.android.os.statsd", } +prebuilt_etc { + name: "com.android.os.statsd.init.rc", + src: "statsd.rc", + filename: "init.rc", + installable: false, +} // JNI library for StatsLog.write cc_library_shared { diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp index f7a817667f30..487c8e1b216d 100644 --- a/apex/statsd/aidl/Android.bp +++ b/apex/statsd/aidl/Android.bp @@ -38,6 +38,13 @@ aidl_interface { }, ndk: { enabled: true, - } + apex_available: [ + // TODO(b/145923087): Remove this once statsd binary is in apex + "//apex_available:platform", + + "com.android.os.statsd", + "test_com.android.os.statsd", + ], + }, } } diff --git a/cmds/statsd/statsd.rc b/apex/statsd/statsd.rc index a98ecd586b42..605da2af0c19 100644 --- a/cmds/statsd/statsd.rc +++ b/apex/statsd/statsd.rc @@ -12,19 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -service statsd /system/bin/statsd +service statsd /apex/com.android.os.statsd/bin/statsd class main socket statsdw dgram+passcred 0222 statsd statsd user statsd group statsd log writepid /dev/cpuset/system-background/tasks - -on property:ro.statsd.enable=false - stop statsd - -on post-fs-data - # Create directory for statsd - mkdir /data/misc/stats-data/ 0770 statsd system - mkdir /data/misc/stats-service/ 0770 statsd system - mkdir /data/misc/stats-active-metric/ 0770 statsd system - mkdir /data/misc/train-info/ 0770 statsd system diff --git a/api/current.txt b/api/current.txt index 51ae4a85baa5..1e65e7bdfc9e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -9,6 +9,7 @@ package android { ctor public Manifest.permission(); field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER"; field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION"; + field public static final String ACCESS_CALL_AUDIO = "android.permission.ACCESS_CALL_AUDIO"; field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES"; field public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION"; field public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION"; @@ -2982,7 +2983,6 @@ package android.accessibilityservice { method public int describeContents(); method public static String feedbackTypeToString(int); method public static String flagToString(int); - method public int getAnimatedImageRes(); method @Deprecated public boolean getCanRetrieveWindowContent(); method public int getCapabilities(); method @Deprecated public String getDescription(); @@ -2991,6 +2991,7 @@ package android.accessibilityservice { method public int getNonInteractiveUiTimeoutMillis(); method public android.content.pm.ResolveInfo getResolveInfo(); method public String getSettingsActivityName(); + method @Nullable public android.graphics.drawable.Drawable loadAnimatedImage(@NonNull android.content.pm.PackageManager); method public String loadDescription(android.content.pm.PackageManager); method @Nullable public String loadHtmlDescription(@NonNull android.content.pm.PackageManager); method public CharSequence loadSummary(android.content.pm.PackageManager); @@ -12327,6 +12328,7 @@ package android.content.pm { method public int describeContents(); method public void dump(android.util.Printer, String); method public final int getIconResource(); + method public boolean isCrossProfileIntentForwarderActivity(); method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public CharSequence loadLabel(android.content.pm.PackageManager); method public void writeToParcel(android.os.Parcel, int); @@ -12465,6 +12467,7 @@ package android.content.pm { method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(int); method public boolean isRateLimitingActive(); method public boolean isRequestPinShortcutSupported(); + method public void pushDynamicShortcut(@NonNull android.content.pm.ShortcutInfo); method public void removeAllDynamicShortcuts(); method public void removeDynamicShortcuts(@NonNull java.util.List<java.lang.String>); method public void removeLongLivedShortcuts(@NonNull java.util.List<java.lang.String>); @@ -23174,7 +23177,7 @@ package android.inputmethodservice { method public void onConfigureWindow(android.view.Window, boolean, boolean); method public android.view.View onCreateCandidatesView(); method public android.view.View onCreateExtractTextView(); - method @Nullable public android.view.inputmethod.InlineSuggestionsRequest onCreateInlineSuggestionsRequest(); + method @Nullable public android.view.inputmethod.InlineSuggestionsRequest onCreateInlineSuggestionsRequest(@NonNull android.os.Bundle); method public android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface(); method public android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface(); method public android.view.View onCreateInputView(); @@ -23489,66 +23492,54 @@ package android.location { } public final class GnssAntennaInfo implements android.os.Parcelable { - ctor public GnssAntennaInfo(double, @NonNull android.location.GnssAntennaInfo.PhaseCenterOffsetCoordinates, @Nullable android.location.GnssAntennaInfo.PhaseCenterVariationCorrections, @Nullable android.location.GnssAntennaInfo.SignalGainCorrections); method public int describeContents(); - method public double getCarrierFrequencyMHz(); - method @NonNull public android.location.GnssAntennaInfo.PhaseCenterOffsetCoordinates getPhaseCenterOffsetCoordinates(); - method @Nullable public android.location.GnssAntennaInfo.PhaseCenterVariationCorrections getPhaseCenterVariationCorrections(); - method @Nullable public android.location.GnssAntennaInfo.SignalGainCorrections getSignalGainCorrections(); + method @FloatRange(from=0.0f) public double getCarrierFrequencyMHz(); + method @NonNull public android.location.GnssAntennaInfo.PhaseCenterOffset getPhaseCenterOffset(); + method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getPhaseCenterVariationCorrections(); + method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getSignalGainCorrections(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo> CREATOR; } - public abstract static class GnssAntennaInfo.Callback { - ctor public GnssAntennaInfo.Callback(); + public static class GnssAntennaInfo.Builder { + ctor public GnssAntennaInfo.Builder(); + method @NonNull public android.location.GnssAntennaInfo build(); + method @NonNull public android.location.GnssAntennaInfo.Builder setCarrierFrequencyMHz(@FloatRange(from=0.0f) double); + method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterOffset(@NonNull android.location.GnssAntennaInfo.PhaseCenterOffset); + method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterVariationCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections); + method @NonNull public android.location.GnssAntennaInfo.Builder setSignalGainCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections); + } + + public static interface GnssAntennaInfo.Listener { method public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>); - method public void onStatusChanged(int); - field public static final int STATUS_LOCATION_DISABLED = 2; // 0x2 - field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0 - field public static final int STATUS_READY = 1; // 0x1 } - public static final class GnssAntennaInfo.PhaseCenterOffsetCoordinates implements android.os.Parcelable { - ctor public GnssAntennaInfo.PhaseCenterOffsetCoordinates(double, double, double, double, double, double); + public static final class GnssAntennaInfo.PhaseCenterOffset implements android.os.Parcelable { + ctor public GnssAntennaInfo.PhaseCenterOffset(double, double, double, double, double, double); method public int describeContents(); - method public double getXCoordMillimeters(); - method public double getXCoordUncertaintyMillimeters(); - method public double getYCoordMillimeters(); - method public double getYCoordUncertaintyMillimeters(); - method public double getZCoordMillimeters(); - method public double getZCoordUncertaintyMillimeters(); + method @FloatRange public double getXOffsetMm(); + method @FloatRange public double getXOffsetUncertaintyMm(); + method @FloatRange public double getYOffsetMm(); + method @FloatRange public double getYOffsetUncertaintyMm(); + method @FloatRange public double getZOffsetMm(); + method @FloatRange public double getZOffsetUncertaintyMm(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterOffsetCoordinates> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterOffset> CREATOR; } - public static final class GnssAntennaInfo.PhaseCenterVariationCorrections implements android.os.Parcelable { - ctor public GnssAntennaInfo.PhaseCenterVariationCorrections(@NonNull double[][], @NonNull double[][]); + public static final class GnssAntennaInfo.SphericalCorrections implements android.os.Parcelable { + ctor public GnssAntennaInfo.SphericalCorrections(@NonNull double[][], @NonNull double[][]); method public int describeContents(); - method public double getDeltaPhi(); - method public double getDeltaTheta(); - method public int getNumColumns(); - method public int getNumRows(); - method public double getPhaseCenterVariationCorrectionMillimetersAt(int, int); - method public double getPhaseCenterVariationCorrectionUncertaintyMillimetersAt(int, int); - method @NonNull public double[][] getRawCorrectionUncertaintiesArray(); - method @NonNull public double[][] getRawCorrectionsArray(); + method @NonNull public double[][] getCorrectionUncertaintiesArray(); + method @NonNull public double[][] getCorrectionsArray(); + method @FloatRange(from=0.0f, to=180.0f) public double getDeltaPhi(); + method @FloatRange(from=0.0f, to=360.0f) public double getDeltaTheta(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterVariationCorrections> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SphericalCorrections> CREATOR; } - public static final class GnssAntennaInfo.SignalGainCorrections implements android.os.Parcelable { - ctor public GnssAntennaInfo.SignalGainCorrections(@NonNull double[][], @NonNull double[][]); - method public int describeContents(); - method public double getDeltaPhi(); - method public double getDeltaTheta(); - method public int getNumColumns(); - method public int getNumRows(); - method @NonNull public double[][] getRawCorrectionUncertaintiesArray(); - method @NonNull public double[][] getRawCorrectionsArray(); - method public double getSignalGainCorrectionDbiAt(int, int); - method public double getSignalGainCorrectionUncertaintyDbiAt(int, int); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SignalGainCorrections> CREATOR; + public final class GnssCapabilities { + method public boolean hasGnssAntennaInfo(); } public final class GnssClock implements android.os.Parcelable { @@ -23859,6 +23850,7 @@ package android.location { method @NonNull public java.util.List<java.lang.String> getAllProviders(); method @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>); + method @NonNull public android.location.GnssCapabilities getGnssCapabilities(); method @Nullable public String getGnssHardwareModelName(); method public int getGnssYearOfHardware(); method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus); @@ -23868,7 +23860,7 @@ package android.location { method @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean); method public boolean isLocationEnabled(); method public boolean isProviderEnabled(@NonNull String); - method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerAntennaInfoCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Callback); + method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback); @@ -23900,7 +23892,7 @@ package android.location { method public void setTestProviderEnabled(@NonNull String, boolean); method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location); method @Deprecated public void setTestProviderStatus(@NonNull String, int, @Nullable android.os.Bundle, long); - method public void unregisterAntennaInfoCallback(@NonNull android.location.GnssAntennaInfo.Callback); + method public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener); method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback); method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback); method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback); @@ -24796,7 +24788,7 @@ package android.media { } public abstract class DrmInitData { - method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID); + method @Deprecated public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID); method @NonNull public android.media.DrmInitData.SchemeInitData getSchemeInitDataAt(int); method public int getSchemeInitDataCount(); } @@ -26412,8 +26404,8 @@ package android.media { method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException, java.lang.InterruptedException; method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...); method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer); - method @Nullable public String getExtractorName(); - method @NonNull public static java.util.List<java.lang.String> getExtractorNames(@NonNull android.media.MediaFormat); + method @Nullable public String getParserName(); + method @NonNull public static java.util.List<java.lang.String> getParserNames(@NonNull android.media.MediaFormat); method public void release(); method public void seek(@NonNull android.media.MediaParser.SeekPoint); } @@ -31744,7 +31736,7 @@ package android.net.wifi.hotspot2 { method public android.net.wifi.hotspot2.pps.Credential getCredential(); method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp(); method public long getSubscriptionExpirationTimeMillis(); - method @NonNull public String getUniqueId() throws java.lang.IllegalStateException; + method @NonNull public String getUniqueId(); method public boolean isOsuProvisioned(); method public void setCredential(android.net.wifi.hotspot2.pps.Credential); method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp); @@ -43403,11 +43395,12 @@ package android.service.controls { public abstract class ControlsProviderService extends android.app.Service { ctor public ControlsProviderService(); - method public abstract void loadAvailableControls(@NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>); - method public void loadSuggestedControls(int, @NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>); + method @Deprecated public void loadAvailableControls(@NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>); method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void performControlAction(@NonNull String, @NonNull android.service.controls.actions.ControlAction, @NonNull java.util.function.Consumer<java.lang.Integer>); method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>); + method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForAllAvailable(); + method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForSuggested(); field public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService"; field @NonNull public static final String TAG = "ControlsProviderService"; } @@ -45654,7 +45647,7 @@ package android.telecom { method public final android.telecom.CallAudioState getCallAudioState(); method public final String getCallerDisplayName(); method public final int getCallerDisplayNamePresentation(); - method public int getCallerNumberVerificationStatus(); + method public final int getCallerNumberVerificationStatus(); method public final android.telecom.Conference getConference(); method public final java.util.List<android.telecom.Conferenceable> getConferenceables(); method public final int getConnectionCapabilities(); @@ -45707,7 +45700,7 @@ package android.telecom { method public final void setAudioModeIsVoip(boolean); method public final void setAudioRoute(int); method public final void setCallerDisplayName(String, int); - method public void setCallerNumberVerificationStatus(int); + method public final void setCallerNumberVerificationStatus(int); method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>); method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>); method public final void setConnectionCapabilities(int); @@ -46559,8 +46552,8 @@ package android.telephony { field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call"; field public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool"; field public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool"; - field public static final String KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL = "allow_holding_video_call"; field public static final String KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL = "allow_hold_call_during_emergency_bool"; + field public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL = "allow_hold_video_call_bool"; field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool"; field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool"; field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool"; @@ -46813,59 +46806,6 @@ package android.telephony { field public static final String KEY_WIFI_OFF_DEFERRING_TIME_INT = "ims.wifi_off_deferring_time_int"; } - public static final class CarrierConfigManager.Iwlan { - field public static final int AUTHENTICATION_METHOD_CERT = 1; // 0x1 - field public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0; // 0x0 - field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2 - field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe - field public static final int DH_GROUP_NONE = 0; // 0x0 - field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3 - field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc - field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13 - field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14 - field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12 - field public static final int EPDG_ADDRESS_PCO = 2; // 0x2 - field public static final int EPDG_ADDRESS_PLMN = 1; // 0x1 - field public static final int EPDG_ADDRESS_STATIC = 0; // 0x0 - field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5 - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2 - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe - field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0 - field public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT = "iwlan.child_sa_rekey_hard_timer_sec_int"; - field public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT = "iwlan.child_sa_rekey_soft_timer_sec_int"; - field public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.child_session_aes_cbc_key_size_int_array"; - field public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.child_encryption_aes_ctr_key_size_int_array"; - field public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY = "iwlan.diffie_hellman_groups_int_array"; - field public static final String KEY_DPD_TIMER_SEC_INT = "iwlan.dpd_timer_sec_int"; - field public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY = "iwlan.epdg_address_priority_int_array"; - field public static final String KEY_EPDG_AUTHENTICATION_METHOD_INT = "iwlan.epdg_authentication_method_int"; - field public static final String KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING = "iwlan.epdg_static_address_roaming_string"; - field public static final String KEY_EPDG_STATIC_ADDRESS_STRING = "iwlan.epdg_static_address_string"; - field public static final String KEY_IKE_FRAGMENTATION_ENABLED_BOOL = "iwlan.ike_fragmentation_enabled_bool"; - field public static final String KEY_IKE_REKEY_HARD_TIMER_SEC_INT = "iwlan.ike_rekey_hard_timer_in_sec"; - field public static final String KEY_IKE_REKEY_SOFT_TIMER_SEC_INT = "iwlan.ike_rekey_soft_timer_sec_int"; - field public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_cbc_key_size_int_array"; - field public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_aes_ctr_key_size_int_array"; - field public static final int KEY_LEN_AES_128 = 128; // 0x80 - field public static final int KEY_LEN_AES_192 = 192; // 0xc0 - field public static final int KEY_LEN_AES_256 = 256; // 0x100 - field public static final int KEY_LEN_UNUSED = 0; // 0x0 - field public static final String KEY_MAX_RETRIES_INT = "iwlan.max_retries_int"; - field public static final String KEY_MCC_MNCS_STRING_ARRAY = "iwlan.mcc_mncs_string_array"; - field public static final String KEY_NATT_ENABLED_BOOL = "iwlan.natt_enabled_bool"; - field public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT = "iwlan.natt_keep_alive_timer_sec_int"; - field public static final String KEY_PREFIX = "iwlan."; - field public static final String KEY_RETRANSMIT_TIMER_SEC_INT = "iwlan.retransmit_timer_sec_int"; - field public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_child_session_encryption_algorithms_int_array"; - field public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_ike_session_encryption_algorithms_int_array"; - field public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY = "iwlan.supported_integrity_algorithms_int_array"; - field public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = "iwlan.supported_prf_algorithms_int_array"; - field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4 - field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2 - } - public abstract class CellIdentity implements android.os.Parcelable { method public int describeContents(); method @Nullable public CharSequence getOperatorAlphaLong(); @@ -47127,6 +47067,350 @@ package android.telephony { field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ClosedSubscriberGroupInfo> CREATOR; } + public final class DataFailCause { + field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab + field public static final int ACCESS_BLOCK = 2087; // 0x827 + field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828 + field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c + field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850 + field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30 + field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e + field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f + field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41 + field public static final int APN_DISABLED = 2045; // 0x7fd + field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b + field public static final int APN_MISMATCH = 2054; // 0x806 + field public static final int APN_PARAMETERS_CHANGED = 2060; // 0x80c + field public static final int APN_PENDING_HANDOVER = 2041; // 0x7f9 + field public static final int APN_TYPE_CONFLICT = 112; // 0x70 + field public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 122; // 0x7a + field public static final int BEARER_HANDLING_NOT_SUPPORTED = 60; // 0x3c + field public static final int CALL_DISALLOWED_IN_ROAMING = 2068; // 0x814 + field public static final int CALL_PREEMPT_BY_EMERGENCY_APN = 127; // 0x7f + field public static final int CANNOT_ENCODE_OTA_MESSAGE = 2159; // 0x86f + field public static final int CDMA_ALERT_STOP = 2077; // 0x81d + field public static final int CDMA_INCOMING_CALL = 2076; // 0x81c + field public static final int CDMA_INTERCEPT = 2073; // 0x819 + field public static final int CDMA_LOCK = 2072; // 0x818 + field public static final int CDMA_RELEASE_DUE_TO_SO_REJECTION = 2075; // 0x81b + field public static final int CDMA_REORDER = 2074; // 0x81a + field public static final int CDMA_RETRY_ORDER = 2086; // 0x826 + field public static final int CHANNEL_ACQUISITION_FAILURE = 2078; // 0x81e + field public static final int CLOSE_IN_PROGRESS = 2030; // 0x7ee + field public static final int COLLISION_WITH_NETWORK_INITIATED_REQUEST = 56; // 0x38 + field public static final int COMPANION_IFACE_IN_USE = 118; // 0x76 + field public static final int CONCURRENT_SERVICES_INCOMPATIBLE = 2083; // 0x823 + field public static final int CONCURRENT_SERVICES_NOT_ALLOWED = 2091; // 0x82b + field public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 2080; // 0x820 + field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64 + field public static final int CONGESTION = 2106; // 0x83a + field public static final int CONNECTION_RELEASED = 2113; // 0x841 + field public static final int CS_DOMAIN_NOT_AVAILABLE = 2181; // 0x885 + field public static final int CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 2188; // 0x88c + field public static final int DATA_PLAN_EXPIRED = 2198; // 0x896 + field public static final int DATA_ROAMING_SETTINGS_DISABLED = 2064; // 0x810 + field public static final int DATA_SETTINGS_DISABLED = 2063; // 0x80f + field public static final int DBM_OR_SMS_IN_PROGRESS = 2211; // 0x8a3 + field public static final int DDS_SWITCHED = 2065; // 0x811 + field public static final int DDS_SWITCH_IN_PROGRESS = 2067; // 0x813 + field public static final int DRB_RELEASED_BY_RRC = 2112; // 0x840 + field public static final int DS_EXPLICIT_DEACTIVATION = 2125; // 0x84d + field public static final int DUAL_SWITCH = 2227; // 0x8b3 + field public static final int DUN_CALL_DISALLOWED = 2056; // 0x808 + field public static final int DUPLICATE_BEARER_ID = 2118; // 0x846 + field public static final int EHRPD_TO_HRPD_FALLBACK = 2049; // 0x801 + field public static final int EMBMS_NOT_ENABLED = 2193; // 0x891 + field public static final int EMBMS_REGULAR_DEACTIVATION = 2195; // 0x893 + field public static final int EMERGENCY_IFACE_ONLY = 116; // 0x74 + field public static final int EMERGENCY_MODE = 2221; // 0x8ad + field public static final int EMM_ACCESS_BARRED = 115; // 0x73 + field public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 121; // 0x79 + field public static final int EMM_ATTACH_FAILED = 2115; // 0x843 + field public static final int EMM_ATTACH_STARTED = 2116; // 0x844 + field public static final int EMM_DETACHED = 2114; // 0x842 + field public static final int EMM_T3417_EXPIRED = 2130; // 0x852 + field public static final int EMM_T3417_EXT_EXPIRED = 2131; // 0x853 + field public static final int EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 2178; // 0x882 + field public static final int EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 2179; // 0x883 + field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff + field public static final int ESM_BAD_OTA_MESSAGE = 2122; // 0x84a + field public static final int ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 2120; // 0x848 + field public static final int ESM_COLLISION_SCENARIOS = 2119; // 0x847 + field public static final int ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 2124; // 0x84c + field public static final int ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 2123; // 0x84b + field public static final int ESM_FAILURE = 2182; // 0x886 + field public static final int ESM_INFO_NOT_RECEIVED = 53; // 0x35 + field public static final int ESM_LOCAL_CAUSE_NONE = 2126; // 0x84e + field public static final int ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 2121; // 0x849 + field public static final int ESM_PROCEDURE_TIME_OUT = 2155; // 0x86b + field public static final int ESM_UNKNOWN_EPS_BEARER_CONTEXT = 2111; // 0x83f + field public static final int EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 2201; // 0x899 + field public static final int EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 2200; // 0x898 + field public static final int EVDO_HDR_CHANGED = 2202; // 0x89a + field public static final int EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 2206; // 0x89e + field public static final int EVDO_HDR_EXITED = 2203; // 0x89b + field public static final int EVDO_HDR_NO_SESSION = 2204; // 0x89c + field public static final int EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 2205; // 0x89d + field public static final int FADE = 2217; // 0x8a9 + field public static final int FAILED_TO_ACQUIRE_COLOCATED_HDR = 2207; // 0x89f + field public static final int FEATURE_NOT_SUPP = 40; // 0x28 + field public static final int FILTER_SEMANTIC_ERROR = 44; // 0x2c + field public static final int FILTER_SYTAX_ERROR = 45; // 0x2d + field public static final int FORBIDDEN_APN_NAME = 2066; // 0x812 + field public static final int GPRS_REGISTRATION_FAIL = -2; // 0xfffffffe + field public static final int GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 2097; // 0x831 + field public static final int GPRS_SERVICES_NOT_ALLOWED = 2098; // 0x832 + field public static final int GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 2103; // 0x837 + field public static final int HANDOFF_PREFERENCE_CHANGED = 2251; // 0x8cb + field public static final int HDR_ACCESS_FAILURE = 2213; // 0x8a5 + field public static final int HDR_FADE = 2212; // 0x8a4 + field public static final int HDR_NO_LOCK_GRANTED = 2210; // 0x8a2 + field public static final int IFACE_AND_POL_FAMILY_MISMATCH = 120; // 0x78 + field public static final int IFACE_MISMATCH = 117; // 0x75 + field public static final int ILLEGAL_ME = 2096; // 0x830 + field public static final int ILLEGAL_MS = 2095; // 0x82f + field public static final int IMEI_NOT_ACCEPTED = 2177; // 0x881 + field public static final int IMPLICITLY_DETACHED = 2100; // 0x834 + field public static final int IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 2176; // 0x880 + field public static final int INCOMING_CALL_REJECTED = 2092; // 0x82c + field public static final int INSUFFICIENT_RESOURCES = 26; // 0x1a + field public static final int INTERFACE_IN_USE = 2058; // 0x80a + field public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 114; // 0x72 + field public static final int INTERNAL_EPC_NONEPC_TRANSITION = 2057; // 0x809 + field public static final int INVALID_CONNECTION_ID = 2156; // 0x86c + field public static final int INVALID_DNS_ADDR = 123; // 0x7b + field public static final int INVALID_EMM_STATE = 2190; // 0x88e + field public static final int INVALID_MANDATORY_INFO = 96; // 0x60 + field public static final int INVALID_MODE = 2223; // 0x8af + field public static final int INVALID_PCSCF_ADDR = 113; // 0x71 + field public static final int INVALID_PCSCF_OR_DNS_ADDRESS = 124; // 0x7c + field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e + field public static final int INVALID_SIM_STATE = 2224; // 0x8b0 + field public static final int INVALID_TRANSACTION_ID = 81; // 0x51 + field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff + field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca + field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77 + field public static final int IP_VERSION_MISMATCH = 2055; // 0x807 + field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892 + field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829 + field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba + field public static final int LIMITED_TO_IPV6 = 2235; // 0x8bb + field public static final int LLC_SNDCP = 25; // 0x19 + field public static final int LOCAL_END = 2215; // 0x8a7 + field public static final int LOCATION_AREA_NOT_ALLOWED = 2102; // 0x836 + field public static final int LOST_CONNECTION = 65540; // 0x10004 + field public static final int LOWER_LAYER_REGISTRATION_FAILURE = 2197; // 0x895 + field public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 2044; // 0x7fc + field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845 + field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f + field public static final int MAC_FAILURE = 2183; // 0x887 + field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d + field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876 + field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f + field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804 + field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805 + field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe + field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f + field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61 + field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802 + field public static final int MIP_FA_ADMIN_PROHIBITED = 2001; // 0x7d1 + field public static final int MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 2012; // 0x7dc + field public static final int MIP_FA_ENCAPSULATION_UNAVAILABLE = 2008; // 0x7d8 + field public static final int MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 2004; // 0x7d4 + field public static final int MIP_FA_INSUFFICIENT_RESOURCES = 2002; // 0x7d2 + field public static final int MIP_FA_MALFORMED_REPLY = 2007; // 0x7d7 + field public static final int MIP_FA_MALFORMED_REQUEST = 2006; // 0x7d6 + field public static final int MIP_FA_MISSING_CHALLENGE = 2017; // 0x7e1 + field public static final int MIP_FA_MISSING_HOME_ADDRESS = 2015; // 0x7df + field public static final int MIP_FA_MISSING_HOME_AGENT = 2014; // 0x7de + field public static final int MIP_FA_MISSING_NAI = 2013; // 0x7dd + field public static final int MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2003; // 0x7d3 + field public static final int MIP_FA_REASON_UNSPECIFIED = 2000; // 0x7d0 + field public static final int MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 2005; // 0x7d5 + field public static final int MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 2011; // 0x7db + field public static final int MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 2010; // 0x7da + field public static final int MIP_FA_STALE_CHALLENGE = 2018; // 0x7e2 + field public static final int MIP_FA_UNKNOWN_CHALLENGE = 2016; // 0x7e0 + field public static final int MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 2009; // 0x7d9 + field public static final int MIP_HA_ADMIN_PROHIBITED = 2020; // 0x7e4 + field public static final int MIP_HA_ENCAPSULATION_UNAVAILABLE = 2029; // 0x7ed + field public static final int MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 2023; // 0x7e7 + field public static final int MIP_HA_INSUFFICIENT_RESOURCES = 2021; // 0x7e5 + field public static final int MIP_HA_MALFORMED_REQUEST = 2025; // 0x7e9 + field public static final int MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2022; // 0x7e6 + field public static final int MIP_HA_REASON_UNSPECIFIED = 2019; // 0x7e3 + field public static final int MIP_HA_REGISTRATION_ID_MISMATCH = 2024; // 0x7e8 + field public static final int MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 2028; // 0x7ec + field public static final int MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 2027; // 0x7eb + field public static final int MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 2026; // 0x7ea + field public static final int MISSING_UNKNOWN_APN = 27; // 0x1b + field public static final int MODEM_APP_PREEMPTED = 2032; // 0x7f0 + field public static final int MODEM_RESTART = 2037; // 0x7f5 + field public static final int MSC_TEMPORARILY_NOT_REACHABLE = 2180; // 0x884 + field public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; // 0x65 + field public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 98; // 0x62 + field public static final int MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 2099; // 0x833 + field public static final int MULTIPLE_PDP_CALL_NOT_ALLOWED = 2192; // 0x890 + field public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 55; // 0x37 + field public static final int NAS_LAYER_FAILURE = 2191; // 0x88f + field public static final int NAS_REQUEST_REJECTED_BY_NETWORK = 2167; // 0x877 + field public static final int NAS_SIGNALLING = 14; // 0xe + field public static final int NETWORK_FAILURE = 38; // 0x26 + field public static final int NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 2154; // 0x86a + field public static final int NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 2153; // 0x869 + field public static final int NETWORK_INITIATED_TERMINATION = 2031; // 0x7ef + field public static final int NONE = 0; // 0x0 + field public static final int NON_IP_NOT_SUPPORTED = 2069; // 0x815 + field public static final int NORMAL_RELEASE = 2218; // 0x8aa + field public static final int NO_CDMA_SERVICE = 2084; // 0x824 + field public static final int NO_COLLOCATED_HDR = 2225; // 0x8b1 + field public static final int NO_EPS_BEARER_CONTEXT_ACTIVATED = 2189; // 0x88d + field public static final int NO_GPRS_CONTEXT = 2094; // 0x82e + field public static final int NO_HYBRID_HDR_SERVICE = 2209; // 0x8a1 + field public static final int NO_PDP_CONTEXT_ACTIVATED = 2107; // 0x83b + field public static final int NO_RESPONSE_FROM_BASE_STATION = 2081; // 0x821 + field public static final int NO_SERVICE = 2216; // 0x8a8 + field public static final int NO_SERVICE_ON_GATEWAY = 2093; // 0x82d + field public static final int NSAPI_IN_USE = 35; // 0x23 + field public static final int NULL_APN_DISALLOWED = 2061; // 0x80d + field public static final int OEM_DCFAILCAUSE_1 = 4097; // 0x1001 + field public static final int OEM_DCFAILCAUSE_10 = 4106; // 0x100a + field public static final int OEM_DCFAILCAUSE_11 = 4107; // 0x100b + field public static final int OEM_DCFAILCAUSE_12 = 4108; // 0x100c + field public static final int OEM_DCFAILCAUSE_13 = 4109; // 0x100d + field public static final int OEM_DCFAILCAUSE_14 = 4110; // 0x100e + field public static final int OEM_DCFAILCAUSE_15 = 4111; // 0x100f + field public static final int OEM_DCFAILCAUSE_2 = 4098; // 0x1002 + field public static final int OEM_DCFAILCAUSE_3 = 4099; // 0x1003 + field public static final int OEM_DCFAILCAUSE_4 = 4100; // 0x1004 + field public static final int OEM_DCFAILCAUSE_5 = 4101; // 0x1005 + field public static final int OEM_DCFAILCAUSE_6 = 4102; // 0x1006 + field public static final int OEM_DCFAILCAUSE_7 = 4103; // 0x1007 + field public static final int OEM_DCFAILCAUSE_8 = 4104; // 0x1008 + field public static final int OEM_DCFAILCAUSE_9 = 4105; // 0x1009 + field public static final int ONLY_IPV4V6_ALLOWED = 57; // 0x39 + field public static final int ONLY_IPV4_ALLOWED = 50; // 0x32 + field public static final int ONLY_IPV6_ALLOWED = 51; // 0x33 + field public static final int ONLY_NON_IP_ALLOWED = 58; // 0x3a + field public static final int ONLY_SINGLE_BEARER_ALLOWED = 52; // 0x34 + field public static final int OPERATOR_BARRED = 8; // 0x8 + field public static final int OTASP_COMMIT_IN_PROGRESS = 2208; // 0x8a0 + field public static final int PDN_CONN_DOES_NOT_EXIST = 54; // 0x36 + field public static final int PDN_INACTIVITY_TIMER_EXPIRED = 2051; // 0x803 + field public static final int PDN_IPV4_CALL_DISALLOWED = 2033; // 0x7f1 + field public static final int PDN_IPV4_CALL_THROTTLED = 2034; // 0x7f2 + field public static final int PDN_IPV6_CALL_DISALLOWED = 2035; // 0x7f3 + field public static final int PDN_IPV6_CALL_THROTTLED = 2036; // 0x7f4 + field public static final int PDN_NON_IP_CALL_DISALLOWED = 2071; // 0x817 + field public static final int PDN_NON_IP_CALL_THROTTLED = 2070; // 0x816 + field public static final int PDP_ACTIVATE_MAX_RETRY_FAILED = 2109; // 0x83d + field public static final int PDP_DUPLICATE = 2104; // 0x838 + field public static final int PDP_ESTABLISH_TIMEOUT_EXPIRED = 2161; // 0x871 + field public static final int PDP_INACTIVE_TIMEOUT_EXPIRED = 2163; // 0x873 + field public static final int PDP_LOWERLAYER_ERROR = 2164; // 0x874 + field public static final int PDP_MODIFY_COLLISION = 2165; // 0x875 + field public static final int PDP_MODIFY_TIMEOUT_EXPIRED = 2162; // 0x872 + field public static final int PDP_PPP_NOT_SUPPORTED = 2038; // 0x7f6 + field public static final int PDP_WITHOUT_ACTIVE_TFT = 46; // 0x2e + field public static final int PHONE_IN_USE = 2222; // 0x8ae + field public static final int PHYSICAL_LINK_CLOSE_IN_PROGRESS = 2040; // 0x7f8 + field public static final int PLMN_NOT_ALLOWED = 2101; // 0x835 + field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5 + field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8 + field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9 + field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6 + field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7 + field public static final int PPP_TIMEOUT = 2228; // 0x8b4 + field public static final int PREF_RADIO_TECH_CHANGED = -4; // 0xfffffffc + field public static final int PROFILE_BEARER_INCOMPATIBLE = 2042; // 0x7fa + field public static final int PROTOCOL_ERRORS = 111; // 0x6f + field public static final int QOS_NOT_ACCEPTED = 37; // 0x25 + field public static final int RADIO_ACCESS_BEARER_FAILURE = 2110; // 0x83e + field public static final int RADIO_ACCESS_BEARER_SETUP_FAILURE = 2160; // 0x870 + field public static final int RADIO_NOT_AVAILABLE = 65537; // 0x10001 + field public static final int RADIO_POWER_OFF = -5; // 0xfffffffb + field public static final int REDIRECTION_OR_HANDOFF_IN_PROGRESS = 2220; // 0x8ac + field public static final int REGISTRATION_FAIL = -1; // 0xffffffff + field public static final int REGULAR_DEACTIVATION = 36; // 0x24 + field public static final int REJECTED_BY_BASE_STATION = 2082; // 0x822 + field public static final int RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 2173; // 0x87d + field public static final int RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 2174; // 0x87e + field public static final int RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 2171; // 0x87b + field public static final int RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 2175; // 0x87f + field public static final int RRC_CONNECTION_ABORT_REQUEST = 2151; // 0x867 + field public static final int RRC_CONNECTION_ACCESS_BARRED = 2139; // 0x85b + field public static final int RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 2137; // 0x859 + field public static final int RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 2138; // 0x85a + field public static final int RRC_CONNECTION_CELL_NOT_CAMPED = 2144; // 0x860 + field public static final int RRC_CONNECTION_CELL_RESELECTION = 2140; // 0x85c + field public static final int RRC_CONNECTION_CONFIG_FAILURE = 2141; // 0x85d + field public static final int RRC_CONNECTION_INVALID_REQUEST = 2168; // 0x878 + field public static final int RRC_CONNECTION_LINK_FAILURE = 2143; // 0x85f + field public static final int RRC_CONNECTION_NORMAL_RELEASE = 2147; // 0x863 + field public static final int RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 2150; // 0x866 + field public static final int RRC_CONNECTION_RADIO_LINK_FAILURE = 2148; // 0x864 + field public static final int RRC_CONNECTION_REESTABLISHMENT_FAILURE = 2149; // 0x865 + field public static final int RRC_CONNECTION_REJECT_BY_NETWORK = 2146; // 0x862 + field public static final int RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 2172; // 0x87c + field public static final int RRC_CONNECTION_RF_UNAVAILABLE = 2170; // 0x87a + field public static final int RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 2152; // 0x868 + field public static final int RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 2145; // 0x861 + field public static final int RRC_CONNECTION_TIMER_EXPIRED = 2142; // 0x85e + field public static final int RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 2169; // 0x879 + field public static final int RRC_UPLINK_CONNECTION_RELEASE = 2134; // 0x856 + field public static final int RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 2132; // 0x854 + field public static final int RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 2133; // 0x855 + field public static final int RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 2136; // 0x858 + field public static final int RRC_UPLINK_RADIO_LINK_FAILURE = 2135; // 0x857 + field public static final int RUIM_NOT_PRESENT = 2085; // 0x825 + field public static final int SECURITY_MODE_REJECTED = 2186; // 0x88a + field public static final int SERVICE_NOT_ALLOWED_ON_PLMN = 2129; // 0x851 + field public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 33; // 0x21 + field public static final int SERVICE_OPTION_NOT_SUPPORTED = 32; // 0x20 + field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22 + field public static final int SIGNAL_LOST = -3; // 0xfffffffd + field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb + field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888 + field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894 + field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa + field public static final int TFT_SEMANTIC_ERROR = 41; // 0x29 + field public static final int TFT_SYTAX_ERROR = 42; // 0x2a + field public static final int THERMAL_EMERGENCY = 2090; // 0x82a + field public static final int THERMAL_MITIGATION = 2062; // 0x80e + field public static final int TRAT_SWAP_FAILED = 2048; // 0x800 + field public static final int UE_INITIATED_DETACH_OR_DISCONNECT = 128; // 0x80 + field public static final int UE_IS_ENTERING_POWERSAVE_MODE = 2226; // 0x8b2 + field public static final int UE_RAT_CHANGE = 2105; // 0x839 + field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889 + field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897 + field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27 + field public static final int UNACCEPTABLE_NETWORK_PARAMETER = 65538; // 0x10002 + field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b + field public static final int UNKNOWN = 65536; // 0x10000 + field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63 + field public static final int UNKNOWN_PDP_ADDRESS_TYPE = 28; // 0x1c + field public static final int UNKNOWN_PDP_CONTEXT = 43; // 0x2b + field public static final int UNPREFERRED_RAT = 2039; // 0x7f7 + field public static final int UNSUPPORTED_1X_PREV = 2214; // 0x8a6 + field public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 66; // 0x42 + field public static final int UNSUPPORTED_QCI_VALUE = 59; // 0x3b + field public static final int USER_AUTHENTICATION = 29; // 0x1d + field public static final int VSNCP_ADMINISTRATIVELY_PROHIBITED = 2245; // 0x8c5 + field public static final int VSNCP_APN_UNAUTHORIZED = 2238; // 0x8be + field public static final int VSNCP_GEN_ERROR = 2237; // 0x8bd + field public static final int VSNCP_INSUFFICIENT_PARAMETERS = 2243; // 0x8c3 + field public static final int VSNCP_NO_PDN_GATEWAY_ADDRESS = 2240; // 0x8c0 + field public static final int VSNCP_PDN_EXISTS_FOR_THIS_APN = 2248; // 0x8c8 + field public static final int VSNCP_PDN_GATEWAY_REJECT = 2242; // 0x8c2 + field public static final int VSNCP_PDN_GATEWAY_UNREACHABLE = 2241; // 0x8c1 + field public static final int VSNCP_PDN_ID_IN_USE = 2246; // 0x8c6 + field public static final int VSNCP_PDN_LIMIT_EXCEEDED = 2239; // 0x8bf + field public static final int VSNCP_RECONNECT_NOT_ALLOWED = 2249; // 0x8c9 + field public static final int VSNCP_RESOURCE_UNAVAILABLE = 2244; // 0x8c4 + field public static final int VSNCP_SUBSCRIBER_LIMITATION = 2247; // 0x8c7 + field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc + } + public final class DisplayInfo implements android.os.Parcelable { method public int describeContents(); method public int getNetworkType(); @@ -47289,32 +47573,8 @@ package android.telephony { public final class PhoneCapability implements android.os.Parcelable { method public int describeContents(); - method @NonNull public java.util.List<java.lang.Integer> getBands(int); - method @NonNull public java.util.List<java.util.List<java.lang.Long>> getConcurrentFeaturesSupport(); - method @NonNull public java.util.List<java.lang.String> getLogicalModemUuids(); - method public int getMaxActiveDedicatedBearers(); - method public int getMaxActiveInternetData(); - method public int getMaxActivePsVoice(); - method public long getPsDataConnectionLingerTimeMillis(); - method @NonNull public java.util.List<android.telephony.SimSlotCapability> getSimSlotCapabilities(); - method public long getSupportedRats(); - method public int getUeCategory(boolean, int); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneCapability> CREATOR; - field public static final long MODEM_FEATURE_3GPP2_REG = 1L; // 0x1L - field public static final long MODEM_FEATURE_3GPP_REG = 2L; // 0x2L - field public static final long MODEM_FEATURE_CDMA2000_EHRPD_REG = 4L; // 0x4L - field public static final long MODEM_FEATURE_CSIM = 8192L; // 0x2000L - field public static final long MODEM_FEATURE_CS_VOICE_SESSION = 512L; // 0x200L - field public static final long MODEM_FEATURE_DEDICATED_BEARER = 2048L; // 0x800L - field public static final long MODEM_FEATURE_EUTRAN_REG = 32L; // 0x20L - field public static final long MODEM_FEATURE_EUTRA_NR_DUAL_CONNECTIVITY_REG = 128L; // 0x80L - field public static final long MODEM_FEATURE_GERAN_REG = 8L; // 0x8L - field public static final long MODEM_FEATURE_INTERACTIVE_DATA_SESSION = 1024L; // 0x400L - field public static final long MODEM_FEATURE_NETWORK_SCAN = 4096L; // 0x1000L - field public static final long MODEM_FEATURE_NGRAN_REG = 64L; // 0x40L - field public static final long MODEM_FEATURE_PS_VOICE_REG = 256L; // 0x100L - field public static final long MODEM_FEATURE_UTRAN_REG = 16L; // 0x10L } public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher { @@ -47504,18 +47764,6 @@ package android.telephony { field public static final int INVALID = 2147483647; // 0x7fffffff } - public final class SimSlotCapability implements android.os.Parcelable { - method public int describeContents(); - method public int getPhysicalSlotIndex(); - method public int getSlotType(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SimSlotCapability> CREATOR; - field public static final int SLOT_TYPE_EUICC = 3; // 0x3 - field public static final int SLOT_TYPE_IUICC = 2; // 0x2 - field public static final int SLOT_TYPE_SOFT_SIM = 4; // 0x4 - field public static final int SLOT_TYPE_UICC = 1; // 0x1 - } - public final class SmsManager { method public String createAppSpecificSmsToken(android.app.PendingIntent); method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent); @@ -47872,7 +48120,6 @@ package android.telephony { method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getNetworkSelectionMode(); method public String getNetworkSpecifier(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getNetworkType(); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.PhoneCapability getPhoneCapability(); method @Deprecated public int getPhoneCount(); method public int getPhoneType(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription(); @@ -56481,7 +56728,7 @@ package android.view.inline { method public int describeContents(); method @NonNull public android.util.Size getMaxSize(); method @NonNull public android.util.Size getMinSize(); - method @Nullable public String getStyle(); + method @Nullable public android.os.Bundle getStyle(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.view.inline.InlinePresentationSpec> CREATOR; } @@ -56489,7 +56736,7 @@ package android.view.inline { public static final class InlinePresentationSpec.Builder { ctor public InlinePresentationSpec.Builder(@NonNull android.util.Size, @NonNull android.util.Size); method @NonNull public android.view.inline.InlinePresentationSpec build(); - method @NonNull public android.view.inline.InlinePresentationSpec.Builder setStyle(@Nullable String); + method @NonNull public android.view.inline.InlinePresentationSpec.Builder setStyle(@Nullable android.os.Bundle); } } diff --git a/api/system-current.txt b/api/system-current.txt index 7b8f7176a0a6..9663c0c53a39 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -137,7 +137,6 @@ package android { field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS"; field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE"; field public static final String MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE = "android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE"; - field public static final String MONITOR_DEVICE_CONFIG_ACCESS = "android.permission.MONITOR_DEVICE_CONFIG_ACCESS"; field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE"; field public static final String NETWORK_AIRPLANE_MODE = "android.permission.NETWORK_AIRPLANE_MODE"; field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING"; @@ -376,6 +375,7 @@ package android.app { method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int); field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover"; field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility"; + field public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio"; field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications"; field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot"; @@ -1958,6 +1958,11 @@ package android.content.integrity { method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String); } + public static final class IntegrityFormula.SourceStamp { + method @NonNull public static android.content.integrity.IntegrityFormula notTrusted(); + method @NonNull public static android.content.integrity.IntegrityFormula stampCertificateHashEquals(@NonNull String); + } + public final class Rule implements android.os.Parcelable { ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int); method public int describeContents(); @@ -3775,8 +3780,14 @@ package android.hardware.usb { method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long); field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED"; field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE"; + field public static final long FUNCTION_ACCESSORY = 2L; // 0x2L + field public static final long FUNCTION_ADB = 1L; // 0x1L + field public static final long FUNCTION_AUDIO_SOURCE = 64L; // 0x40L + field public static final long FUNCTION_MIDI = 8L; // 0x8L + field public static final long FUNCTION_MTP = 4L; // 0x4L field public static final long FUNCTION_NCM = 1024L; // 0x400L field public static final long FUNCTION_NONE = 0L; // 0x0L + field public static final long FUNCTION_PTP = 16L; // 0x10L field public static final long FUNCTION_RNDIS = 32L; // 0x20L field public static final String USB_CONFIGURED = "configured"; field public static final String USB_CONNECTED = "connected"; @@ -3823,7 +3834,6 @@ package android.location { public final class GnssCapabilities { method public boolean hasGeofencing(); - method public boolean hasGnssAntennaInfo(); method public boolean hasLowPowerMode(); method public boolean hasMeasurementCorrections(); method public boolean hasMeasurementCorrectionsExcessPathLength(); @@ -4163,7 +4173,6 @@ package android.location { method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>); method @Nullable public String getExtraLocationControllerPackage(); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize(); - method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GnssCapabilities getGnssCapabilities(); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections); method public boolean isExtraLocationControllerPackageEnabled(); method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle); @@ -6738,337 +6747,6 @@ package android.net.apf { } -package android.net.eap { - - public final class EapSessionConfig { - } - - public static final class EapSessionConfig.Builder { - ctor public EapSessionConfig.Builder(); - method @NonNull public android.net.eap.EapSessionConfig build(); - method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaConfig(int, int); - method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaPrimeConfig(int, int, @NonNull String, boolean); - method @NonNull public android.net.eap.EapSessionConfig.Builder setEapIdentity(@NonNull byte[]); - method @NonNull public android.net.eap.EapSessionConfig.Builder setEapMsChapV2Config(@NonNull String, @NonNull String); - method @NonNull public android.net.eap.EapSessionConfig.Builder setEapSimConfig(int, int); - } - - public static class EapSessionConfig.EapAkaConfig extends android.net.eap.EapSessionConfig.EapUiccConfig { - } - - public static class EapSessionConfig.EapAkaPrimeConfig extends android.net.eap.EapSessionConfig.EapAkaConfig { - method public boolean allowsMismatchedNetworkNames(); - method @NonNull public String getNetworkName(); - } - - public abstract static class EapSessionConfig.EapMethodConfig { - method public int getMethodType(); - } - - public static class EapSessionConfig.EapMsChapV2Config extends android.net.eap.EapSessionConfig.EapMethodConfig { - method @NonNull public String getPassword(); - method @NonNull public String getUsername(); - } - - public static class EapSessionConfig.EapSimConfig extends android.net.eap.EapSessionConfig.EapUiccConfig { - } - - public abstract static class EapSessionConfig.EapUiccConfig extends android.net.eap.EapSessionConfig.EapMethodConfig { - method public int getAppType(); - method public int getSubId(); - } - -} - -package android.net.ipsec.ike { - - public final class ChildSaProposal extends android.net.ipsec.ike.SaProposal { - } - - public static final class ChildSaProposal.Builder { - ctor public ChildSaProposal.Builder(); - method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addDhGroup(int); - method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addEncryptionAlgorithm(int, int); - method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addIntegrityAlgorithm(int); - method @NonNull public android.net.ipsec.ike.ChildSaProposal build(); - } - - public interface ChildSessionCallback { - method public void onClosed(); - method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException); - method public void onIpSecTransformCreated(@NonNull android.net.IpSecTransform, int); - method public void onIpSecTransformDeleted(@NonNull android.net.IpSecTransform, int); - method public void onOpened(@NonNull android.net.ipsec.ike.ChildSessionConfiguration); - } - - public final class ChildSessionConfiguration { - method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getInboundTrafficSelectors(); - method @NonNull public java.util.List<android.net.LinkAddress> getInternalAddresses(); - method @NonNull public java.util.List<java.net.InetAddress> getInternalDhcpServers(); - method @NonNull public java.util.List<java.net.InetAddress> getInternalDnsServers(); - method @NonNull public java.util.List<android.net.IpPrefix> getInternalSubnets(); - method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors(); - } - - public abstract class ChildSessionParams { - method public long getHardLifetime(); - method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors(); - method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors(); - method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals(); - method public long getSoftLifetime(); - } - - public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification { - ctor public IkeFqdnIdentification(@NonNull String); - field @NonNull public final String fqdn; - } - - public abstract class IkeIdentification { - } - - public final class IkeIpv4AddrIdentification extends android.net.ipsec.ike.IkeIdentification { - ctor public IkeIpv4AddrIdentification(@NonNull java.net.Inet4Address); - field @NonNull public final java.net.Inet4Address ipv4Address; - } - - public class IkeIpv6AddrIdentification extends android.net.ipsec.ike.IkeIdentification { - ctor public IkeIpv6AddrIdentification(@NonNull java.net.Inet6Address); - field @NonNull public final java.net.Inet6Address ipv6Address; - } - - public final class IkeKeyIdIdentification extends android.net.ipsec.ike.IkeIdentification { - ctor public IkeKeyIdIdentification(@NonNull byte[]); - field @NonNull public final byte[] keyId; - } - - public final class IkeRfc822AddrIdentification extends android.net.ipsec.ike.IkeIdentification { - ctor public IkeRfc822AddrIdentification(@NonNull String); - field @NonNull public final String rfc822Name; - } - - public final class IkeSaProposal extends android.net.ipsec.ike.SaProposal { - method @NonNull public java.util.List<java.lang.Integer> getPseudorandomFunctions(); - } - - public static final class IkeSaProposal.Builder { - ctor public IkeSaProposal.Builder(); - method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addDhGroup(int); - method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addEncryptionAlgorithm(int, int); - method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addIntegrityAlgorithm(int); - method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addPseudorandomFunction(int); - method @NonNull public android.net.ipsec.ike.IkeSaProposal build(); - } - - public final class IkeSession implements java.lang.AutoCloseable { - ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionParams, @NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback); - method public void close(); - method public void closeChildSession(@NonNull android.net.ipsec.ike.ChildSessionCallback); - method public void kill(); - method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull android.net.ipsec.ike.ChildSessionCallback); - } - - public interface IkeSessionCallback { - method public void onClosed(); - method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException); - method public void onError(@NonNull android.net.ipsec.ike.exceptions.IkeProtocolException); - method public void onOpened(@NonNull android.net.ipsec.ike.IkeSessionConfiguration); - } - - public final class IkeSessionConfiguration { - method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers(); - method @NonNull public String getRemoteApplicationVersion(); - method @NonNull public java.util.List<byte[]> getRemoteVendorIDs(); - method public boolean isIkeExtensionEnabled(int); - field public static final int EXTENSION_TYPE_FRAGMENTATION = 1; // 0x1 - field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2 - } - - public final class IkeSessionParams { - method @NonNull public java.util.List<android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest> getConfigurationRequests(); - method public long getHardLifetime(); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig(); - method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification(); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig(); - method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification(); - method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals(); - method @NonNull public java.net.InetAddress getServerAddress(); - method public long getSoftLifetime(); - method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket(); - } - - public static final class IkeSessionParams.Builder { - ctor public IkeSessionParams.Builder(); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(@NonNull java.net.InetAddress); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(int); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal); - method @NonNull public android.net.ipsec.ike.IkeSessionParams build(); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@Nullable java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLifetime(long, long); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setServerAddress(@NonNull java.net.InetAddress); - method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket); - } - - public static interface IkeSessionParams.ConfigRequestIpv4PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest { - method @Nullable public java.net.Inet4Address getAddress(); - } - - public static interface IkeSessionParams.ConfigRequestIpv6PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest { - method @Nullable public java.net.Inet6Address getAddress(); - } - - public abstract static class IkeSessionParams.IkeAuthConfig { - } - - public static class IkeSessionParams.IkeAuthDigitalSignLocalConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig { - method @NonNull public java.security.cert.X509Certificate getClientEndCertificate(); - method @NonNull public java.util.List<java.security.cert.X509Certificate> getIntermediateCertificates(); - method @NonNull public java.security.PrivateKey getPrivateKey(); - } - - public static class IkeSessionParams.IkeAuthDigitalSignRemoteConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig { - method @Nullable public java.security.cert.X509Certificate getRemoteCaCert(); - } - - public static class IkeSessionParams.IkeAuthEapConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig { - method @NonNull public android.net.eap.EapSessionConfig getEapConfig(); - } - - public static class IkeSessionParams.IkeAuthPskConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig { - method @NonNull public byte[] getPsk(); - } - - public static interface IkeSessionParams.IkeConfigRequest { - } - - public final class IkeTrafficSelector { - ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress); - field public final int endPort; - field @NonNull public final java.net.InetAddress endingAddress; - field public final int startPort; - field @NonNull public final java.net.InetAddress startingAddress; - } - - public abstract class SaProposal { - method @NonNull public java.util.List<java.lang.Integer> getDhGroups(); - method @NonNull public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getEncryptionAlgorithms(); - method @NonNull public java.util.List<java.lang.Integer> getIntegrityAlgorithms(); - field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2 - field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe - field public static final int DH_GROUP_NONE = 0; // 0x0 - field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3 - field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc - field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13 - field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14 - field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12 - field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5 - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2 - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe - field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0 - field public static final int KEY_LEN_AES_128 = 128; // 0x80 - field public static final int KEY_LEN_AES_192 = 192; // 0xc0 - field public static final int KEY_LEN_AES_256 = 256; // 0x100 - field public static final int KEY_LEN_UNUSED = 0; // 0x0 - field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4 - field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2 - } - - public final class TransportModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams { - } - - public static final class TransportModeChildSessionParams.Builder { - ctor public TransportModeChildSessionParams.Builder(); - method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); - method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); - method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal); - method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams build(); - method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder setLifetime(long, long); - } - - public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams { - method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest> getConfigurationRequests(); - } - - public static final class TunnelModeChildSessionParams.Builder { - ctor public TunnelModeChildSessionParams.Builder(); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(int); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet4Address); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet6Address, int); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(int); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(int); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build(); - method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder setLifetime(long, long); - } - - public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest { - method @Nullable public java.net.Inet4Address getAddress(); - } - - public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest { - method @Nullable public java.net.Inet4Address getAddress(); - } - - public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest { - method @Nullable public java.net.Inet4Address getAddress(); - } - - public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest { - } - - public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest { - method @Nullable public java.net.Inet6Address getAddress(); - method public int getPrefixLength(); - } - - public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest { - method @Nullable public java.net.Inet6Address getAddress(); - } - - public static interface TunnelModeChildSessionParams.TunnelModeChildConfigRequest { - } - -} - -package android.net.ipsec.ike.exceptions { - - public abstract class IkeException extends java.lang.Exception { - } - - public final class IkeInternalException extends android.net.ipsec.ike.exceptions.IkeException { - } - - public abstract class IkeProtocolException extends android.net.ipsec.ike.exceptions.IkeException { - method @Nullable public byte[] getErrorData(); - method public int getErrorType(); - field public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24; // 0x18 - field public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44; // 0x2c - field public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37; // 0x25 - field public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36; // 0x24 - field public static final int ERROR_TYPE_INVALID_IKE_SPI = 4; // 0x4 - field public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17; // 0x11 - field public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5; // 0x5 - field public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9; // 0x9 - field public static final int ERROR_TYPE_INVALID_SELECTORS = 39; // 0x27 - field public static final int ERROR_TYPE_INVALID_SYNTAX = 7; // 0x7 - field public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35; // 0x23 - field public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14; // 0xe - field public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34; // 0x22 - field public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43; // 0x2b - field public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38; // 0x26 - field public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1; // 0x1 - } - -} - package android.net.metrics { public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event { @@ -9769,6 +9447,7 @@ package android.provider { field public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size"; field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length"; field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length"; + field public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled"; field public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled"; field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category."; field public static final String DOZE_ALWAYS_ON = "doze_always_on"; @@ -10212,6 +9891,7 @@ package android.service.autofill { public abstract class InlineSuggestionRenderService extends android.app.Service { ctor public InlineSuggestionRenderService(); method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); + method @Nullable public android.os.Bundle onGetInlineSuggestionsRendererInfo(); method @Nullable public android.view.View onRenderSuggestion(@NonNull android.service.autofill.InlinePresentation, int, int); field public static final String SERVICE_INTERFACE = "android.service.autofill.InlineSuggestionRenderService"; } @@ -11389,347 +11069,7 @@ package android.telephony { } public final class DataFailCause { - field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab - field public static final int ACCESS_BLOCK = 2087; // 0x827 - field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828 - field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c - field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850 - field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30 - field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e - field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f - field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41 - field public static final int APN_DISABLED = 2045; // 0x7fd - field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b - field public static final int APN_MISMATCH = 2054; // 0x806 - field public static final int APN_PARAMETERS_CHANGED = 2060; // 0x80c - field public static final int APN_PENDING_HANDOVER = 2041; // 0x7f9 - field public static final int APN_TYPE_CONFLICT = 112; // 0x70 - field public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 122; // 0x7a - field public static final int BEARER_HANDLING_NOT_SUPPORTED = 60; // 0x3c - field public static final int CALL_DISALLOWED_IN_ROAMING = 2068; // 0x814 - field public static final int CALL_PREEMPT_BY_EMERGENCY_APN = 127; // 0x7f - field public static final int CANNOT_ENCODE_OTA_MESSAGE = 2159; // 0x86f - field public static final int CDMA_ALERT_STOP = 2077; // 0x81d - field public static final int CDMA_INCOMING_CALL = 2076; // 0x81c - field public static final int CDMA_INTERCEPT = 2073; // 0x819 - field public static final int CDMA_LOCK = 2072; // 0x818 - field public static final int CDMA_RELEASE_DUE_TO_SO_REJECTION = 2075; // 0x81b - field public static final int CDMA_REORDER = 2074; // 0x81a - field public static final int CDMA_RETRY_ORDER = 2086; // 0x826 - field public static final int CHANNEL_ACQUISITION_FAILURE = 2078; // 0x81e - field public static final int CLOSE_IN_PROGRESS = 2030; // 0x7ee - field public static final int COLLISION_WITH_NETWORK_INITIATED_REQUEST = 56; // 0x38 - field public static final int COMPANION_IFACE_IN_USE = 118; // 0x76 - field public static final int CONCURRENT_SERVICES_INCOMPATIBLE = 2083; // 0x823 - field public static final int CONCURRENT_SERVICES_NOT_ALLOWED = 2091; // 0x82b - field public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 2080; // 0x820 - field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64 - field public static final int CONGESTION = 2106; // 0x83a - field public static final int CONNECTION_RELEASED = 2113; // 0x841 - field public static final int CS_DOMAIN_NOT_AVAILABLE = 2181; // 0x885 - field public static final int CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 2188; // 0x88c - field public static final int DATA_PLAN_EXPIRED = 2198; // 0x896 - field public static final int DATA_ROAMING_SETTINGS_DISABLED = 2064; // 0x810 - field public static final int DATA_SETTINGS_DISABLED = 2063; // 0x80f - field public static final int DBM_OR_SMS_IN_PROGRESS = 2211; // 0x8a3 - field public static final int DDS_SWITCHED = 2065; // 0x811 - field public static final int DDS_SWITCH_IN_PROGRESS = 2067; // 0x813 - field public static final int DRB_RELEASED_BY_RRC = 2112; // 0x840 - field public static final int DS_EXPLICIT_DEACTIVATION = 2125; // 0x84d - field public static final int DUAL_SWITCH = 2227; // 0x8b3 - field public static final int DUN_CALL_DISALLOWED = 2056; // 0x808 - field public static final int DUPLICATE_BEARER_ID = 2118; // 0x846 - field public static final int EHRPD_TO_HRPD_FALLBACK = 2049; // 0x801 - field public static final int EMBMS_NOT_ENABLED = 2193; // 0x891 - field public static final int EMBMS_REGULAR_DEACTIVATION = 2195; // 0x893 - field public static final int EMERGENCY_IFACE_ONLY = 116; // 0x74 - field public static final int EMERGENCY_MODE = 2221; // 0x8ad - field public static final int EMM_ACCESS_BARRED = 115; // 0x73 - field public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 121; // 0x79 - field public static final int EMM_ATTACH_FAILED = 2115; // 0x843 - field public static final int EMM_ATTACH_STARTED = 2116; // 0x844 - field public static final int EMM_DETACHED = 2114; // 0x842 - field public static final int EMM_T3417_EXPIRED = 2130; // 0x852 - field public static final int EMM_T3417_EXT_EXPIRED = 2131; // 0x853 - field public static final int EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 2178; // 0x882 - field public static final int EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 2179; // 0x883 - field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff - field public static final int ESM_BAD_OTA_MESSAGE = 2122; // 0x84a - field public static final int ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 2120; // 0x848 - field public static final int ESM_COLLISION_SCENARIOS = 2119; // 0x847 - field public static final int ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 2124; // 0x84c - field public static final int ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 2123; // 0x84b - field public static final int ESM_FAILURE = 2182; // 0x886 - field public static final int ESM_INFO_NOT_RECEIVED = 53; // 0x35 - field public static final int ESM_LOCAL_CAUSE_NONE = 2126; // 0x84e - field public static final int ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 2121; // 0x849 - field public static final int ESM_PROCEDURE_TIME_OUT = 2155; // 0x86b - field public static final int ESM_UNKNOWN_EPS_BEARER_CONTEXT = 2111; // 0x83f - field public static final int EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 2201; // 0x899 - field public static final int EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 2200; // 0x898 - field public static final int EVDO_HDR_CHANGED = 2202; // 0x89a - field public static final int EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 2206; // 0x89e - field public static final int EVDO_HDR_EXITED = 2203; // 0x89b - field public static final int EVDO_HDR_NO_SESSION = 2204; // 0x89c - field public static final int EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 2205; // 0x89d - field public static final int FADE = 2217; // 0x8a9 - field public static final int FAILED_TO_ACQUIRE_COLOCATED_HDR = 2207; // 0x89f - field public static final int FEATURE_NOT_SUPP = 40; // 0x28 - field public static final int FILTER_SEMANTIC_ERROR = 44; // 0x2c - field public static final int FILTER_SYTAX_ERROR = 45; // 0x2d - field public static final int FORBIDDEN_APN_NAME = 2066; // 0x812 - field public static final int GPRS_REGISTRATION_FAIL = -2; // 0xfffffffe - field public static final int GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 2097; // 0x831 - field public static final int GPRS_SERVICES_NOT_ALLOWED = 2098; // 0x832 - field public static final int GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 2103; // 0x837 - field public static final int HANDOFF_PREFERENCE_CHANGED = 2251; // 0x8cb - field public static final int HDR_ACCESS_FAILURE = 2213; // 0x8a5 - field public static final int HDR_FADE = 2212; // 0x8a4 - field public static final int HDR_NO_LOCK_GRANTED = 2210; // 0x8a2 - field public static final int IFACE_AND_POL_FAMILY_MISMATCH = 120; // 0x78 - field public static final int IFACE_MISMATCH = 117; // 0x75 - field public static final int ILLEGAL_ME = 2096; // 0x830 - field public static final int ILLEGAL_MS = 2095; // 0x82f - field public static final int IMEI_NOT_ACCEPTED = 2177; // 0x881 - field public static final int IMPLICITLY_DETACHED = 2100; // 0x834 - field public static final int IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 2176; // 0x880 - field public static final int INCOMING_CALL_REJECTED = 2092; // 0x82c - field public static final int INSUFFICIENT_RESOURCES = 26; // 0x1a - field public static final int INTERFACE_IN_USE = 2058; // 0x80a - field public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 114; // 0x72 - field public static final int INTERNAL_EPC_NONEPC_TRANSITION = 2057; // 0x809 - field public static final int INVALID_CONNECTION_ID = 2156; // 0x86c - field public static final int INVALID_DNS_ADDR = 123; // 0x7b - field public static final int INVALID_EMM_STATE = 2190; // 0x88e - field public static final int INVALID_MANDATORY_INFO = 96; // 0x60 - field public static final int INVALID_MODE = 2223; // 0x8af - field public static final int INVALID_PCSCF_ADDR = 113; // 0x71 - field public static final int INVALID_PCSCF_OR_DNS_ADDRESS = 124; // 0x7c - field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e - field public static final int INVALID_SIM_STATE = 2224; // 0x8b0 - field public static final int INVALID_TRANSACTION_ID = 81; // 0x51 - field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff - field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca - field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77 - field public static final int IP_VERSION_MISMATCH = 2055; // 0x807 - field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892 - field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829 - field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba - field public static final int LIMITED_TO_IPV6 = 2235; // 0x8bb - field public static final int LLC_SNDCP = 25; // 0x19 - field public static final int LOCAL_END = 2215; // 0x8a7 - field public static final int LOCATION_AREA_NOT_ALLOWED = 2102; // 0x836 - field public static final int LOST_CONNECTION = 65540; // 0x10004 - field public static final int LOWER_LAYER_REGISTRATION_FAILURE = 2197; // 0x895 - field public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 2044; // 0x7fc - field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845 - field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f - field public static final int MAC_FAILURE = 2183; // 0x887 - field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d - field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876 - field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f - field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804 - field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805 - field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe - field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f - field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61 - field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802 - field public static final int MIP_FA_ADMIN_PROHIBITED = 2001; // 0x7d1 - field public static final int MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 2012; // 0x7dc - field public static final int MIP_FA_ENCAPSULATION_UNAVAILABLE = 2008; // 0x7d8 - field public static final int MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 2004; // 0x7d4 - field public static final int MIP_FA_INSUFFICIENT_RESOURCES = 2002; // 0x7d2 - field public static final int MIP_FA_MALFORMED_REPLY = 2007; // 0x7d7 - field public static final int MIP_FA_MALFORMED_REQUEST = 2006; // 0x7d6 - field public static final int MIP_FA_MISSING_CHALLENGE = 2017; // 0x7e1 - field public static final int MIP_FA_MISSING_HOME_ADDRESS = 2015; // 0x7df - field public static final int MIP_FA_MISSING_HOME_AGENT = 2014; // 0x7de - field public static final int MIP_FA_MISSING_NAI = 2013; // 0x7dd - field public static final int MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2003; // 0x7d3 - field public static final int MIP_FA_REASON_UNSPECIFIED = 2000; // 0x7d0 - field public static final int MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 2005; // 0x7d5 - field public static final int MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 2011; // 0x7db - field public static final int MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 2010; // 0x7da - field public static final int MIP_FA_STALE_CHALLENGE = 2018; // 0x7e2 - field public static final int MIP_FA_UNKNOWN_CHALLENGE = 2016; // 0x7e0 - field public static final int MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 2009; // 0x7d9 - field public static final int MIP_HA_ADMIN_PROHIBITED = 2020; // 0x7e4 - field public static final int MIP_HA_ENCAPSULATION_UNAVAILABLE = 2029; // 0x7ed - field public static final int MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 2023; // 0x7e7 - field public static final int MIP_HA_INSUFFICIENT_RESOURCES = 2021; // 0x7e5 - field public static final int MIP_HA_MALFORMED_REQUEST = 2025; // 0x7e9 - field public static final int MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2022; // 0x7e6 - field public static final int MIP_HA_REASON_UNSPECIFIED = 2019; // 0x7e3 - field public static final int MIP_HA_REGISTRATION_ID_MISMATCH = 2024; // 0x7e8 - field public static final int MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 2028; // 0x7ec - field public static final int MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 2027; // 0x7eb - field public static final int MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 2026; // 0x7ea - field public static final int MISSING_UNKNOWN_APN = 27; // 0x1b - field public static final int MODEM_APP_PREEMPTED = 2032; // 0x7f0 - field public static final int MODEM_RESTART = 2037; // 0x7f5 - field public static final int MSC_TEMPORARILY_NOT_REACHABLE = 2180; // 0x884 - field public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; // 0x65 - field public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 98; // 0x62 - field public static final int MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 2099; // 0x833 - field public static final int MULTIPLE_PDP_CALL_NOT_ALLOWED = 2192; // 0x890 - field public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 55; // 0x37 - field public static final int NAS_LAYER_FAILURE = 2191; // 0x88f - field public static final int NAS_REQUEST_REJECTED_BY_NETWORK = 2167; // 0x877 - field public static final int NAS_SIGNALLING = 14; // 0xe - field public static final int NETWORK_FAILURE = 38; // 0x26 - field public static final int NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 2154; // 0x86a - field public static final int NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 2153; // 0x869 - field public static final int NETWORK_INITIATED_TERMINATION = 2031; // 0x7ef - field public static final int NONE = 0; // 0x0 - field public static final int NON_IP_NOT_SUPPORTED = 2069; // 0x815 - field public static final int NORMAL_RELEASE = 2218; // 0x8aa - field public static final int NO_CDMA_SERVICE = 2084; // 0x824 - field public static final int NO_COLLOCATED_HDR = 2225; // 0x8b1 - field public static final int NO_EPS_BEARER_CONTEXT_ACTIVATED = 2189; // 0x88d - field public static final int NO_GPRS_CONTEXT = 2094; // 0x82e - field public static final int NO_HYBRID_HDR_SERVICE = 2209; // 0x8a1 - field public static final int NO_PDP_CONTEXT_ACTIVATED = 2107; // 0x83b - field public static final int NO_RESPONSE_FROM_BASE_STATION = 2081; // 0x821 - field public static final int NO_SERVICE = 2216; // 0x8a8 - field public static final int NO_SERVICE_ON_GATEWAY = 2093; // 0x82d - field public static final int NSAPI_IN_USE = 35; // 0x23 - field public static final int NULL_APN_DISALLOWED = 2061; // 0x80d - field public static final int OEM_DCFAILCAUSE_1 = 4097; // 0x1001 - field public static final int OEM_DCFAILCAUSE_10 = 4106; // 0x100a - field public static final int OEM_DCFAILCAUSE_11 = 4107; // 0x100b - field public static final int OEM_DCFAILCAUSE_12 = 4108; // 0x100c - field public static final int OEM_DCFAILCAUSE_13 = 4109; // 0x100d - field public static final int OEM_DCFAILCAUSE_14 = 4110; // 0x100e - field public static final int OEM_DCFAILCAUSE_15 = 4111; // 0x100f - field public static final int OEM_DCFAILCAUSE_2 = 4098; // 0x1002 - field public static final int OEM_DCFAILCAUSE_3 = 4099; // 0x1003 - field public static final int OEM_DCFAILCAUSE_4 = 4100; // 0x1004 - field public static final int OEM_DCFAILCAUSE_5 = 4101; // 0x1005 - field public static final int OEM_DCFAILCAUSE_6 = 4102; // 0x1006 - field public static final int OEM_DCFAILCAUSE_7 = 4103; // 0x1007 - field public static final int OEM_DCFAILCAUSE_8 = 4104; // 0x1008 - field public static final int OEM_DCFAILCAUSE_9 = 4105; // 0x1009 - field public static final int ONLY_IPV4V6_ALLOWED = 57; // 0x39 - field public static final int ONLY_IPV4_ALLOWED = 50; // 0x32 - field public static final int ONLY_IPV6_ALLOWED = 51; // 0x33 - field public static final int ONLY_NON_IP_ALLOWED = 58; // 0x3a - field public static final int ONLY_SINGLE_BEARER_ALLOWED = 52; // 0x34 - field public static final int OPERATOR_BARRED = 8; // 0x8 - field public static final int OTASP_COMMIT_IN_PROGRESS = 2208; // 0x8a0 - field public static final int PDN_CONN_DOES_NOT_EXIST = 54; // 0x36 - field public static final int PDN_INACTIVITY_TIMER_EXPIRED = 2051; // 0x803 - field public static final int PDN_IPV4_CALL_DISALLOWED = 2033; // 0x7f1 - field public static final int PDN_IPV4_CALL_THROTTLED = 2034; // 0x7f2 - field public static final int PDN_IPV6_CALL_DISALLOWED = 2035; // 0x7f3 - field public static final int PDN_IPV6_CALL_THROTTLED = 2036; // 0x7f4 - field public static final int PDN_NON_IP_CALL_DISALLOWED = 2071; // 0x817 - field public static final int PDN_NON_IP_CALL_THROTTLED = 2070; // 0x816 - field public static final int PDP_ACTIVATE_MAX_RETRY_FAILED = 2109; // 0x83d - field public static final int PDP_DUPLICATE = 2104; // 0x838 - field public static final int PDP_ESTABLISH_TIMEOUT_EXPIRED = 2161; // 0x871 - field public static final int PDP_INACTIVE_TIMEOUT_EXPIRED = 2163; // 0x873 - field public static final int PDP_LOWERLAYER_ERROR = 2164; // 0x874 - field public static final int PDP_MODIFY_COLLISION = 2165; // 0x875 - field public static final int PDP_MODIFY_TIMEOUT_EXPIRED = 2162; // 0x872 - field public static final int PDP_PPP_NOT_SUPPORTED = 2038; // 0x7f6 - field public static final int PDP_WITHOUT_ACTIVE_TFT = 46; // 0x2e - field public static final int PHONE_IN_USE = 2222; // 0x8ae - field public static final int PHYSICAL_LINK_CLOSE_IN_PROGRESS = 2040; // 0x7f8 - field public static final int PLMN_NOT_ALLOWED = 2101; // 0x835 - field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5 - field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8 - field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9 - field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6 - field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7 - field public static final int PPP_TIMEOUT = 2228; // 0x8b4 - field public static final int PREF_RADIO_TECH_CHANGED = -4; // 0xfffffffc - field public static final int PROFILE_BEARER_INCOMPATIBLE = 2042; // 0x7fa - field public static final int PROTOCOL_ERRORS = 111; // 0x6f - field public static final int QOS_NOT_ACCEPTED = 37; // 0x25 - field public static final int RADIO_ACCESS_BEARER_FAILURE = 2110; // 0x83e - field public static final int RADIO_ACCESS_BEARER_SETUP_FAILURE = 2160; // 0x870 - field public static final int RADIO_NOT_AVAILABLE = 65537; // 0x10001 - field public static final int RADIO_POWER_OFF = -5; // 0xfffffffb - field public static final int REDIRECTION_OR_HANDOFF_IN_PROGRESS = 2220; // 0x8ac - field public static final int REGISTRATION_FAIL = -1; // 0xffffffff - field public static final int REGULAR_DEACTIVATION = 36; // 0x24 - field public static final int REJECTED_BY_BASE_STATION = 2082; // 0x822 - field public static final int RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 2173; // 0x87d - field public static final int RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 2174; // 0x87e - field public static final int RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 2171; // 0x87b - field public static final int RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 2175; // 0x87f - field public static final int RRC_CONNECTION_ABORT_REQUEST = 2151; // 0x867 - field public static final int RRC_CONNECTION_ACCESS_BARRED = 2139; // 0x85b - field public static final int RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 2137; // 0x859 - field public static final int RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 2138; // 0x85a - field public static final int RRC_CONNECTION_CELL_NOT_CAMPED = 2144; // 0x860 - field public static final int RRC_CONNECTION_CELL_RESELECTION = 2140; // 0x85c - field public static final int RRC_CONNECTION_CONFIG_FAILURE = 2141; // 0x85d - field public static final int RRC_CONNECTION_INVALID_REQUEST = 2168; // 0x878 - field public static final int RRC_CONNECTION_LINK_FAILURE = 2143; // 0x85f - field public static final int RRC_CONNECTION_NORMAL_RELEASE = 2147; // 0x863 - field public static final int RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 2150; // 0x866 - field public static final int RRC_CONNECTION_RADIO_LINK_FAILURE = 2148; // 0x864 - field public static final int RRC_CONNECTION_REESTABLISHMENT_FAILURE = 2149; // 0x865 - field public static final int RRC_CONNECTION_REJECT_BY_NETWORK = 2146; // 0x862 - field public static final int RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 2172; // 0x87c - field public static final int RRC_CONNECTION_RF_UNAVAILABLE = 2170; // 0x87a - field public static final int RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 2152; // 0x868 - field public static final int RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 2145; // 0x861 - field public static final int RRC_CONNECTION_TIMER_EXPIRED = 2142; // 0x85e - field public static final int RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 2169; // 0x879 - field public static final int RRC_UPLINK_CONNECTION_RELEASE = 2134; // 0x856 - field public static final int RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 2132; // 0x854 - field public static final int RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 2133; // 0x855 - field public static final int RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 2136; // 0x858 - field public static final int RRC_UPLINK_RADIO_LINK_FAILURE = 2135; // 0x857 - field public static final int RUIM_NOT_PRESENT = 2085; // 0x825 - field public static final int SECURITY_MODE_REJECTED = 2186; // 0x88a - field public static final int SERVICE_NOT_ALLOWED_ON_PLMN = 2129; // 0x851 - field public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 33; // 0x21 - field public static final int SERVICE_OPTION_NOT_SUPPORTED = 32; // 0x20 - field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22 - field public static final int SIGNAL_LOST = -3; // 0xfffffffd - field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb - field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888 - field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894 - field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa - field public static final int TFT_SEMANTIC_ERROR = 41; // 0x29 - field public static final int TFT_SYTAX_ERROR = 42; // 0x2a - field public static final int THERMAL_EMERGENCY = 2090; // 0x82a - field public static final int THERMAL_MITIGATION = 2062; // 0x80e - field public static final int TRAT_SWAP_FAILED = 2048; // 0x800 - field public static final int UE_INITIATED_DETACH_OR_DISCONNECT = 128; // 0x80 - field public static final int UE_IS_ENTERING_POWERSAVE_MODE = 2226; // 0x8b2 - field public static final int UE_RAT_CHANGE = 2105; // 0x839 - field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889 - field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897 - field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27 - field public static final int UNACCEPTABLE_NETWORK_PARAMETER = 65538; // 0x10002 - field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b - field public static final int UNKNOWN = 65536; // 0x10000 - field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63 - field public static final int UNKNOWN_PDP_ADDRESS_TYPE = 28; // 0x1c - field public static final int UNKNOWN_PDP_CONTEXT = 43; // 0x2b - field public static final int UNPREFERRED_RAT = 2039; // 0x7f7 - field public static final int UNSUPPORTED_1X_PREV = 2214; // 0x8a6 - field public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 66; // 0x42 - field public static final int UNSUPPORTED_QCI_VALUE = 59; // 0x3b - field public static final int USER_AUTHENTICATION = 29; // 0x1d - field public static final int VSNCP_ADMINISTRATIVELY_PROHIBITED = 2245; // 0x8c5 - field public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be - field public static final int VSNCP_GEN_ERROR = 2237; // 0x8bd - field public static final int VSNCP_INSUFFICIENT_PARAMETERS = 2243; // 0x8c3 - field public static final int VSNCP_NO_PDN_GATEWAY_ADDRESS = 2240; // 0x8c0 - field public static final int VSNCP_PDN_EXISTS_FOR_THIS_APN = 2248; // 0x8c8 - field public static final int VSNCP_PDN_GATEWAY_REJECT = 2242; // 0x8c2 - field public static final int VSNCP_PDN_GATEWAY_UNREACHABLE = 2241; // 0x8c1 - field public static final int VSNCP_PDN_ID_IN_USE = 2246; // 0x8c6 - field public static final int VSNCP_PDN_LIMIT_EXCEEDED = 2239; // 0x8bf - field public static final int VSNCP_RECONNECT_NOT_ALLOWED = 2249; // 0x8c9 - field public static final int VSNCP_RESOURCE_UNAVAILABLE = 2244; // 0x8c4 - field public static final int VSNCP_SUBSCRIBER_LIMITATION = 2247; // 0x8c7 - field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc + field @Deprecated public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be } public final class DataSpecificRegistrationInfo implements android.os.Parcelable { diff --git a/api/test-current.txt b/api/test-current.txt index 57606333bb21..9e37a3c5be96 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -846,6 +846,11 @@ package android.content.integrity { method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String); } + public static final class IntegrityFormula.SourceStamp { + method @NonNull public static android.content.integrity.IntegrityFormula notTrusted(); + method @NonNull public static android.content.integrity.IntegrityFormula stampCertificateHashEquals(@NonNull String); + } + public final class Rule implements android.os.Parcelable { ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int); method public int describeContents(); @@ -1473,6 +1478,10 @@ package android.media { method @NonNull public String getOriginalId(); } + public class MediaRouter2.RoutingController { + method @NonNull public String getOriginalId(); + } + public final class PlaybackParams implements android.os.Parcelable { method public int getAudioStretchMode(); method public android.media.PlaybackParams setAudioStretchMode(int); @@ -3150,6 +3159,7 @@ package android.service.autofill { public abstract class InlineSuggestionRenderService extends android.app.Service { ctor public InlineSuggestionRenderService(); method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); + method @Nullable public android.os.Bundle onGetInlineSuggestionsRendererInfo(); method @Nullable public android.view.View onRenderSuggestion(@NonNull android.service.autofill.InlinePresentation, int, int); field public static final String SERVICE_INTERFACE = "android.service.autofill.InlineSuggestionRenderService"; } diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp index f56dd6e4968e..95de6c506795 100644 --- a/cmds/hid/jni/com_android_commands_hid_Device.cpp +++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp @@ -129,7 +129,7 @@ JNIEnv* DeviceCallback::getJNIEnv() { } std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, int32_t pid, - const std::vector<uint8_t>& descriptor, + uint16_t bus, const std::vector<uint8_t>& descriptor, std::unique_ptr<DeviceCallback> callback) { size_t size = descriptor.size(); if (size > HID_MAX_DESCRIPTOR_SIZE) { @@ -148,7 +148,7 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name)); memcpy(&ev.u.create2.rd_data, descriptor.data(), size * sizeof(ev.u.create2.rd_data[0])); ev.u.create2.rd_size = size; - ev.u.create2.bus = BUS_BLUETOOTH; + ev.u.create2.bus = bus; ev.u.create2.vendor = vid; ev.u.create2.product = pid; ev.u.create2.version = 0; @@ -293,8 +293,8 @@ std::vector<uint8_t> getData(JNIEnv* env, jbyteArray javaArray) { return data; } -static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid, - jbyteArray rawDescriptor, jobject callback) { +static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, + jint pid, jint bus, jbyteArray rawDescriptor, jobject callback) { ScopedUtfChars name(env, rawName); if (name.c_str() == nullptr) { return 0; @@ -305,7 +305,7 @@ static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint i std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback)); std::unique_ptr<uhid::Device> d = - uhid::Device::open(id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc, + uhid::Device::open(id, reinterpret_cast<const char*>(name.c_str()), vid, pid, bus, desc, std::move(cb)); return reinterpret_cast<jlong>(d.release()); } @@ -339,14 +339,14 @@ static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) { } static JNINativeMethod sMethods[] = { - { "nativeOpenDevice", - "(Ljava/lang/String;III[B" - "Lcom/android/commands/hid/Device$DeviceCallback;)J", - reinterpret_cast<void*>(openDevice) }, - { "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) }, - { "nativeSendGetFeatureReportReply", "(JI[B)V", - reinterpret_cast<void*>(sendGetFeatureReportReply) }, - { "nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice) }, + {"nativeOpenDevice", + "(Ljava/lang/String;IIII[B" + "Lcom/android/commands/hid/Device$DeviceCallback;)J", + reinterpret_cast<void*>(openDevice)}, + {"nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport)}, + {"nativeSendGetFeatureReportReply", "(JI[B)V", + reinterpret_cast<void*>(sendGetFeatureReportReply)}, + {"nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice)}, }; int register_com_android_commands_hid_Device(JNIEnv* env) { diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h index 93ea881cfe28..7202b45adcde 100644 --- a/cmds/hid/jni/com_android_commands_hid_Device.h +++ b/cmds/hid/jni/com_android_commands_hid_Device.h @@ -43,7 +43,7 @@ private: class Device { public: static std::unique_ptr<Device> open(int32_t id, const char* name, int32_t vid, int32_t pid, - const std::vector<uint8_t>& descriptor, + uint16_t bus, const std::vector<uint8_t>& descriptor, std::unique_ptr<DeviceCallback> callback); ~Device(); diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java index 874604ceb5e4..dade41511ae6 100644 --- a/cmds/hid/src/com/android/commands/hid/Device.java +++ b/cmds/hid/src/com/android/commands/hid/Device.java @@ -52,13 +52,13 @@ public class Device { System.loadLibrary("hidcommand_jni"); } - private static native long nativeOpenDevice(String name, int id, int vid, int pid, + private static native long nativeOpenDevice(String name, int id, int vid, int pid, int bus, byte[] descriptor, DeviceCallback callback); private static native void nativeSendReport(long ptr, byte[] data); private static native void nativeSendGetFeatureReportReply(long ptr, int id, byte[] data); private static native void nativeCloseDevice(long ptr); - public Device(int id, String name, int vid, int pid, byte[] descriptor, + public Device(int id, String name, int vid, int pid, int bus, byte[] descriptor, byte[] report, SparseArray<byte[]> featureReports, Map<ByteBuffer, byte[]> outputs) { mId = id; mThread = new HandlerThread("HidDeviceHandler"); @@ -70,6 +70,7 @@ public class Device { args.argi1 = id; args.argi2 = vid; args.argi3 = pid; + args.argi4 = bus; if (name != null) { args.arg1 = name; } else { @@ -115,7 +116,7 @@ public class Device { case MSG_OPEN_DEVICE: SomeArgs args = (SomeArgs) msg.obj; mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3, - (byte[]) args.arg2, new DeviceCallback()); + args.argi4, (byte[]) args.arg2, new DeviceCallback()); pauseEvents(); break; case MSG_SEND_REPORT: diff --git a/cmds/hid/src/com/android/commands/hid/Event.java b/cmds/hid/src/com/android/commands/hid/Event.java index 62587a70f10d..d4bf1d820a70 100644 --- a/cmds/hid/src/com/android/commands/hid/Event.java +++ b/cmds/hid/src/com/android/commands/hid/Event.java @@ -36,12 +36,28 @@ public class Event { public static final String COMMAND_DELAY = "delay"; public static final String COMMAND_REPORT = "report"; + // These constants come from "include/uapi/linux/input.h" in the kernel + enum Bus { + USB(0x03), BLUETOOTH(0x05); + + Bus(int value) { + mValue = value; + } + + int getValue() { + return mValue; + } + + private int mValue; + } + private int mId; private String mCommand; private String mName; private byte[] mDescriptor; private int mVid; private int mPid; + private Bus mBus; private byte[] mReport; private SparseArray<byte[]> mFeatureReports; private Map<ByteBuffer, byte[]> mOutputs; @@ -71,6 +87,10 @@ public class Event { return mPid; } + public int getBus() { + return mBus.getValue(); + } + public byte[] getReport() { return mReport; } @@ -94,6 +114,7 @@ public class Event { + ", descriptor=" + Arrays.toString(mDescriptor) + ", vid=" + mVid + ", pid=" + mPid + + ", bus=" + mBus + ", report=" + Arrays.toString(mReport) + ", feature_reports=" + mFeatureReports.toString() + ", outputs=" + mOutputs.toString() @@ -144,6 +165,10 @@ public class Event { mEvent.mPid = pid; } + public void setBus(Bus bus) { + mEvent.mBus = bus; + } + public void setDuration(int duration) { mEvent.mDuration = duration; } @@ -206,6 +231,9 @@ public class Event { case "pid": eb.setPid(readInt()); break; + case "bus": + eb.setBus(readBus()); + break; case "report": eb.setReport(readData()); break; @@ -264,6 +292,11 @@ public class Event { return Integer.decode(val); } + private Bus readBus() throws IOException { + String val = mReader.nextString(); + return Bus.valueOf(val.toUpperCase()); + } + private SparseArray<byte[]> readFeatureReports() throws IllegalStateException, IOException { SparseArray<byte[]> featureReports = new SparseArray<>(); diff --git a/cmds/hid/src/com/android/commands/hid/Hid.java b/cmds/hid/src/com/android/commands/hid/Hid.java index 0ee2cc45932f..fac0ab2ef125 100644 --- a/cmds/hid/src/com/android/commands/hid/Hid.java +++ b/cmds/hid/src/com/android/commands/hid/Hid.java @@ -113,7 +113,7 @@ public class Hid { "Tried to send command \"" + e.getCommand() + "\" to an unregistered device!"); } int id = e.getId(); - Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), + Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(), e.getDescriptor(), e.getReport(), e.getFeatureReports(), e.getOutputs()); mDevices.append(id, d); } diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 93522d4ff0a6..73a8f666b78e 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -217,7 +217,10 @@ cc_binary { shared_libs: ["libgtest_prod"], - init_rc: ["statsd.rc"], + apex_available: [ + "com.android.os.statsd", + "test_com.android.os.statsd", + ], } // ============== @@ -299,6 +302,11 @@ cc_test { static_libs: [ "libgmock", "libplatformprotos", + + // TODO(b/149842105): Make libstatssocket shared and remove libcutils once statsd_test is + // moved to the apex. + "libstatssocket", + "libcutils", ], proto: { @@ -308,7 +316,6 @@ cc_test { shared_libs: [ "libprotobuf-cpp-lite", - "libstatssocket" ], } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index a4e8fdc10a3b..43d0fce316ad 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -392,6 +392,7 @@ message Atom { WifiFailureStatReported wifi_failure_stat_reported = 252 [(module) = "wifi"]; WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"]; AppFreezeChanged app_freeze_changed = 254 [(module) = "framework"]; + SnapshotMergeReported snapshot_merge_reported = 255; SdkExtensionStatus sdk_extension_status = 354; } @@ -4418,6 +4419,52 @@ message BootTimeEventErrorCode { optional int32 error_code = 2; } +/** + * Collects Virtual A/B statistics related to the use of dm-snapshot performed + * after an OTA. + * + * Logged from: + * - system/core/fs_mgr/libsnapshot/snapshot.cpp + * - system/core/fs_mgr/libsnapshot/snapshotctl.cpp + */ +message SnapshotMergeReported { + // Keep in sync with + // system/core/fs_mgr/libsnapshot/android/snapshot/snapshot.proto + enum UpdateState { + // No update or merge is in progress. + NONE = 0; + // An update is applying; snapshots may already exist. + INITIATED = 1; + // An update is pending, but has not been successfully booted yet. + UNVERIFIED = 2; + // The kernel is merging in the background. + MERGING = 3; + // Post-merge cleanup steps could not be completed due to a transient + // error, but the next reboot will finish any pending operations. + MERGE_NEEDS_REBOOT = 4; + // Merging is complete, and needs to be acknowledged. + MERGE_COMPLETED = 5; + // Merging failed due to an unrecoverable error. + MERGE_FAILED = 6; + // The update was implicitly cancelled, either by a rollback or a flash + // operation via fastboot. This state can only be returned by WaitForMerge. + CANCELLED = 7; + }; + + // Status of the update after the merge attempts. + optional UpdateState final_state = 1; + + // Time to complete a merge operation in milliseconds. + // A negative value corresponds to the case in which the merge operation + // was interrupted and resumed (e.g. in case of a system reboot during the + // merge). + optional int64 duration_millis = 2; + + // Number of reboots that occurred after issuing and before completing the + // merge of all the snapshot devices. + optional int32 intermediate_reboots = 3; +} + ////////////////////////////////////////////////////////////////////// // Pulled atoms below this line // ////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index c1e21959a667..c37328454c7d 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -27,6 +27,7 @@ import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; @@ -34,6 +35,7 @@ import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.graphics.drawable.Drawable; import android.hardware.fingerprint.FingerprintManager; import android.os.Build; import android.os.Parcel; @@ -786,12 +788,33 @@ public class AccessibilityServiceInfo implements Parcelable { * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> * </p> * @return The animated image resource id. + * @hide */ public int getAnimatedImageRes() { return mAnimatedImageRes; } /** + * The animated image drawable. + * <p> + * <strong>Statically set from + * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> + * </p> + * @return The animated image drawable. + */ + @Nullable + public Drawable loadAnimatedImage(@NonNull PackageManager packageManager) { + if (mAnimatedImageRes == /* invalid */ 0) { + return null; + } + + final String packageName = mComponentName.getPackageName(); + final ApplicationInfo applicationInfo = mResolveInfo.serviceInfo.applicationInfo; + + return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo); + } + + /** * Whether this service can retrieve the current window's content. * <p> * <strong>Statically set from diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java index 9912d2b1cc8b..d537ce1253dc 100644 --- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java @@ -22,10 +22,12 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Xml; @@ -193,12 +195,31 @@ public final class AccessibilityShortcutInfo { * The animated image resource id of the accessibility shortcut target. * * @return The animated image resource id. + * + * @hide */ public int getAnimatedImageRes() { return mAnimatedImageRes; } /** + * The animated image drawable of the accessibility shortcut target. + * + * @return The animated image drawable. + */ + @Nullable + public Drawable loadAnimatedImage(@NonNull PackageManager packageManager) { + if (mAnimatedImageRes == /* invalid */ 0) { + return null; + } + + final String packageName = mComponentName.getPackageName(); + final ApplicationInfo applicationInfo = mActivityInfo.applicationInfo; + + return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo); + } + + /** * The localized html description of the accessibility shortcut target. * * @return The localized html description. diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS index 265674a74b7e..c6f42f719caa 100644 --- a/core/java/android/accessibilityservice/OWNERS +++ b/core/java/android/accessibilityservice/OWNERS @@ -1,3 +1,4 @@ svetoslavganov@google.com pweaver@google.com rhedjao@google.com +qasid@google.com diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 9ed479840750..8f02f1555edf 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1035,10 +1035,12 @@ public class AppOpsManager { public static final int OP_ACTIVATE_PLATFORM_VPN = 94; /** @hide */ public static final int OP_LOADER_USAGE_STATS = 95; + /** @hide Access telephony call audio */ + public static final int OP_ACCESS_CALL_AUDIO = 96; /** @hide */ @UnsupportedAppUsage - public static final int _NUM_OP = 96; + public static final int _NUM_OP = 97; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1329,6 +1331,9 @@ public class AppOpsManager { @SystemApi public static final String OPSTR_MANAGE_EXTERNAL_STORAGE = "android:manage_external_storage"; + /** @hide Access telephony call audio */ + @SystemApi + public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio"; /** @hide Communicate cross-profile within the same profile group. */ @SystemApi @@ -1418,6 +1423,7 @@ public class AppOpsManager { OP_MANAGE_EXTERNAL_STORAGE, OP_INTERACT_ACROSS_PROFILES, OP_LOADER_USAGE_STATS, + OP_ACCESS_CALL_AUDIO, }; /** @@ -1525,6 +1531,7 @@ public class AppOpsManager { OP_INTERACT_ACROSS_PROFILES, //INTERACT_ACROSS_PROFILES OP_ACTIVATE_PLATFORM_VPN, // ACTIVATE_PLATFORM_VPN OP_LOADER_USAGE_STATS, // LOADER_USAGE_STATS + OP_ACCESS_CALL_AUDIO, // ACCESS_CALL_AUDIO }; /** @@ -1627,6 +1634,7 @@ public class AppOpsManager { OPSTR_INTERACT_ACROSS_PROFILES, OPSTR_ACTIVATE_PLATFORM_VPN, OPSTR_LOADER_USAGE_STATS, + OPSTR_ACCESS_CALL_AUDIO, }; /** @@ -1730,6 +1738,7 @@ public class AppOpsManager { "INTERACT_ACROSS_PROFILES", "ACTIVATE_PLATFORM_VPN", "LOADER_USAGE_STATS", + "ACCESS_CALL_AUDIO", }; /** @@ -1834,6 +1843,7 @@ public class AppOpsManager { android.Manifest.permission.INTERACT_ACROSS_PROFILES, null, // no permission for OP_ACTIVATE_PLATFORM_VPN android.Manifest.permission.LOADER_USAGE_STATS, + Manifest.permission.ACCESS_CALL_AUDIO, }; /** @@ -1938,6 +1948,7 @@ public class AppOpsManager { null, // INTERACT_ACROSS_PROFILES null, // ACTIVATE_PLATFORM_VPN null, // LOADER_USAGE_STATS + null, // ACCESS_CALL_AUDIO }; /** @@ -2041,6 +2052,7 @@ public class AppOpsManager { false, // INTERACT_ACROSS_PROFILES false, // ACTIVATE_PLATFORM_VPN false, // LOADER_USAGE_STATS + false, // ACCESS_CALL_AUDIO }; /** @@ -2143,6 +2155,7 @@ public class AppOpsManager { AppOpsManager.MODE_DEFAULT, // INTERACT_ACROSS_PROFILES AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS + AppOpsManager.MODE_DEFAULT, // ACCESS_CALL_AUDIO }; /** @@ -2249,6 +2262,7 @@ public class AppOpsManager { false, // INTERACT_ACROSS_PROFILES false, // ACTIVATE_PLATFORM_VPN false, // LOADER_USAGE_STATS + false, // ACCESS_CALL_AUDIO }; /** diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java index 130e2ecdcc83..6b1afdad82df 100644 --- a/core/java/android/app/AsyncNotedAppOp.java +++ b/core/java/android/app/AsyncNotedAppOp.java @@ -256,10 +256,10 @@ public final class AsyncNotedAppOp implements Parcelable { }; @DataClass.Generated( - time = 1580158740502L, + time = 1581728574427L, codegenVersion = "1.0.14", sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java", - inputSignatures = "private final @android.annotation.IntRange(from=0L, to=95L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)") + inputSignatures = "private final @android.annotation.IntRange(from=0L, to=96L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java index 229bee55e911..5bc999240a66 100644 --- a/core/java/android/app/DexLoadReporter.java +++ b/core/java/android/app/DexLoadReporter.java @@ -28,9 +28,8 @@ import dalvik.system.VMRuntime; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.HashSet; -import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -87,50 +86,32 @@ import java.util.Set; } @Override - public void report(List<ClassLoader> classLoadersChain, List<String> classPaths) { - if (classLoadersChain.size() != classPaths.size()) { - Slog.wtf(TAG, "Bad call to DexLoadReporter: argument size mismatch"); - return; - } - if (classPaths.isEmpty()) { - Slog.wtf(TAG, "Bad call to DexLoadReporter: empty dex paths"); - return; - } - - // The first element of classPaths is the list of dex files that should be registered. - // The classpath is represented as a list of dex files separated by File.pathSeparator. - String[] dexPathsForRegistration = classPaths.get(0).split(File.pathSeparator); - if (dexPathsForRegistration.length == 0) { - // No dex files to register. + public void report(Map<String, String> classLoaderContextMap) { + if (classLoaderContextMap.isEmpty()) { + Slog.wtf(TAG, "Bad call to DexLoadReporter: empty classLoaderContextMap"); return; } // Notify the package manager about the dex loads unconditionally. // The load might be for either a primary or secondary dex file. - notifyPackageManager(classLoadersChain, classPaths); + notifyPackageManager(classLoaderContextMap); // Check for secondary dex files and register them for profiling if possible. // Note that we only register the dex paths belonging to the first class loader. - registerSecondaryDexForProfiling(dexPathsForRegistration); + registerSecondaryDexForProfiling(classLoaderContextMap.keySet()); } - private void notifyPackageManager(List<ClassLoader> classLoadersChain, - List<String> classPaths) { + private void notifyPackageManager(Map<String, String> classLoaderContextMap) { // Get the class loader names for the binder call. - List<String> classLoadersNames = new ArrayList<>(classPaths.size()); - for (ClassLoader classLoader : classLoadersChain) { - classLoadersNames.add(classLoader.getClass().getName()); - } String packageName = ActivityThread.currentPackageName(); try { - ActivityThread.getPackageManager().notifyDexLoad( - packageName, classLoadersNames, classPaths, - VMRuntime.getRuntime().vmInstructionSet()); + ActivityThread.getPackageManager().notifyDexLoad(packageName, + classLoaderContextMap, VMRuntime.getRuntime().vmInstructionSet()); } catch (RemoteException re) { Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re); } } - private void registerSecondaryDexForProfiling(String[] dexPaths) { + private void registerSecondaryDexForProfiling(Set<String> dexPaths) { if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) { return; } diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java index 0287564bcc56..8eb7e7246976 100644 --- a/core/java/android/app/SharedElementCallback.java +++ b/core/java/android/app/SharedElementCallback.java @@ -19,7 +19,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.ColorSpace; -import android.graphics.GraphicBuffer; import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; @@ -48,8 +47,8 @@ import java.util.Map; public abstract class SharedElementCallback { private Matrix mTempMatrix; private static final String BUNDLE_SNAPSHOT_BITMAP = "sharedElement:snapshot:bitmap"; - private static final String BUNDLE_SNAPSHOT_GRAPHIC_BUFFER = - "sharedElement:snapshot:graphicBuffer"; + private static final String BUNDLE_SNAPSHOT_HARDWARE_BUFFER = + "sharedElement:snapshot:hardwareBuffer"; private static final String BUNDLE_SNAPSHOT_COLOR_SPACE = "sharedElement:snapshot:colorSpace"; private static final String BUNDLE_SNAPSHOT_IMAGE_SCALETYPE = "sharedElement:snapshot:imageScaleType"; private static final String BUNDLE_SNAPSHOT_IMAGE_MATRIX = "sharedElement:snapshot:imageMatrix"; @@ -186,8 +185,8 @@ public abstract class SharedElementCallback { if (bitmap.getConfig() != Bitmap.Config.HARDWARE) { bundle.putParcelable(BUNDLE_SNAPSHOT_BITMAP, bitmap); } else { - GraphicBuffer graphicBuffer = bitmap.createGraphicBufferHandle(); - bundle.putParcelable(BUNDLE_SNAPSHOT_GRAPHIC_BUFFER, graphicBuffer); + HardwareBuffer hardwareBuffer = bitmap.getHardwareBuffer(); + bundle.putParcelable(BUNDLE_SNAPSHOT_HARDWARE_BUFFER, hardwareBuffer); ColorSpace cs = bitmap.getColorSpace(); if (cs != null) { bundle.putInt(BUNDLE_SNAPSHOT_COLOR_SPACE, cs.getId()); @@ -235,7 +234,7 @@ public abstract class SharedElementCallback { View view = null; if (snapshot instanceof Bundle) { Bundle bundle = (Bundle) snapshot; - GraphicBuffer buffer = bundle.getParcelable(BUNDLE_SNAPSHOT_GRAPHIC_BUFFER); + HardwareBuffer buffer = bundle.getParcelable(BUNDLE_SNAPSHOT_HARDWARE_BUFFER); Bitmap bitmap = bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP); if (buffer == null && bitmap == null) { return null; @@ -246,8 +245,7 @@ public abstract class SharedElementCallback { if (colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length) { colorSpace = ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]); } - bitmap = Bitmap.wrapHardwareBuffer(HardwareBuffer.createFromGraphicBuffer(buffer), - colorSpace); + bitmap = Bitmap.wrapHardwareBuffer(buffer, colorSpace); } ImageView imageView = new ImageView(context); view = imageView; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index f1559f79996e..be87f5c4b2b9 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -186,6 +186,7 @@ import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyRegistryManager; import android.util.ArrayMap; import android.util.Log; +import android.util.Slog; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.WindowManager; @@ -222,6 +223,8 @@ import java.util.Objects; public final class SystemServiceRegistry { private static final String TAG = "SystemServiceRegistry"; + private static final boolean ENABLE_SERVICE_NOT_FOUND_WTF = true; + // Service registry information. // This information is never changed once static initialization has completed. private static final Map<Class<?>, String> SYSTEM_SERVICE_NAMES = @@ -1373,8 +1376,29 @@ public final class SystemServiceRegistry { * @hide */ public static Object getSystemService(ContextImpl ctx, String name) { - ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name); - return fetcher != null ? fetcher.getService(ctx) : null; + if (name == null) { + return null; + } + final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name); + if (ENABLE_SERVICE_NOT_FOUND_WTF && fetcher == null) { + // This should be a caller bug. + Slog.wtf(TAG, "Unknown manager requested: " + name); + return null; + } + + final Object ret = fetcher.getService(ctx); + if (ENABLE_SERVICE_NOT_FOUND_WTF && ret == null) { + // Some services do return null in certain situations, so don't do WTF for them. + switch (name) { + case Context.CONTENT_CAPTURE_MANAGER_SERVICE: + case Context.APP_PREDICTION_SERVICE: + case Context.INCREMENTAL_SERVICE: + return null; + } + Slog.wtf(TAG, "Manager wrapper not available: " + name); + return null; + } + return ret; } /** @@ -1382,7 +1406,15 @@ public final class SystemServiceRegistry { * @hide */ public static String getSystemServiceName(Class<?> serviceClass) { - return SYSTEM_SERVICE_NAMES.get(serviceClass); + if (serviceClass == null) { + return null; + } + final String serviceName = SYSTEM_SERVICE_NAMES.get(serviceClass); + if (ENABLE_SERVICE_NOT_FOUND_WTF && serviceName == null) { + // This should be a caller bug. + Slog.wtf(TAG, "Unknown manager requested: " + serviceClass.getCanonicalName()); + } + return serviceName; } /** @@ -1679,7 +1711,9 @@ public final class SystemServiceRegistry { try { cache.wait(); } catch (InterruptedException e) { - Log.w(TAG, "getService() interrupted"); + // This shouldn't normally happen, but if someone interrupts the + // thread, it will. + Slog.wtf(TAG, "getService() interrupted"); Thread.currentThread().interrupt(); return null; } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index c1bde704947e..546fef913192 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -33,6 +33,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.annotation.UserHandleAware; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; @@ -5740,6 +5741,25 @@ public class DevicePolicyManager { } /** + * Returns whether the admin has enabled always-on VPN lockdown for the current user. + * + * Only callable by the system. + * @hide + */ + @UserHandleAware + public boolean isAlwaysOnVpnLockdownEnabled() { + throwIfParentInstance("isAlwaysOnVpnLockdownEnabled"); + if (mService != null) { + try { + return mService.isAlwaysOnVpnLockdownEnabledForUser(myUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** * Called by device or profile owner to query the set of packages that are allowed to access * the network directly when always-on VPN is in lockdown mode but not connected. Returns * {@code null} when always-on VPN is not active or not in lockdown mode. @@ -5786,6 +5806,26 @@ public class DevicePolicyManager { } /** + * Returns the VPN package name if the admin has enabled always-on VPN on the current user, + * or {@code null} if none is set. + * + * Only callable by the system. + * @hide + */ + @UserHandleAware + public @Nullable String getAlwaysOnVpnPackage() { + throwIfParentInstance("getAlwaysOnVpnPackage"); + if (mService != null) { + try { + return mService.getAlwaysOnVpnPackageForUser(myUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return null; + } + + /** * Called by an application that is administering the device to disable all cameras on the * device, for this user. After setting this, no applications running as this user will be able * to access any cameras on the device. @@ -11990,4 +12030,21 @@ public class DevicePolicyManager { } return 0; } + + /** + * Returns {@code true} when {@code userId} has a profile owner that is capable of resetting + * password in RUNNING_LOCKED state. For that it should have at least one direct boot aware + * component and have an active password reset token. Can only be called by the system. + * @hide + */ + public boolean canProfileOwnerResetPasswordWhenLocked(int userId) { + if (mService != null) { + try { + return mService.canProfileOwnerResetPasswordWhenLocked(userId); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + return false; + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 84332ca466ef..d161e06d354d 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -196,7 +196,9 @@ interface IDevicePolicyManager { boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist); String getAlwaysOnVpnPackage(in ComponentName who); + String getAlwaysOnVpnPackageForUser(int userHandle); boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who); + boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle); List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who); void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); @@ -478,4 +480,5 @@ interface IDevicePolicyManager { long getManagedProfileMaximumTimeOff(in ComponentName admin); void setManagedProfileMaximumTimeOff(in ComponentName admin, long timeoutMs); + boolean canProfileOwnerResetPasswordWhenLocked(in int userId); } diff --git a/core/java/android/content/integrity/AppInstallMetadata.java b/core/java/android/content/integrity/AppInstallMetadata.java index 4be7e6df46e0..4ec94762ac34 100644 --- a/core/java/android/content/integrity/AppInstallMetadata.java +++ b/core/java/android/content/integrity/AppInstallMetadata.java @@ -42,6 +42,9 @@ public final class AppInstallMetadata { private final List<String> mInstallerCertificates; private final long mVersionCode; private final boolean mIsPreInstalled; + private final boolean mIsStampTrusted; + // Raw string encoding for the SHA-256 hash of the certificate of the stamp. + private final String mStampCertificateHash; private final Map<String, String> mAllowedInstallersAndCertificates; private AppInstallMetadata(Builder builder) { @@ -51,6 +54,8 @@ public final class AppInstallMetadata { this.mInstallerCertificates = builder.mInstallerCertificates; this.mVersionCode = builder.mVersionCode; this.mIsPreInstalled = builder.mIsPreInstalled; + this.mIsStampTrusted = builder.mIsStampTrusted; + this.mStampCertificateHash = builder.mStampCertificateHash; this.mAllowedInstallersAndCertificates = builder.mAllowedInstallersAndCertificates; } @@ -84,9 +89,17 @@ public final class AppInstallMetadata { return mIsPreInstalled; } - /** - * Get the allowed installers and their corresponding cert. - */ + /** @see AppInstallMetadata.Builder#setIsStampTrusted(boolean) */ + public boolean isStampTrusted() { + return mIsStampTrusted; + } + + /** @see AppInstallMetadata.Builder#setStampCertificateHash(String) */ + public String getStampCertificateHash() { + return mStampCertificateHash; + } + + /** Get the allowed installers and their corresponding cert. */ public Map<String, String> getAllowedInstallersAndCertificates() { return mAllowedInstallersAndCertificates; } @@ -95,13 +108,16 @@ public final class AppInstallMetadata { public String toString() { return String.format( "AppInstallMetadata { PackageName = %s, AppCerts = %s, InstallerName = %s," - + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b }", + + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b, " + + "StampTrusted = %b, StampCert = %s }", mPackageName, mAppCertificates, mInstallerName == null ? "null" : mInstallerName, mInstallerCertificates == null ? "null" : mInstallerCertificates, mVersionCode, - mIsPreInstalled); + mIsPreInstalled, + mIsStampTrusted, + mStampCertificateHash == null ? "null" : mStampCertificateHash); } /** Builder class for constructing {@link AppInstallMetadata} objects. */ @@ -112,6 +128,8 @@ public final class AppInstallMetadata { private List<String> mInstallerCertificates; private long mVersionCode; private boolean mIsPreInstalled; + private boolean mIsStampTrusted; + private String mStampCertificateHash; private Map<String, String> mAllowedInstallersAndCertificates; public Builder() { @@ -203,6 +221,31 @@ public final class AppInstallMetadata { } /** + * Set certificate hash of the stamp embedded in the APK. + * + * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate + * of the stamp. + * + * @see AppInstallMetadata#getStampCertificateHash() + */ + @NonNull + public Builder setStampCertificateHash(@NonNull String stampCertificateHash) { + this.mStampCertificateHash = Objects.requireNonNull(stampCertificateHash); + return this; + } + + /** + * Set whether the stamp embedded in the APK is trusted or not. + * + * @see AppInstallMetadata#isStampTrusted() + */ + @NonNull + public Builder setIsStampTrusted(boolean isStampTrusted) { + this.mIsStampTrusted = isStampTrusted; + return this; + } + + /** * Build {@link AppInstallMetadata}. * * @throws IllegalArgumentException if package name or app certificate is null diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java index d911eabc3b83..977a631cecd8 100644 --- a/core/java/android/content/integrity/AtomicFormula.java +++ b/core/java/android/content/integrity/AtomicFormula.java @@ -47,12 +47,14 @@ public abstract class AtomicFormula extends IntegrityFormula { /** @hide */ @IntDef( value = { - PACKAGE_NAME, - APP_CERTIFICATE, - INSTALLER_NAME, - INSTALLER_CERTIFICATE, - VERSION_CODE, - PRE_INSTALLED, + PACKAGE_NAME, + APP_CERTIFICATE, + INSTALLER_NAME, + INSTALLER_CERTIFICATE, + VERSION_CODE, + PRE_INSTALLED, + STAMP_TRUSTED, + STAMP_CERTIFICATE_HASH, }) @Retention(RetentionPolicy.SOURCE) public @interface Key {} @@ -105,6 +107,20 @@ public abstract class AtomicFormula extends IntegrityFormula { */ public static final int PRE_INSTALLED = 5; + /** + * If the APK has an embedded trusted stamp. + * + * <p>Can only be used in {@link BooleanAtomicFormula}. + */ + public static final int STAMP_TRUSTED = 6; + + /** + * SHA-256 of the certificate used to sign the stamp embedded in the APK. + * + * <p>Can only be used in {@link StringAtomicFormula}. + */ + public static final int STAMP_CERTIFICATE_HASH = 7; + public static final int EQ = 0; public static final int GT = 1; public static final int GTE = 2; @@ -266,9 +282,7 @@ public abstract class AtomicFormula extends IntegrityFormula { } private static boolean isValidOperator(int operator) { - return operator == EQ - || operator == GT - || operator == GTE; + return operator == EQ || operator == GT || operator == GTE; } private static long getLongMetadataValue(AppInstallMetadata appInstallMetadata, int key) { @@ -300,7 +314,8 @@ public abstract class AtomicFormula extends IntegrityFormula { key == PACKAGE_NAME || key == APP_CERTIFICATE || key == INSTALLER_CERTIFICATE - || key == INSTALLER_NAME, + || key == INSTALLER_NAME + || key == STAMP_CERTIFICATE_HASH, String.format( "Key %s cannot be used with StringAtomicFormula", keyToString(key))); mValue = null; @@ -321,7 +336,8 @@ public abstract class AtomicFormula extends IntegrityFormula { key == PACKAGE_NAME || key == APP_CERTIFICATE || key == INSTALLER_CERTIFICATE - || key == INSTALLER_NAME, + || key == INSTALLER_NAME + || key == STAMP_CERTIFICATE_HASH, String.format( "Key %s cannot be used with StringAtomicFormula", keyToString(key))); mValue = value; @@ -329,15 +345,14 @@ public abstract class AtomicFormula extends IntegrityFormula { } /** - * Constructs a new {@link StringAtomicFormula} together with handling the necessary - * hashing for the given key. + * Constructs a new {@link StringAtomicFormula} together with handling the necessary hashing + * for the given key. * - * <p> The value will be automatically hashed with SHA256 and the hex digest will be - * computed when the key is PACKAGE_NAME or INSTALLER_NAME and the value is more than 32 - * characters. + * <p>The value will be automatically hashed with SHA256 and the hex digest will be computed + * when the key is PACKAGE_NAME or INSTALLER_NAME and the value is more than 32 characters. * - * <p> The APP_CERTIFICATES and INSTALLER_CERTIFICATES are always delivered in hashed - * form. So the isHashedValue is set to true by default. + * <p>The APP_CERTIFICATES, INSTALLER_CERTIFICATES, and STAMP_CERTIFICATE_HASH are always + * delivered in hashed form. So the isHashedValue is set to true by default. * * @throws IllegalArgumentException if {@code key} cannot be used with string value. */ @@ -347,13 +362,15 @@ public abstract class AtomicFormula extends IntegrityFormula { key == PACKAGE_NAME || key == APP_CERTIFICATE || key == INSTALLER_CERTIFICATE - || key == INSTALLER_NAME, + || key == INSTALLER_NAME + || key == STAMP_CERTIFICATE_HASH, String.format( "Key %s cannot be used with StringAtomicFormula", keyToString(key))); mValue = hashValue(key, value); mIsHashedValue = key == APP_CERTIFICATE - || key == INSTALLER_CERTIFICATE + || key == INSTALLER_CERTIFICATE + || key == STAMP_CERTIFICATE_HASH ? true : !mValue.equals(value); } @@ -460,6 +477,8 @@ public abstract class AtomicFormula extends IntegrityFormula { return appInstallMetadata.getInstallerCertificates(); case AtomicFormula.INSTALLER_NAME: return Collections.singletonList(appInstallMetadata.getInstallerName()); + case AtomicFormula.STAMP_CERTIFICATE_HASH: + return Collections.singletonList(appInstallMetadata.getStampCertificateHash()); default: throw new IllegalStateException( "Unexpected key in StringAtomicFormula: " + key); @@ -502,7 +521,7 @@ public abstract class AtomicFormula extends IntegrityFormula { public BooleanAtomicFormula(@Key int key) { super(key); checkArgument( - key == PRE_INSTALLED, + key == PRE_INSTALLED || key == STAMP_TRUSTED, String.format( "Key %s cannot be used with BooleanAtomicFormula", keyToString(key))); mValue = null; @@ -519,7 +538,7 @@ public abstract class AtomicFormula extends IntegrityFormula { public BooleanAtomicFormula(@Key int key, boolean value) { super(key); checkArgument( - key == PRE_INSTALLED, + key == PRE_INSTALLED || key == STAMP_TRUSTED, String.format( "Key %s cannot be used with BooleanAtomicFormula", keyToString(key))); mValue = value; @@ -615,6 +634,8 @@ public abstract class AtomicFormula extends IntegrityFormula { switch (key) { case AtomicFormula.PRE_INSTALLED: return appInstallMetadata.isPreInstalled(); + case AtomicFormula.STAMP_TRUSTED: + return appInstallMetadata.isStampTrusted(); default: throw new IllegalStateException( "Unexpected key in BooleanAtomicFormula: " + key); @@ -640,6 +661,10 @@ public abstract class AtomicFormula extends IntegrityFormula { return "INSTALLER_CERTIFICATE"; case PRE_INSTALLED: return "PRE_INSTALLED"; + case STAMP_TRUSTED: + return "STAMP_TRUSTED"; + case STAMP_CERTIFICATE_HASH: + return "STAMP_CERTIFICATE_HASH"; default: throw new IllegalArgumentException("Unknown key " + key); } @@ -664,6 +689,8 @@ public abstract class AtomicFormula extends IntegrityFormula { || key == VERSION_CODE || key == INSTALLER_NAME || key == INSTALLER_CERTIFICATE - || key == PRE_INSTALLED; + || key == PRE_INSTALLED + || key == STAMP_TRUSTED + || key == STAMP_CERTIFICATE_HASH; } } diff --git a/core/java/android/content/integrity/IntegrityFormula.java b/core/java/android/content/integrity/IntegrityFormula.java index c5e5c8a8daad..fc177721240c 100644 --- a/core/java/android/content/integrity/IntegrityFormula.java +++ b/core/java/android/content/integrity/IntegrityFormula.java @@ -90,8 +90,7 @@ public abstract class IntegrityFormula { return new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true); } - private Application() { - } + private Application() {} } /** Factory class for creating integrity formulas based on installer. */ @@ -117,26 +116,45 @@ public abstract class IntegrityFormula { */ @NonNull public static IntegrityFormula certificatesContain(@NonNull String installerCertificate) { - return new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE, - installerCertificate); + return new StringAtomicFormula( + AtomicFormula.INSTALLER_CERTIFICATE, installerCertificate); } - private Installer() { + private Installer() {} + } + + /** Factory class for creating integrity formulas based on source stamp. */ + public static final class SourceStamp { + /** Returns an integrity formula that checks the equality to a stamp certificate hash. */ + @NonNull + public static IntegrityFormula stampCertificateHashEquals( + @NonNull String stampCertificateHash) { + return new StringAtomicFormula( + AtomicFormula.STAMP_CERTIFICATE_HASH, stampCertificateHash); + } + + /** + * Returns an integrity formula that is valid when stamp embedded in the APK is NOT trusted. + */ + @NonNull + public static IntegrityFormula notTrusted() { + return new BooleanAtomicFormula(AtomicFormula.STAMP_TRUSTED, /* value= */ false); } + + private SourceStamp() {} } /** @hide */ @IntDef( value = { - COMPOUND_FORMULA_TAG, - STRING_ATOMIC_FORMULA_TAG, - LONG_ATOMIC_FORMULA_TAG, - BOOLEAN_ATOMIC_FORMULA_TAG, - INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG + COMPOUND_FORMULA_TAG, + STRING_ATOMIC_FORMULA_TAG, + LONG_ATOMIC_FORMULA_TAG, + BOOLEAN_ATOMIC_FORMULA_TAG, + INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG }) @Retention(RetentionPolicy.SOURCE) - @interface Tag { - } + @interface Tag {} /** @hide */ public static final int COMPOUND_FORMULA_TAG = 0; @@ -171,8 +189,8 @@ public abstract class IntegrityFormula { public abstract boolean isAppCertificateFormula(); /** - * Returns true when the formula (or one of its atomic formulas) has installer package name - * or installer certificate as key. + * Returns true when the formula (or one of its atomic formulas) has installer package name or + * installer certificate as key. * * @hide */ @@ -243,15 +261,12 @@ public abstract class IntegrityFormula { return new CompoundFormula(CompoundFormula.AND, Arrays.asList(formulae)); } - /** - * Returns a formula that evaluates to true when {@code formula} evaluates to false. - */ + /** Returns a formula that evaluates to true when {@code formula} evaluates to false. */ @NonNull public static IntegrityFormula not(@NonNull IntegrityFormula formula) { return new CompoundFormula(CompoundFormula.NOT, Arrays.asList(formula)); } // Constructor is package private so it cannot be inherited outside of this package. - IntegrityFormula() { - } + IntegrityFormula() {} } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java b/core/java/android/content/pm/AndroidTestBaseUpdater.java index 0b871e433f5b..1cbbdca76e13 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java +++ b/core/java/android/content/pm/AndroidTestBaseUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,21 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.screenshot; -import android.app.Activity; -import android.os.Bundle; - -import com.android.systemui.tests.R; +package android.content.pm; /** - * A stub activity used in {@link ScreenshotTest}. + * Dummy class to maintain legacy behavior of including a class in core source to toggle + * whether or not a shared library is stripped at build time. + * + * @hide */ -public class ScreenshotStubActivity extends Activity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - } +public class AndroidTestBaseUpdater { } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index b89901aff47b..e9cdbf28e9cb 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -482,19 +482,12 @@ interface IPackageManager { * Notify the package manager that a list of dex files have been loaded. * * @param loadingPackageName the name of the package who performs the load - * @param classLoadersNames the names of the class loaders present in the loading chain. The - * list encodes the class loader chain in the natural order. The first class loader has - * the second one as its parent and so on. The dex files present in the class path of the - * first class loader will be recorded in the usage file. - * @param classPaths the class paths corresponding to the class loaders names from - * {@param classLoadersNames}. The the first element corresponds to the first class loader - * and so on. A classpath is represented as a list of dex files separated by - * {@code File.pathSeparator}, or null if the class loader's classpath is not known. - * The dex files found in the first class path will be recorded in the usage file. + * @param classLoaderContextMap a map from file paths to dex files that have been loaded to + * the class loader context that was used to load them. * @param loaderIsa the ISA of the loader process */ - oneway void notifyDexLoad(String loadingPackageName, in List<String> classLoadersNames, - in List<String> classPaths, String loaderIsa); + oneway void notifyDexLoad(String loadingPackageName, + in Map<String, String> classLoaderContextMap, String loaderIsa); /** * Register an application dex module with the package manager. diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl index 9e85fc301a0c..29a55b7a74da 100644 --- a/core/java/android/content/pm/IShortcutService.aidl +++ b/core/java/android/content/pm/IShortcutService.aidl @@ -76,4 +76,6 @@ interface IShortcutService { void removeLongLivedShortcuts(String packageName, in List shortcutIds, int userId); ParceledListSlice getShortcuts(String packageName, int matchFlags, int userId); + + void pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId); }
\ No newline at end of file diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 168679e793f8..1de8245088da 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -41,7 +41,6 @@ import static android.os.Build.VERSION_CODES.O; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; -import android.annotation.AnyThread; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -56,12 +55,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageParserCacheHelper.ReadHelper; -import android.content.pm.PackageParserCacheHelper.WriteHelper; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ApkParseUtils; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.permission.SplitPermissionInfoParcelable; import android.content.pm.split.DefaultSplitAssetLoader; import android.content.pm.split.SplitAssetDependencyLoader; @@ -79,14 +73,10 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.PatternMatcher; import android.os.RemoteException; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; -import android.system.ErrnoException; -import android.system.OsConstants; -import android.system.StructStat; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -118,7 +108,6 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -316,9 +305,6 @@ public class PackageParser { public int mParseError = PackageManager.INSTALL_SUCCEEDED; - public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult - = ThreadLocal.withInitial(ApkParseUtils.ParseResult::new); - public static boolean sCompatibilityModeEnabled = true; public static boolean sUseRoundIcon = false; @@ -1054,7 +1040,7 @@ public class PackageParser { * and unique split names. * <p> * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. + * must be done separately in {@link #collectCertificates(Package, boolean)}. * * If {@code useCaches} is true, the package parser might return a cached * result from a previous parse of the same {@code packageFile} with the same @@ -1082,201 +1068,6 @@ public class PackageParser { } /** - * Updated method which returns {@link ParsedPackage}, the current representation of a - * package parsed from disk. - * - * @see #parsePackage(File, int, boolean) - */ - @AnyThread - public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches) - throws PackageParserException { - ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null; - if (parsed != null) { - return parsed; - } - - long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; - ApkParseUtils.ParseInput parseInput = mSharedResult.get().reset(); - parsed = ApkParseUtils.parsePackage( - parseInput, - mSeparateProcesses, - mCallback, - mMetrics, - mOnlyCoreApps, - packageFile, - flags - ) - .hideAsParsed(); - - long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; - cacheResult(packageFile, flags, parsed); - if (LOG_PARSE_TIMINGS) { - parseTime = cacheTime - parseTime; - cacheTime = SystemClock.uptimeMillis() - cacheTime; - if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) { - Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime - + "ms, update_cache=" + cacheTime + " ms"); - } - } - - return parsed; - } - - /** - * Returns the cache key for a specified {@code packageFile} and {@code flags}. - */ - private String getCacheKey(File packageFile, int flags) { - StringBuilder sb = new StringBuilder(packageFile.getName()); - sb.append('-'); - sb.append(flags); - - return sb.toString(); - } - - @VisibleForTesting - protected ParsedPackage fromCacheEntry(byte[] bytes) { - return fromCacheEntryStatic(bytes); - } - - /** static version of {@link #fromCacheEntry} for unit tests. */ - @VisibleForTesting - public static ParsedPackage fromCacheEntryStatic(byte[] bytes) { - final Parcel p = Parcel.obtain(); - p.unmarshall(bytes, 0, bytes.length); - p.setDataPosition(0); - - final ReadHelper helper = new ReadHelper(p); - helper.startAndInstall(); - - // TODO(b/135203078): Hide PackageImpl constructor? - ParsedPackage pkg = new PackageImpl(p); - - p.recycle(); - - sCachedPackageReadCount.incrementAndGet(); - - return pkg; - } - - @VisibleForTesting - protected byte[] toCacheEntry(ParsedPackage pkg) { - return toCacheEntryStatic(pkg); - - } - - /** static version of {@link #toCacheEntry} for unit tests. */ - @VisibleForTesting - public static byte[] toCacheEntryStatic(ParsedPackage pkg) { - final Parcel p = Parcel.obtain(); - final WriteHelper helper = new WriteHelper(p); - - pkg.writeToParcel(p, 0 /* flags */); - - helper.finishAndUninstall(); - - byte[] serialized = p.marshall(); - p.recycle(); - - return serialized; - } - - /** - * Given a {@code packageFile} and a {@code cacheFile} returns whether the - * cache file is up to date based on the mod-time of both files. - */ - private static boolean isCacheUpToDate(File packageFile, File cacheFile) { - try { - // NOTE: We don't use the File.lastModified API because it has the very - // non-ideal failure mode of returning 0 with no excepions thrown. - // The nio2 Files API is a little better but is considerably more expensive. - final StructStat pkg = android.system.Os.stat(packageFile.getAbsolutePath()); - final StructStat cache = android.system.Os.stat(cacheFile.getAbsolutePath()); - return pkg.st_mtime < cache.st_mtime; - } catch (ErrnoException ee) { - // The most common reason why stat fails is that a given cache file doesn't - // exist. We ignore that here. It's easy to reason that it's safe to say the - // cache isn't up to date if we see any sort of exception here. - // - // (1) Exception while stating the package file : This should never happen, - // and if it does, we do a full package parse (which is likely to throw the - // same exception). - // (2) Exception while stating the cache file : If the file doesn't exist, the - // cache is obviously out of date. If the file *does* exist, we can't read it. - // We will attempt to delete and recreate it after parsing the package. - if (ee.errno != OsConstants.ENOENT) { - Slog.w("Error while stating package cache : ", ee); - } - - return false; - } - } - - /** - * Returns the cached parse result for {@code packageFile} for parse flags {@code flags}, - * or {@code null} if no cached result exists. - */ - public ParsedPackage getCachedResult(File packageFile, int flags) { - if (mCacheDir == null) { - return null; - } - - final String cacheKey = getCacheKey(packageFile, flags); - final File cacheFile = new File(mCacheDir, cacheKey); - - try { - // If the cache is not up to date, return null. - if (!isCacheUpToDate(packageFile, cacheFile)) { - return null; - } - - final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath()); - return fromCacheEntry(bytes); - } catch (Throwable e) { - Slog.w(TAG, "Error reading package cache: ", e); - - // If something went wrong while reading the cache entry, delete the cache file - // so that we regenerate it the next time. - cacheFile.delete(); - return null; - } - } - - /** - * Caches the parse result for {@code packageFile} with flags {@code flags}. - */ - public void cacheResult(File packageFile, int flags, ParsedPackage parsed) { - if (mCacheDir == null) { - return; - } - - try { - final String cacheKey = getCacheKey(packageFile, flags); - final File cacheFile = new File(mCacheDir, cacheKey); - - if (cacheFile.exists()) { - if (!cacheFile.delete()) { - Slog.e(TAG, "Unable to delete cache file: " + cacheFile); - } - } - - final byte[] cacheEntry = toCacheEntry(parsed); - - if (cacheEntry == null) { - return; - } - - try (FileOutputStream fos = new FileOutputStream(cacheFile)) { - fos.write(cacheEntry); - } catch (IOException ioe) { - Slog.w(TAG, "Error writing cache entry.", ioe); - cacheFile.delete(); - } - } catch (Throwable e) { - Slog.w(TAG, "Error saving package cache.", e); - } - } - - /** * Parse all APKs contained in the given directory, treating them as a * single package. This also performs sanity checking, such as requiring * identical package name and version codes, a single base APK, and unique @@ -1284,7 +1075,7 @@ public class PackageParser { * <p> * Note that this <em>does not</em> perform signature verification; that * must be done separately in - * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. + * {@link #collectCertificates(Package, boolean)} . */ private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException { final PackageLite lite = parseClusterPackageLite(packageDir, 0); @@ -1346,7 +1137,7 @@ public class PackageParser { * <p> * Note that this <em>does not</em> perform signature verification; that * must be done separately in - * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. + * {@link #collectCertificates(Package, boolean)}. */ @UnsupportedAppUsage public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException { @@ -1695,7 +1486,7 @@ public class PackageParser { } } - private static String validateName(String name, boolean requireSeparator, + public static String validateName(String name, boolean requireSeparator, boolean requireFilename) { final int N = name.length(); boolean hasSep = false; diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index da7623a1426e..30cf4e76ba04 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -28,7 +28,7 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPON import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import android.compat.annotation.UnsupportedAppUsage; -import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.component.ParsedMainComponent; import android.os.BaseBundle; import android.os.Debug; import android.os.PersistableBundle; @@ -163,7 +163,7 @@ public class PackageUserState { } public boolean isMatch(boolean isSystem, boolean isPackageEnabled, - ComponentParseUtils.ParsedComponent component, int flags) { + ParsedMainComponent component, int flags) { return isMatch(isSystem, isPackageEnabled, component.isEnabled(), component.isDirectBootAware(), component.getName(), flags); } @@ -217,7 +217,7 @@ public class PackageUserState { } public boolean isEnabled(boolean isPackageEnabled, - ComponentParseUtils.ParsedComponent parsedComponent, int flags) { + ParsedMainComponent parsedComponent, int flags) { return isEnabled(isPackageEnabled, parsedComponent.isEnabled(), parsedComponent.getName(), flags); } diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java index 55846adf2f1f..82b07f24a906 100644 --- a/core/java/android/content/pm/ResolveInfo.java +++ b/core/java/android/content/pm/ResolveInfo.java @@ -39,6 +39,8 @@ import java.util.Comparator; */ public class ResolveInfo implements Parcelable { private static final String TAG = "ResolveInfo"; + private static final String INTENT_FORWARDER_ACTIVITY = + "com.android.internal.app.IntentForwarderActivity"; /** * The activity or broadcast receiver that corresponds to this resolution @@ -351,6 +353,16 @@ public class ResolveInfo implements Parcelable { } } + /** + * Returns whether this resolution represents the intent forwarder activity. + * + * @return whether this resolution represents the intent forwarder activity + */ + public boolean isCrossProfileIntentForwarderActivity() { + return activityInfo != null + && INTENT_FORWARDER_ACTIVITY.equals(activityInfo.targetActivity); + } + public ResolveInfo() { targetUserId = UserHandle.USER_CURRENT; } diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index 2863b268e795..fe4b36fd9ae3 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -20,7 +20,6 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.pm.parsing.AndroidPackage; import android.os.Parcel; import android.os.Parcelable; @@ -39,28 +38,6 @@ import java.util.List; public final class SharedLibraryInfo implements Parcelable { /** @hide */ - public static SharedLibraryInfo createForStatic(AndroidPackage pkg) { - return new SharedLibraryInfo(null, pkg.getPackageName(), - pkg.makeListAllCodePaths(), - pkg.getStaticSharedLibName(), - pkg.getStaticSharedLibVersion(), - TYPE_STATIC, - new VersionedPackage(pkg.getManifestPackageName(), - pkg.getLongVersionCode()), - null, null); - } - - /** @hide */ - public static SharedLibraryInfo createForDynamic(AndroidPackage pkg, String name) { - return new SharedLibraryInfo(null, pkg.getPackageName(), - pkg.makeListAllCodePaths(), name, - (long) VERSION_UNDEFINED, - TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(), - pkg.getLongVersionCode()), - null, null); - } - - /** @hide */ @IntDef(flag = true, prefix = { "TYPE_" }, value = { TYPE_BUILTIN, TYPE_DYNAMIC, diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index bde4f614a39e..49e8c052cbca 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -1726,11 +1726,11 @@ public final class ShortcutInfo implements Parcelable { } /** - * @return true if pinned but neither static nor dynamic. + * @return true if pinned or cached, but neither static nor dynamic. * @hide */ public boolean isFloating() { - return isPinned() && !(isDynamic() || isManifestShortcut()); + return (isPinned() || isCached()) && !(isDynamic() || isManifestShortcut()); } /** @hide */ diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index 3eea3f62fd46..35c99a13a152 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -24,6 +24,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.UserIdInt; +import android.app.Notification; import android.app.usage.UsageStatsManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -741,4 +742,33 @@ public class ShortcutManager { throw e.rethrowFromSystemServer(); } } + + /** + * Publish a single dynamic shortcut. If there are already dynamic or pinned shortcuts with the + * same ID, each mutable shortcut is updated. + * + * <p>This method is useful when posting notifications which are tagged with shortcut IDs; In + * order to make sure shortcuts exist and are up-to-date, without the need to explicitly handle + * the shortcut count limit. + * @see android.app.NotificationManager#notify(int, Notification) + * @see Notification.Builder#setShortcutId(String) + * + * <p>If {@link #getMaxShortcutCountPerActivity()} is already reached, an existing shortcut with + * the lowest rank will be removed to add space for the new shortcut. + * + * <p>If the rank of the shortcut is not explicitly set, it will be set to zero, and shortcut + * will be added to the top of the list. + * + * @throws IllegalArgumentException if trying to update an immutable shortcut. + * + * @throws IllegalStateException when the user is locked. + */ + public void pushDynamicShortcut(@NonNull ShortcutInfo shortcut) { + try { + mService.pushDynamicShortcut(mContext.getPackageName(), shortcut, injectMyUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java index 4cd201fbe538..cdb1d221d177 100644 --- a/core/java/android/content/pm/dex/DexMetadataHelper.java +++ b/core/java/android/content/pm/dex/DexMetadataHelper.java @@ -22,7 +22,6 @@ import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.parsing.AndroidPackage; import android.util.ArrayMap; import android.util.jar.StrictJarFile; @@ -87,16 +86,6 @@ public class DexMetadataHelper { * * NOTE: involves I/O checks. */ - public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) { - return buildPackageApkToDexMetadataMap(pkg.makeListAllCodePaths()); - } - - /** - * Return the dex metadata files for the given package as a map - * [code path -> dex metadata path]. - * - * NOTE: involves I/O checks. - */ private static Map<String, String> getPackageDexMetadata(PackageLite pkg) { return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths()); } @@ -114,7 +103,7 @@ public class DexMetadataHelper { * This should only be used for code paths extracted from a package structure after the naming * was enforced in the installer. */ - private static Map<String, String> buildPackageApkToDexMetadataMap( + public static Map<String, String> buildPackageApkToDexMetadataMap( List<String> codePaths) { ArrayMap<String, String> result = new ArrayMap<>(); for (int i = codePaths.size() - 1; i >= 0; i--) { @@ -157,25 +146,12 @@ public class DexMetadataHelper { } /** - * Validate the dex metadata files installed for the given package. - * - * @throws PackageParserException in case of errors. - */ - public static void validatePackageDexMetadata(AndroidPackage pkg) - throws PackageParserException { - Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values(); - for (String dexMetadata : apkToDexMetadataList) { - validateDexMetadataFile(dexMetadata); - } - } - - /** * Validate that the given file is a dex metadata archive. * This is just a sanity validation that the file is a zip archive. * * @throws PackageParserException if the file is not a .dm file. */ - private static void validateDexMetadataFile(String dmaPath) throws PackageParserException { + public static void validateDexMetadataFile(String dmaPath) throws PackageParserException { StrictJarFile jarFile = null; try { jarFile = new StrictJarFile(dmaPath, false, false); diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java deleted file mode 100644 index 2003ce27a214..000000000000 --- a/core/java/android/content/pm/parsing/AndroidPackage.java +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package android.content.pm.parsing; - -import android.annotation.Nullable; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.ConfigurationInfo; -import android.content.pm.FeatureGroupInfo; -import android.content.pm.FeatureInfo; -import android.content.pm.PackageParser; -import android.content.pm.PackageUserState; -import android.content.pm.SharedLibraryInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedFeature; -import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; -import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; -import android.content.pm.parsing.ComponentParseUtils.ParsedService; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.SparseArray; - -import java.security.PublicKey; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -/** - * The last state of a package during parsing/install before it is available in - * {@link com.android.server.pm.PackageManagerService#mPackages}. - * - * It is the responsibility of the caller to understand what data is available at what step of the - * parsing or install process. - * - * TODO(b/135203078): Nullability annotations - * TODO(b/135203078): Remove get/setAppInfo differences - * - * @hide - */ -public interface AndroidPackage extends Parcelable { - - /** - * This will eventually be removed. Avoid calling this at all costs. - */ - @Deprecated - AndroidPackageWrite mutate(); - - boolean canHaveOatDir(); - - boolean cantSaveState(); - - List<String> getAdoptPermissions(); - - List<String> getAllCodePaths(); - - List<String> getAllCodePathsExcludingResourceOnly(); - - String getAppComponentFactory(); - - /** - * TODO(b/135203078): Use non-AppInfo method - * @deprecated use {@link #getClassLoaderName()} - */ - @Deprecated - String getAppInfoClassLoaderName(); - - /** - * TODO(b/135203078): Use non-AppInfo method - * @deprecated use {@link #getCodePath()} - */ - @Deprecated - String getAppInfoCodePath(); - - /** - * TODO(b/135203078): Use non-AppInfo method - * @deprecated use {@link #getName()} - */ - @Deprecated - String getAppInfoName(); - - /** - * TODO(b/135203078): Use non-AppInfo method - * @deprecated use {@link #getPackageName()} - */ - @Deprecated - String getAppInfoPackageName(); - - /** - * TODO(b/135203078): Use non-AppInfo method - * @deprecated use {@link #getProcessName()} - */ - @Deprecated - String getAppInfoProcessName(); - - /** - * TODO(b/135203078): Use non-AppInfo method - * @deprecated use {@link #getCodePath()} - */ - @Deprecated - String getAppInfoResourcePath(); - - Bundle getAppMetaData(); - - /** - * TODO(b/135203078): Use non-AppInfo method - * @deprecated use {@link #getVolumeUuid()} - */ - @Deprecated - String getApplicationInfoVolumeUuid(); - - String getBackupAgentName(); - - int getBanner(); - - String getBaseCodePath(); - - int getBaseRevisionCode(); - - int getCategory(); - - String getClassLoaderName(); - - String getClassName(); - - String getCodePath(); - - int getCompatibleWidthLimitDp(); - - int getCompileSdkVersion(); - - String getCompileSdkVersionCodeName(); - - @Nullable - List<ConfigurationInfo> getConfigPreferences(); - - String getCpuAbiOverride(); - - String getCredentialProtectedDataDir(); - - String getDataDir(); - - int getDescriptionRes(); - - String getDeviceProtectedDataDir(); - - List<FeatureGroupInfo> getFeatureGroups(); - - int getFlags(); - - int getFullBackupContent(); - - int getHiddenApiEnforcementPolicy(); - - int getIcon(); - - int getIconRes(); - - List<String> getImplicitPermissions(); - - int getInstallLocation(); - - Map<String, ArraySet<PublicKey>> getKeySetMapping(); - - int getLabelRes(); - - int getLargestWidthLimitDp(); - - long[] getLastPackageUsageTimeInMills(); - - long getLatestForegroundPackageUseTimeInMills(); - - long getLatestPackageUseTimeInMills(); - - List<String> getLibraryNames(); - - int getLogo(); - - long getLongVersionCode(); - - String getManageSpaceActivityName(); - - String getManifestPackageName(); - - float getMaxAspectRatio(); - - Bundle getMetaData(); // TODO(b/135203078): Make all the Bundles immutable - - @Nullable - Set<String> getMimeGroups(); - - float getMinAspectRatio(); - - int getMinSdkVersion(); - - String getName(); - - String getNativeLibraryDir(); - - String getNativeLibraryRootDir(); - - int getNetworkSecurityConfigRes(); - - CharSequence getNonLocalizedLabel(); - - @Nullable - List<String> getOriginalPackages(); - - String getOverlayCategory(); - - int getOverlayPriority(); - - String getOverlayTarget(); - - String getOverlayTargetName(); - - /** - * Map of overlayable name to actor name. - */ - Map<String, String> getOverlayables(); - - // TODO(b/135203078): Does this and getAppInfoPackageName have to be separate methods? - // The refactor makes them the same value with no known consequences, so should be redundant. - String getPackageName(); - - @Nullable - List<ParsedActivity> getActivities(); - - @Nullable - List<ParsedInstrumentation> getInstrumentations(); - - @Nullable - List<ParsedFeature> getFeatures(); - - @Nullable - List<ParsedPermissionGroup> getPermissionGroups(); - - @Nullable - List<ParsedPermission> getPermissions(); - - @Nullable - List<ParsedProvider> getProviders(); - - @Nullable - List<ParsedActivity> getReceivers(); - - @Nullable - List<ParsedService> getServices(); - - String getPermission(); - - @Nullable - List<ParsedActivityIntentInfo> getPreferredActivityFilters(); - - int getPreferredOrder(); - - String getPrimaryCpuAbi(); - - int getPrivateFlags(); - - String getProcessName(); - - @Nullable - List<String> getProtectedBroadcasts(); - - String getPublicSourceDir(); - - List<Intent> getQueriesIntents(); - - List<String> getQueriesPackages(); - - Set<String> getQueriesProviders(); - - String getRealPackage(); - - // TODO(b/135203078): Rename to getRequiredFeatures? Somewhat ambiguous whether "Req" is - // required or requested. - @Nullable - List<FeatureInfo> getReqFeatures(); - - List<String> getRequestedPermissions(); - - String getRequiredAccountType(); - - int getRequiresSmallestWidthDp(); - - byte[] getRestrictUpdateHash(); - - String getRestrictedAccountType(); - - int getRoundIconRes(); - - String getScanPublicSourceDir(); - - String getScanSourceDir(); - - String getSeInfo(); - - String getSeInfoUser(); - - String getSecondaryCpuAbi(); - - String getSecondaryNativeLibraryDir(); - - String getSharedUserId(); - - int getSharedUserLabel(); - - PackageParser.SigningDetails getSigningDetails(); - - String[] getSplitClassLoaderNames(); - - @Nullable - String[] getSplitCodePaths(); - - @Nullable - SparseArray<int[]> getSplitDependencies(); - - int[] getSplitFlags(); - - String[] getSplitNames(); - - String[] getSplitPublicSourceDirs(); - - int[] getSplitRevisionCodes(); - - String getStaticSharedLibName(); - - long getStaticSharedLibVersion(); - - // TODO(b/135203078): Return String directly - UUID getStorageUuid(); - - int getTargetSandboxVersion(); - - int getTargetSdkVersion(); - - String getTaskAffinity(); - - int getTheme(); - - int getUiOptions(); - - int getUid(); - - Set<String> getUpgradeKeySets(); - - @Nullable - List<String> getUsesLibraries(); - - @Nullable - String[] getUsesLibraryFiles(); - - List<SharedLibraryInfo> getUsesLibraryInfos(); - - @Nullable - List<String> getUsesOptionalLibraries(); - - @Nullable - List<String> getUsesStaticLibraries(); - - @Nullable - String[][] getUsesStaticLibrariesCertDigests(); - - @Nullable - long[] getUsesStaticLibrariesVersions(); - - @Nullable - ArrayMap<String, ComponentParseUtils.ParsedProcess> getProcesses(); - - int getVersionCode(); - - int getVersionCodeMajor(); - - String getVersionName(); - - String getVolumeUuid(); - - String getZygotePreloadName(); - - boolean hasComponentClassName(String className); - - boolean hasPreserveLegacyExternalStorage(); - - // App Info - - boolean hasRequestedLegacyExternalStorage(); - - boolean isBaseHardwareAccelerated(); - - boolean isCoreApp(); - - boolean isDefaultToDeviceProtectedStorage(); - - boolean isDirectBootAware(); - - boolean isEmbeddedDexUsed(); - - boolean isEnabled(); - - boolean isCrossProfile(); - - boolean isEncryptionAware(); - - boolean isExternal(); - - boolean isForceQueryable(); - - boolean isForwardLocked(); - - boolean isHiddenUntilInstalled(); - - boolean isInstantApp(); - - boolean isInternal(); - - boolean isLibrary(); - - // TODO(b/135203078): Should probably be in a utility class - boolean isMatch(int flags); - - boolean isNativeLibraryRootRequiresIsa(); - - boolean isOem(); - - boolean isOverlayIsStatic(); - - boolean isPrivileged(); - - boolean isProduct(); - - boolean isProfileableByShell(); - - boolean isRequiredForAllUsers(); - - boolean isStaticSharedLibrary(); - - boolean isStub(); - - boolean isSystem(); // TODO(b/135203078): Collapse with isSystemApp, should be exactly the same. - - boolean isSystemApp(); - - boolean isSystemExt(); - - boolean isUpdatedSystemApp(); - - boolean isUse32BitAbi(); - - boolean isVendor(); - - boolean isVisibleToInstantApps(); - - List<String> makeListAllCodePaths(); // TODO(b/135203078): Collapse with getAllCodePaths - - boolean requestsIsolatedSplitLoading(); - - /** - * Generates an {@link ApplicationInfo} object with only the data available in this object. - * - * This does not contain any system or user state data, and should be avoided. Prefer - * {@link PackageInfoUtils#generateApplicationInfo(AndroidPackage, int, PackageUserState, int)}. - */ - ApplicationInfo toAppInfoWithoutState(); - - Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() { - @Override - public PackageImpl createFromParcel(Parcel source) { - return new PackageImpl(source); - } - - @Override - public PackageImpl[] newArray(int size) { - return new PackageImpl[size]; - } - }; -} diff --git a/core/java/android/content/pm/parsing/AndroidPackageWrite.java b/core/java/android/content/pm/parsing/AndroidPackageWrite.java deleted file mode 100644 index b7595d2dd710..000000000000 --- a/core/java/android/content/pm/parsing/AndroidPackageWrite.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm.parsing; - -import android.annotation.Nullable; -import android.content.pm.PackageParser; -import android.content.pm.SharedLibraryInfo; - -import java.util.List; - -/** - * Contains remaining mutable fields after package parsing has completed. - * - * Most are state that can probably be tracked outside of the AndroidPackage object. New methods - * should never be added to this interface. - * - * TODO(b/135203078): Remove entirely - * - * @deprecated the eventual goal is that the object returned from parsing represents exactly what - * was parsed from the APK, and so further mutation should be disallowed, - * with any state being stored in another class - * - * @hide - */ -@Deprecated -public interface AndroidPackageWrite extends AndroidPackage { - - AndroidPackageWrite setUsesLibraryFiles(@Nullable String[] usesLibraryFiles); - - // TODO(b/135203078): Remove or use a non-system wide representation of the shared libraries; - // this doesn't represent what was parsed from the APK - AndroidPackageWrite setUsesLibraryInfos(@Nullable List<SharedLibraryInfo> usesLibraryInfos); - - AndroidPackageWrite setHiddenUntilInstalled(boolean hidden); - - AndroidPackageWrite setUpdatedSystemApp(boolean updatedSystemApp); - - AndroidPackageWrite setLastPackageUsageTimeInMills(int reason, long time); - - AndroidPackageWrite setPrimaryCpuAbi(String primaryCpuAbi); - - AndroidPackageWrite setSeInfo(String seInfo); - - AndroidPackageWrite setSigningDetails(PackageParser.SigningDetails signingDetails); -} diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 9087f422cef2..4c6da03b4db3 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -50,7 +50,7 @@ import java.util.List; /** @hide */ public class ApkLiteParseUtils { - private static final String TAG = ApkParseUtils.TAG; + private static final String TAG = ParsingPackageUtils.TAG; // TODO(b/135203078): Consolidate constants private static final int DEFAULT_MIN_SDK_VERSION = 1; @@ -235,7 +235,7 @@ public class ApkLiteParseUtils { final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0; Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); try { - signingDetails = ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(), + signingDetails = ParsingPackageUtils.collectCertificates(apkFile.getAbsolutePath(), skipVerify, false, PackageParser.SigningDetails.UNKNOWN, DEFAULT_TARGET_SDK_VERSION); } finally { diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java deleted file mode 100644 index 905794bb24de..000000000000 --- a/core/java/android/content/pm/parsing/ApkParseUtils.java +++ /dev/null @@ -1,3349 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm.parsing; - -import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.content.pm.PackageManager.FEATURE_WATCH; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; -import static android.os.Build.VERSION_CODES.O; -import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; -import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.ActivityTaskManager; -import android.app.ActivityThread; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.ConfigurationInfo; -import android.content.pm.FeatureGroupInfo; -import android.content.pm.FeatureInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageItemInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.PackageParser.SigningDetails; -import android.content.pm.Signature; -import android.content.pm.permission.SplitPermissionInfoParcelable; -import android.content.pm.split.DefaultSplitAssetLoader; -import android.content.pm.split.SplitAssetDependencyLoader; -import android.content.pm.split.SplitAssetLoader; -import android.content.res.ApkAssets; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.FileUtils; -import android.os.RemoteException; -import android.os.SystemProperties; -import android.os.Trace; -import android.os.ext.SdkExtensions; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.Pair; -import android.util.Slog; -import android.util.SparseArray; -import android.util.TypedValue; -import android.util.apk.ApkSignatureVerifier; - -import com.android.internal.R; -import com.android.internal.os.ClassLoaderFactory; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.XmlUtils; - -import libcore.io.IoUtils; -import libcore.util.EmptyArray; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.File; -import java.io.IOException; -import java.security.PublicKey; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - -/** @hide */ -public class ApkParseUtils { - - // TODO(b/135203078): Consolidate log tags - static final String TAG = "PackageParsing"; - - /** - * Parse the package at the given location. Automatically detects if the - * package is a monolithic style (single APK file) or cluster style - * (directory of APKs). - * <p> - * This performs sanity checking on cluster style packages, such as - * requiring identical package name and version codes, a single base APK, - * and unique split names. - * <p> - * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}. - * - * If {@code useCaches} is true, the package parser might return a cached - * result from a previous parse of the same {@code packageFile} with the same - * {@code flags}. Note that this method does not check whether {@code packageFile} - * has changed since the last parse, it's up to callers to do so. - * - * @see PackageParser#parsePackageLite(File, int) - */ - public static ParsingPackage parsePackage( - ParseInput parseInput, - String[] separateProcesses, - PackageParser.Callback callback, - DisplayMetrics displayMetrics, - boolean onlyCoreApps, - File packageFile, - int flags - ) throws PackageParserException { - if (packageFile.isDirectory()) { - return parseClusterPackage(parseInput, separateProcesses, callback, displayMetrics, - onlyCoreApps, packageFile, flags); - } else { - return parseMonolithicPackage(parseInput, separateProcesses, callback, displayMetrics, - onlyCoreApps, packageFile, flags); - } - } - - /** - * Parse all APKs contained in the given directory, treating them as a - * single package. This also performs sanity checking, such as requiring - * identical package name and version codes, a single base APK, and unique - * split names. - * <p> - * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}. - */ - private static ParsingPackage parseClusterPackage( - ParseInput parseInput, - String[] separateProcesses, - PackageParser.Callback callback, - DisplayMetrics displayMetrics, - boolean onlyCoreApps, - File packageDir, - int flags - ) throws PackageParserException { - final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir, - 0); - if (onlyCoreApps && !lite.coreApp) { - throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Not a coreApp: " + packageDir); - } - - // Build the split dependency tree. - SparseArray<int[]> splitDependencies = null; - final SplitAssetLoader assetLoader; - if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) { - try { - splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite); - assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags); - } catch (SplitAssetDependencyLoader.IllegalDependencyException e) { - throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage()); - } - } else { - assetLoader = new DefaultSplitAssetLoader(lite, flags); - } - - try { - final AssetManager assets = assetLoader.getBaseAssetManager(); - final File baseApk = new File(lite.baseCodePath); - ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback, - displayMetrics, baseApk, assets, flags); - if (parsingPackage == null) { - throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, - "Failed to parse base APK: " + baseApk); - } - - if (!ArrayUtils.isEmpty(lite.splitNames)) { - parsingPackage.asSplit( - lite.splitNames, - lite.splitCodePaths, - lite.splitRevisionCodes, - splitDependencies - ); - final int num = lite.splitNames.length; - - for (int i = 0; i < num; i++) { - final AssetManager splitAssets = assetLoader.getSplitAssetManager(i); - parseSplitApk(parseInput, displayMetrics, separateProcesses, parsingPackage, i, - splitAssets, flags); - } - } - - return parsingPackage.setCodePath(lite.codePath) - .setUse32BitAbi(lite.use32bitAbi); - } finally { - IoUtils.closeQuietly(assetLoader); - } - } - - /** - * Parse the given APK file, treating it as as a single monolithic package. - * <p> - * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}. - */ - public static ParsingPackage parseMonolithicPackage( - ParseInput parseInput, - String[] separateProcesses, - PackageParser.Callback callback, - DisplayMetrics displayMetrics, - boolean onlyCoreApps, - File apkFile, - int flags - ) throws PackageParserException { - final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile, - flags); - if (onlyCoreApps) { - if (!lite.coreApp) { - throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Not a coreApp: " + apkFile); - } - } - - final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); - try { - return parseBaseApk(parseInput, separateProcesses, callback, - displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags) - .setCodePath(apkFile.getCanonicalPath()) - .setUse32BitAbi(lite.use32bitAbi); - } catch (IOException e) { - throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Failed to get path: " + apkFile, e); - } finally { - IoUtils.closeQuietly(assetLoader); - } - } - - private static ParsingPackage parseBaseApk( - ParseInput parseInput, - String[] separateProcesses, - PackageParser.Callback callback, - DisplayMetrics displayMetrics, - File apkFile, - AssetManager assets, - int flags - ) throws PackageParserException { - final String apkPath = apkFile.getAbsolutePath(); - - String volumeUuid = null; - if (apkPath.startsWith(PackageParser.MNT_EXPAND)) { - final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length()); - volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end); - } - - if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); - - XmlResourceParser parser = null; - try { - final int cookie = assets.findCookieForPath(apkPath); - if (cookie == 0) { - throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Failed adding asset path: " + apkPath); - } - parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME); - final Resources res = new Resources(assets, displayMetrics, null); - - ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res, - parser, flags); - if (!result.isSuccess()) { - throw new PackageParserException(result.getParseError(), - apkPath + " (at " + parser.getPositionDescription() + "): " - + result.getErrorMessage()); - } - - ParsingPackage pkg = result.getResultAndNull(); - ApkAssets apkAssets = assets.getApkAssets()[0]; - if (apkAssets.definesOverlayable()) { - SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers(); - int size = packageNames.size(); - for (int index = 0; index < size; index++) { - String packageName = packageNames.get(index); - Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName); - if (overlayableToActor != null && !overlayableToActor.isEmpty()) { - for (String overlayable : overlayableToActor.keySet()) { - pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable)); - } - } - } - } - - return pkg.setVolumeUuid(volumeUuid) - .setApplicationVolumeUuid(volumeUuid) - .setSigningDetails(SigningDetails.UNKNOWN); - } catch (PackageParserException e) { - throw e; - } catch (Exception e) { - throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Failed to read manifest from " + apkPath, e); - } finally { - IoUtils.closeQuietly(parser); - } - } - - private static void parseSplitApk( - ParseInput parseInput, - DisplayMetrics displayMetrics, - String[] separateProcesses, - ParsingPackage parsingPackage, - int splitIndex, - AssetManager assets, - int flags - ) throws PackageParserException { - final String apkPath = parsingPackage.getSplitCodePaths()[splitIndex]; - - if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); - - final Resources res; - XmlResourceParser parser = null; - try { - // This must always succeed, as the path has been added to the AssetManager before. - final int cookie = assets.findCookieForPath(apkPath); - if (cookie == 0) { - throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Failed adding asset path: " + apkPath); - } - - parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME); - res = new Resources(assets, displayMetrics, null); - - final String[] outError = new String[1]; - ParseResult parseResult = parseSplitApk(parseInput, separateProcesses, parsingPackage, - res, parser, flags, splitIndex, outError); - if (!parseResult.isSuccess()) { - throw new PackageParserException(parseResult.getParseError(), - apkPath + " (at " + parser.getPositionDescription() + "): " - + parseResult.getErrorMessage()); - } - } catch (PackageParserException e) { - throw e; - } catch (Exception e) { - throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Failed to read manifest from " + apkPath, e); - } finally { - IoUtils.closeQuietly(parser); - } - } - - /** - * Parse the manifest of a <em>base APK</em>. When adding new features you - * need to consider whether they should be supported by split APKs and child - * packages. - * - * @param apkPath The package apk file path - * @param res The resources from which to resolve values - * @param parser The manifest parser - * @param flags Flags how to parse - * @return Parsed package or null on error. - */ - private static ParseResult parseBaseApk( - ParseInput parseInput, - String[] separateProcesses, - PackageParser.Callback callback, - String apkPath, - Resources res, - XmlResourceParser parser, - int flags - ) throws XmlPullParserException, IOException { - final String splitName; - final String pkgName; - - try { - Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser, - parser); - pkgName = packageSplit.first; - splitName = packageSplit.second; - - if (!TextUtils.isEmpty(splitName)) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, - "Expected base APK, but found split " + splitName - ); - } - } catch (PackageParserException e) { - return parseInput.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME); - } - - TypedArray manifestArray = null; - - try { - manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest); - - boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false); - - ParsingPackage parsingPackage = PackageImpl.forParsing( - pkgName, - apkPath, - manifestArray, - isCoreApp - ); - - ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback, - parsingPackage, manifestArray, res, parser, flags); - if (!result.isSuccess()) { - return result; - } - - return parseInput.success(parsingPackage); - } finally { - if (manifestArray != null) { - manifestArray.recycle(); - } - } - } - - /** - * Parse the manifest of a <em>split APK</em>. - * <p> - * Note that split APKs have many more restrictions on what they're capable - * of doing, so many valid features of a base APK have been carefully - * omitted here. - * - * @param parsingPackage builder to fill - * @return false on failure - */ - private static ParseResult parseSplitApk( - ParseInput parseInput, - String[] separateProcesses, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - int flags, - int splitIndex, - String[] outError - ) throws XmlPullParserException, IOException, PackageParserException { - AttributeSet attrs = parser; - - // We parsed manifest tag earlier; just skip past it - PackageParser.parsePackageSplitNames(parser, attrs); - - int type; - - boolean foundApp = false; - - int outerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals(PackageParser.TAG_APPLICATION)) { - if (foundApp) { - if (PackageParser.RIGID_PARSER) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "<manifest> has more than one <application>" - ); - } else { - Slog.w(TAG, "<manifest> has more than one <application>"); - XmlUtils.skipCurrentTag(parser); - continue; - } - } - - foundApp = true; - ParseResult parseResult = parseSplitApplication(parseInput, separateProcesses, - parsingPackage, res, - parser, flags, - splitIndex, outError); - if (!parseResult.isSuccess()) { - return parseResult; - } - - } else if (PackageParser.RIGID_PARSER) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Bad element under <manifest>: " + parser.getName() - ); - - } else { - Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - } - - if (!foundApp) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY, - "<manifest> does not contain an <application>" - ); - } - - return parseInput.success(parsingPackage); - } - - /** - * Parse the {@code application} XML tree at the current parse location in a - * <em>split APK</em> manifest. - * <p> - * Note that split APKs have many more restrictions on what they're capable - * of doing, so many valid features of a base APK have been carefully - * omitted here. - */ - private static ParseResult parseSplitApplication( - ParseInput parseInput, - String[] separateProcesses, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - int flags, - int splitIndex, - String[] outError - ) throws XmlPullParserException, IOException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); - - parsingPackage.setSplitHasCode(splitIndex, sa.getBoolean( - R.styleable.AndroidManifestApplication_hasCode, true)); - - final String classLoaderName = sa.getString( - R.styleable.AndroidManifestApplication_classLoader); - if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { - parsingPackage.setSplitClassLoaderName(splitIndex, classLoaderName); - } else { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Invalid class loader name: " + classLoaderName - ); - } - - final int innerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - ComponentParseUtils.ParsedComponent parsedComponent = null; - - String tagName = parser.getName(); - switch (tagName) { - case "activity": - ComponentParseUtils.ParsedActivity activity = - ComponentParseUtils.parseActivity(separateProcesses, - parsingPackage, - res, parser, flags, - outError, - false, - parsingPackage.isBaseHardwareAccelerated()); - if (activity == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addActivity(activity); - parsedComponent = activity; - break; - case "receiver": - activity = ComponentParseUtils.parseActivity( - separateProcesses, parsingPackage, - res, parser, flags, outError, - true, false); - if (activity == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addReceiver(activity); - parsedComponent = activity; - break; - case "service": - ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService( - separateProcesses, - parsingPackage, - res, parser, flags, outError - ); - if (s == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addService(s); - parsedComponent = s; - break; - case "provider": - ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider( - separateProcesses, - parsingPackage, - res, parser, flags, outError); - if (p == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addProvider(p); - parsedComponent = p; - break; - case "activity-alias": - activity = ComponentParseUtils.parseActivityAlias( - parsingPackage, - res, - parser, - outError - ); - if (activity == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addActivity(activity); - parsedComponent = activity; - break; - case "meta-data": - // note: application meta-data is stored off to the side, so it can - // remain null in the primary copy (we like to avoid extra copies because - // it can be large) - Bundle appMetaData = parseMetaData(parsingPackage, res, parser, - parsingPackage.getAppMetaData(), - outError); - if (appMetaData == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.setAppMetaData(appMetaData); - break; - case "uses-static-library": - ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage, - res, parser); - if (!parseResult.isSuccess()) { - return parseResult; - } - - break; - case "uses-library": - sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary); - - // Note: don't allow this value to be a reference to a resource - // that may change. - String lname = sa.getNonResourceString( - R.styleable.AndroidManifestUsesLibrary_name); - boolean req = sa.getBoolean( - R.styleable.AndroidManifestUsesLibrary_required, true); - - sa.recycle(); - - if (lname != null) { - lname = lname.intern(); - if (req) { - // Upgrade to treat as stronger constraint - parsingPackage.addUsesLibrary(lname) - .removeUsesOptionalLibrary(lname); - } else { - // Ignore if someone already defined as required - if (!ArrayUtils.contains(parsingPackage.getUsesLibraries(), lname)) { - parsingPackage.addUsesOptionalLibrary(lname); - } - } - } - - XmlUtils.skipCurrentTag(parser); - break; - case "uses-package": - // Dependencies for app installers; we don't currently try to - // enforce this. - XmlUtils.skipCurrentTag(parser); - break; - default: - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "Unknown element under <application>: " + tagName - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } else { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Bad element under <application>: " + tagName - ); - } - } - - if (parsedComponent != null && parsedComponent.getSplitName() == null) { - // If the loaded component did not specify a split, inherit the split name - // based on the split it is defined in. - // This is used to later load the correct split when starting this - // component. - parsedComponent.setSplitName(parsingPackage.getSplitNames()[splitIndex]); - } - } - - return parseInput.success(parsingPackage); - } - - private static ParseResult parseBaseApkTags( - ParseInput parseInput, - String[] separateProcesses, - PackageParser.Callback callback, - ParsingPackage parsingPackage, - TypedArray manifestArray, - Resources res, - XmlResourceParser parser, - int flags - ) throws XmlPullParserException, IOException { - int type; - boolean foundApp = false; - - TypedArray sa = manifestArray; - - ParseResult sharedUserResult = parseSharedUser(parseInput, parsingPackage, sa); - if (!sharedUserResult.isSuccess()) { - return sharedUserResult; - } - - parseManifestAttributes(sa, parsingPackage, flags); - - int outerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - - // All methods return a boolean, even if they can't fail. This can be enforced - // by making this final and not assigned, forcing the switch to assign success - // once in every branch. - final boolean success; - ParseResult parseResult = null; - - // TODO(b/135203078): Either use all booleans or all ParseResults - // TODO(b/135203078): Convert to instance methods to share variables - switch (tagName) { - case PackageParser.TAG_APPLICATION: - if (foundApp) { - if (PackageParser.RIGID_PARSER) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "<manifest> has more than one <application>" - ); - } else { - Slog.w(TAG, "<manifest> has more than one <application>"); - XmlUtils.skipCurrentTag(parser); - success = true; - } - } else { - foundApp = true; - parseResult = parseBaseApplication(parseInput, separateProcesses, - callback, - parsingPackage, res, parser, flags); - success = parseResult.isSuccess(); - } - break; - case PackageParser.TAG_OVERLAY: - parseResult = parseOverlay(parseInput, parsingPackage, res, parser); - success = parseResult.isSuccess(); - break; - case PackageParser.TAG_KEY_SETS: - parseResult = parseKeySets(parseInput, parsingPackage, res, parser); - success = parseResult.isSuccess(); - break; - case PackageParser.TAG_FEATURE: - parseResult = parseFeature(parseInput, parsingPackage, res, parser); - success = parseResult.isSuccess(); - break; - case PackageParser.TAG_PERMISSION_GROUP: - parseResult = parsePermissionGroup(parseInput, parsingPackage, res, - parser); - success = parseResult.isSuccess(); - break; - case PackageParser.TAG_PERMISSION: - parseResult = parsePermission(parseInput, parsingPackage, res, parser); - success = parseResult.isSuccess(); - break; - case PackageParser.TAG_PERMISSION_TREE: - parseResult = parsePermissionTree(parseInput, parsingPackage, res, parser); - success = parseResult.isSuccess(); - break; - case PackageParser.TAG_USES_PERMISSION: - case PackageParser.TAG_USES_PERMISSION_SDK_M: - case PackageParser.TAG_USES_PERMISSION_SDK_23: - parseResult = parseUsesPermission(parseInput, parsingPackage, res, parser, - callback); - success = parseResult.isSuccess(); - break; - case PackageParser.TAG_USES_CONFIGURATION: - success = parseUsesConfiguration(parsingPackage, res, parser); - break; - case PackageParser.TAG_USES_FEATURE: - success = parseUsesFeature(parsingPackage, res, parser); - break; - case PackageParser.TAG_FEATURE_GROUP: - success = parseFeatureGroup(parsingPackage, res, parser); - break; - case PackageParser.TAG_USES_SDK: - parseResult = parseUsesSdk(parseInput, parsingPackage, res, parser); - success = parseResult.isSuccess(); - break; - case PackageParser.TAG_SUPPORT_SCREENS: - success = parseSupportScreens(parsingPackage, res, parser); - break; - case PackageParser.TAG_PROTECTED_BROADCAST: - success = parseProtectedBroadcast(parsingPackage, res, parser); - break; - case PackageParser.TAG_INSTRUMENTATION: - parseResult = parseInstrumentation(parseInput, parsingPackage, res, - parser); - success = parseResult.isSuccess(); - break; - case PackageParser.TAG_ORIGINAL_PACKAGE: - success = parseOriginalPackage(parsingPackage, res, parser); - break; - case PackageParser.TAG_ADOPT_PERMISSIONS: - success = parseAdoptPermissions(parsingPackage, res, parser); - break; - case PackageParser.TAG_USES_GL_TEXTURE: - case PackageParser.TAG_COMPATIBLE_SCREENS: - case PackageParser.TAG_SUPPORTS_INPUT: - case PackageParser.TAG_EAT_COMMENT: - // Just skip this tag - XmlUtils.skipCurrentTag(parser); - success = true; - break; - case PackageParser.TAG_RESTRICT_UPDATE: - success = parseRestrictUpdateHash(flags, parsingPackage, res, parser); - break; - case PackageParser.TAG_QUERIES: - parseResult = parseQueries(parseInput, parsingPackage, res, parser); - success = parseResult.isSuccess(); - break; - default: - parseResult = parseUnknownTag(parseInput, parsingPackage, parser); - success = parseResult.isSuccess(); - break; - } - - if (parseResult != null && !parseResult.isSuccess()) { - return parseResult; - } - - if (!success) { - return parseResult; - } - } - - if (!foundApp && ArrayUtils.size(parsingPackage.getInstrumentations()) == 0) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY, - "<manifest> does not contain an <application> or <instrumentation>" - ); - } - - if (!ComponentParseUtils.ParsedFeature.isCombinationValid(parsingPackage.getFeatures())) { - return parseInput.error( - INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Combination <feature> tags are not valid" - ); - } - - convertNewPermissions(parsingPackage); - - convertSplitPermissions(parsingPackage); - - // At this point we can check if an application is not supporting densities and hence - // cannot be windowed / resized. Note that an SDK version of 0 is common for - // pre-Doughnut applications. - if (parsingPackage.usesCompatibilityMode()) { - adjustPackageToBeUnresizeableAndUnpipable(parsingPackage); - } - - return parseInput.success(parsingPackage); - } - - private static ParseResult parseUnknownTag( - ParseInput parseInput, - ParsingPackage parsingPackage, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - if (PackageParser.RIGID_PARSER) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Bad element under <manifest>: " + parser.getName() - ); - } else { - Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - return parseInput.success(parsingPackage); - } - } - - private static ParseResult parseSharedUser( - ParseInput parseInput, - ParsingPackage parsingPackage, - TypedArray manifestArray - ) { - String str = manifestArray.getNonConfigurationString( - R.styleable.AndroidManifest_sharedUserId, 0); - if (TextUtils.isEmpty(str)) { - return parseInput.success(parsingPackage); - } - - String nameError = validateName(str, true, true); - if (nameError != null && !"android".equals(parsingPackage.getPackageName())) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, - "<manifest> specifies bad sharedUserId name \"" + str + "\": " - + nameError - ); - } - - int sharedUserLabel = manifestArray.getResourceId( - R.styleable.AndroidManifest_sharedUserLabel, 0); - parsingPackage.setSharedUserId(str.intern()) - .setSharedUserLabel(sharedUserLabel); - - return parseInput.success(parsingPackage); - } - - private static void parseManifestAttributes( - TypedArray manifestArray, - ParsingPackage parsingPackage, - int flags - ) { - int installLocation = manifestArray.getInteger(R.styleable.AndroidManifest_installLocation, - PackageParser.PARSE_DEFAULT_INSTALL_LOCATION); - - final int targetSandboxVersion = manifestArray.getInteger( - R.styleable.AndroidManifest_targetSandboxVersion, - PackageParser.PARSE_DEFAULT_TARGET_SANDBOX); - - parsingPackage.setInstallLocation(installLocation) - .setTargetSandboxVersion(targetSandboxVersion); - - /* Set the global "on SD card" flag */ - parsingPackage.setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0); - - parsingPackage.setIsolatedSplitLoading(manifestArray.getBoolean( - R.styleable.AndroidManifest_isolatedSplits, false)); - } - - private static ParseResult parseKeySets( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws XmlPullParserException, IOException { - // we've encountered the 'key-sets' tag - // all the keys and keysets that we want must be defined here - // so we're going to iterate over the parser and pull out the things we want - int outerDepth = parser.getDepth(); - int currentKeySetDepth = -1; - int type; - String currentKeySet = null; - ArrayMap<String, PublicKey> publicKeys = new ArrayMap<>(); - ArraySet<String> upgradeKeySets = new ArraySet<>(); - ArrayMap<String, ArraySet<String>> definedKeySets = - new ArrayMap<>(); - ArraySet<String> improperKeySets = new ArraySet<>(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG) { - if (parser.getDepth() == currentKeySetDepth) { - currentKeySet = null; - currentKeySetDepth = -1; - } - continue; - } - String tagName = parser.getName(); - if (tagName.equals("key-set")) { - if (currentKeySet != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Improperly nested 'key-set' tag at " + parser.getPositionDescription() - ); - } - final TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestKeySet); - final String keysetName = sa.getNonResourceString( - R.styleable.AndroidManifestKeySet_name); - definedKeySets.put(keysetName, new ArraySet<>()); - currentKeySet = keysetName; - currentKeySetDepth = parser.getDepth(); - sa.recycle(); - } else if (tagName.equals("public-key")) { - if (currentKeySet == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Improperly nested 'key-set' tag at " + parser.getPositionDescription() - ); - } - final TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestPublicKey); - final String publicKeyName = sa.getNonResourceString( - R.styleable.AndroidManifestPublicKey_name); - final String encodedKey = sa.getNonResourceString( - R.styleable.AndroidManifestPublicKey_value); - if (encodedKey == null && publicKeys.get(publicKeyName) == null) { - sa.recycle(); - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "'public-key' " + publicKeyName + " must define a public-key value" - + " on first use at " + parser.getPositionDescription() - ); - } else if (encodedKey != null) { - PublicKey currentKey = PackageParser.parsePublicKey(encodedKey); - if (currentKey == null) { - Slog.w(TAG, "No recognized valid key in 'public-key' tag at " - + parser.getPositionDescription() + " key-set " + currentKeySet - + " will not be added to the package's defined key-sets."); - sa.recycle(); - improperKeySets.add(currentKeySet); - XmlUtils.skipCurrentTag(parser); - continue; - } - if (publicKeys.get(publicKeyName) == null - || publicKeys.get(publicKeyName).equals(currentKey)) { - - /* public-key first definition, or matches old definition */ - publicKeys.put(publicKeyName, currentKey); - } else { - sa.recycle(); - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Value of 'public-key' " + publicKeyName - + " conflicts with previously defined value at " - + parser.getPositionDescription() - ); - } - } - definedKeySets.get(currentKeySet).add(publicKeyName); - sa.recycle(); - XmlUtils.skipCurrentTag(parser); - } else if (tagName.equals("upgrade-key-set")) { - final TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestUpgradeKeySet); - String name = sa.getNonResourceString( - R.styleable.AndroidManifestUpgradeKeySet_name); - upgradeKeySets.add(name); - sa.recycle(); - XmlUtils.skipCurrentTag(parser); - } else if (PackageParser.RIGID_PARSER) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Bad element under <key-sets>: " + parser.getName() - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription() - ); - } else { - Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName() - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - } - String packageName = parsingPackage.getPackageName(); - Set<String> publicKeyNames = publicKeys.keySet(); - if (publicKeyNames.removeAll(definedKeySets.keySet())) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Package" + packageName + " AndroidManifest.xml " - + "'key-set' and 'public-key' names must be distinct." - ); - } - - for (ArrayMap.Entry<String, ArraySet<String>> e : definedKeySets.entrySet()) { - final String keySetName = e.getKey(); - if (e.getValue().size() == 0) { - Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " - + "'key-set' " + keySetName + " has no valid associated 'public-key'." - + " Not including in package's defined key-sets."); - continue; - } else if (improperKeySets.contains(keySetName)) { - Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " - + "'key-set' " + keySetName + " contained improper 'public-key'" - + " tags. Not including in package's defined key-sets."); - continue; - } - - for (String s : e.getValue()) { - parsingPackage.addKeySet(keySetName, publicKeys.get(s)); - } - } - if (parsingPackage.getKeySetMapping().keySet().containsAll(upgradeKeySets)) { - parsingPackage.setUpgradeKeySets(upgradeKeySets); - } else { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Package" + packageName + " AndroidManifest.xml " - + "does not define all 'upgrade-key-set's ." - ); - } - - return parseInput.success(parsingPackage); - } - - public static boolean parsePackageItemInfo(String packageName, PackageItemInfo outInfo, - String[] outError, String tag, TypedArray sa, boolean nameRequired, - int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) { - // This case can only happen in unit tests where we sometimes need to create fakes - // of various package parser data structures. - if (sa == null) { - outError[0] = tag + " does not contain any attributes"; - return false; - } - - String name = sa.getNonConfigurationString(nameRes, 0); - if (name == null) { - if (nameRequired) { - outError[0] = tag + " does not specify android:name"; - return false; - } - } else { - String outInfoName = buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) { - outError[0] = tag + " invalid android:name"; - return false; - } - outInfo.name = outInfoName; - if (outInfoName == null) { - return false; - } - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; - if (roundIconVal != 0) { - outInfo.icon = roundIconVal; - outInfo.nonLocalizedLabel = null; - } else { - int iconVal = sa.getResourceId(iconRes, 0); - if (iconVal != 0) { - outInfo.icon = iconVal; - outInfo.nonLocalizedLabel = null; - } - } - - int logoVal = sa.getResourceId(logoRes, 0); - if (logoVal != 0) { - outInfo.logo = logoVal; - } - - int bannerVal = sa.getResourceId(bannerRes, 0); - if (bannerVal != 0) { - outInfo.banner = bannerVal; - } - - TypedValue v = sa.peekValue(labelRes); - if (v != null && (outInfo.labelRes = v.resourceId) == 0) { - outInfo.nonLocalizedLabel = v.coerceToString(); - } - - outInfo.packageName = packageName; - - return true; - } - - private static ParseResult parsePackageItemInfo( - ParseInput parseInput, - ParsingPackage parsingPackage, - String tag, - TypedArray sa, - boolean nameRequired, - int nameRes, - int labelRes, - int iconRes, - int roundIconRes, - int logoRes, - int bannerRes - ) { - // This case can only happen in unit tests where we sometimes need to create fakes - // of various package parser data structures. - if (sa == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - tag + " does not contain any attributes" - ); - } - - String name = sa.getNonConfigurationString(nameRes, 0); - if (name == null) { - if (nameRequired) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - tag + " does not specify android:name" - ); - } - } else { - String packageName = parsingPackage.getPackageName(); - String outInfoName = buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - tag + " invalid android:name" - ); - } else if (outInfoName == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Empty class name in package " + packageName - ); - } - - parsingPackage.setName(outInfoName); - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; - if (roundIconVal != 0) { - parsingPackage.setIcon(roundIconVal) - .setNonLocalizedLabel(null); - } else { - int iconVal = sa.getResourceId(iconRes, 0); - if (iconVal != 0) { - parsingPackage.setIcon(iconVal) - .setNonLocalizedLabel(null); - } - } - - int logoVal = sa.getResourceId(logoRes, 0); - if (logoVal != 0) { - parsingPackage.setLogo(logoVal); - } - - int bannerVal = sa.getResourceId(bannerRes, 0); - if (bannerVal != 0) { - parsingPackage.setBanner(bannerVal); - } - - TypedValue v = sa.peekValue(labelRes); - if (v != null) { - parsingPackage.setLabelRes(v.resourceId); - if (v.resourceId == 0) { - parsingPackage.setNonLocalizedLabel(v.coerceToString()); - } - } - - return parseInput.success(parsingPackage); - } - - private static ParseResult parseFeature( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - // TODO(b/135203078): Remove, replace with ParseResult - String[] outError = new String[1]; - - ComponentParseUtils.ParsedFeature parsedFeature = - ComponentParseUtils.parseFeature(res, parser, outError); - - if (parsedFeature == null || outError[0] != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addFeature(parsedFeature); - - return parseInput.success(parsingPackage); - } - - - private static ParseResult parsePermissionGroup( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws XmlPullParserException, IOException { - // TODO(b/135203078): Remove, replace with ParseResult - String[] outError = new String[1]; - - ComponentParseUtils.ParsedPermissionGroup parsedPermissionGroup = - ComponentParseUtils.parsePermissionGroup(parsingPackage, - res, parser, outError); - - if (parsedPermissionGroup == null || outError[0] != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addPermissionGroup(parsedPermissionGroup); - - return parseInput.success(parsingPackage); - } - - private static ParseResult parsePermission( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws XmlPullParserException, IOException { - // TODO(b/135203078): Remove, replace with ParseResult - String[] outError = new String[1]; - - ComponentParseUtils.ParsedPermission parsedPermission = - ComponentParseUtils.parsePermission(parsingPackage, - res, parser, outError); - - if (parsedPermission == null || outError[0] != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addPermission(parsedPermission); - - return parseInput.success(parsingPackage); - } - - private static ParseResult parsePermissionTree( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws XmlPullParserException, IOException { - // TODO(b/135203078): Remove, replace with ParseResult - String[] outError = new String[1]; - - ComponentParseUtils.ParsedPermission parsedPermission = - ComponentParseUtils.parsePermissionTree(parsingPackage, - res, parser, outError); - - if (parsedPermission == null || outError[0] != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addPermission(parsedPermission); - - return parseInput.success(parsingPackage); - } - - private static ParseResult parseUsesPermission( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - PackageParser.Callback callback - ) - throws XmlPullParserException, IOException { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestUsesPermission); - - // Note: don't allow this value to be a reference to a resource - // that may change. - String name = sa.getNonResourceString( - R.styleable.AndroidManifestUsesPermission_name); - - int maxSdkVersion = 0; - TypedValue val = sa.peekValue( - R.styleable.AndroidManifestUsesPermission_maxSdkVersion); - if (val != null) { - if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) { - maxSdkVersion = val.data; - } - } - - final String requiredFeature = sa.getNonConfigurationString( - R.styleable.AndroidManifestUsesPermission_requiredFeature, 0); - - final String requiredNotfeature = sa.getNonConfigurationString( - R.styleable.AndroidManifestUsesPermission_requiredNotFeature, - 0); - - sa.recycle(); - - XmlUtils.skipCurrentTag(parser); - - // Can only succeed from here on out - ParseResult success = parseInput.success(parsingPackage); - - if (name == null) { - return success; - } - - if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) { - return success; - } - - // Only allow requesting this permission if the platform supports the given feature. - if (requiredFeature != null && callback != null && !callback.hasFeature(requiredFeature)) { - return success; - } - - // Only allow requesting this permission if the platform doesn't support the given feature. - if (requiredNotfeature != null && callback != null - && callback.hasFeature(requiredNotfeature)) { - return success; - } - - if (!parsingPackage.getRequestedPermissions().contains(name)) { - parsingPackage.addRequestedPermission(name.intern()); - } else { - Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: " - + name + " in package: " + parsingPackage.getPackageName() + " at: " - + parser.getPositionDescription()); - } - - return success; - } - - private static boolean parseUsesConfiguration( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - ConfigurationInfo cPref = new ConfigurationInfo(); - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestUsesConfiguration); - cPref.reqTouchScreen = sa.getInt( - R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, - Configuration.TOUCHSCREEN_UNDEFINED); - cPref.reqKeyboardType = sa.getInt( - R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, - Configuration.KEYBOARD_UNDEFINED); - if (sa.getBoolean( - R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, - false)) { - cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; - } - cPref.reqNavigation = sa.getInt( - R.styleable.AndroidManifestUsesConfiguration_reqNavigation, - Configuration.NAVIGATION_UNDEFINED); - if (sa.getBoolean( - R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, - false)) { - cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; - } - sa.recycle(); - parsingPackage.addConfigPreference(cPref); - - XmlUtils.skipCurrentTag(parser); - return true; - } - - private static boolean parseUsesFeature( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - FeatureInfo fi = parseFeatureInfo(res, parser); - parsingPackage.addReqFeature(fi); - - if (fi.name == null) { - ConfigurationInfo cPref = new ConfigurationInfo(); - cPref.reqGlEsVersion = fi.reqGlEsVersion; - parsingPackage.addConfigPreference(cPref); - } - - XmlUtils.skipCurrentTag(parser); - return true; - } - - private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) { - FeatureInfo fi = new FeatureInfo(); - TypedArray sa = res.obtainAttributes(attrs, - R.styleable.AndroidManifestUsesFeature); - // Note: don't allow this value to be a reference to a resource - // that may change. - fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name); - fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0); - if (fi.name == null) { - fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion, - FeatureInfo.GL_ES_VERSION_UNDEFINED); - } - if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) { - fi.flags |= FeatureInfo.FLAG_REQUIRED; - } - sa.recycle(); - return fi; - } - - private static boolean parseFeatureGroup( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - FeatureGroupInfo group = new FeatureGroupInfo(); - ArrayList<FeatureInfo> features = null; - final int innerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - final String innerTagName = parser.getName(); - if (innerTagName.equals("uses-feature")) { - FeatureInfo featureInfo = parseFeatureInfo(res, parser); - // FeatureGroups are stricter and mandate that - // any <uses-feature> declared are mandatory. - featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; - features = ArrayUtils.add(features, featureInfo); - } else { - Slog.w(TAG, - "Unknown element under <feature-group>: " + innerTagName + - " at " + parsingPackage.getBaseCodePath() + " " + - parser.getPositionDescription()); - } - XmlUtils.skipCurrentTag(parser); - } - - if (features != null) { - group.features = new FeatureInfo[features.size()]; - group.features = features.toArray(group.features); - } - - parsingPackage.addFeatureGroup(group); - return true; - } - - private static ParseResult parseUsesSdk( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - if (PackageParser.SDK_VERSION > 0) { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestUsesSdk); - - int minVers = 1; - String minCode = null; - int targetVers = 0; - String targetCode = null; - - TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion); - if (val != null) { - if (val.type == TypedValue.TYPE_STRING && val.string != null) { - minCode = val.string.toString(); - } else { - // If it's not a string, it's an integer. - minVers = val.data; - } - } - - val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion); - if (val != null) { - if (val.type == TypedValue.TYPE_STRING && val.string != null) { - targetCode = val.string.toString(); - if (minCode == null) { - minCode = targetCode; - } - } else { - // If it's not a string, it's an integer. - targetVers = val.data; - } - } else { - targetVers = minVers; - targetCode = minCode; - } - - sa.recycle(); - - // TODO(b/135203078): Remove, replace with ParseResult - String[] outError = new String[1]; - final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, - minCode, - PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, outError); - if (minSdkVersion < 0) { - return parseInput.error( - PackageManager.INSTALL_FAILED_OLDER_SDK - ); - } - - final int targetSdkVersion = PackageParser.computeTargetSdkVersion( - targetVers, - targetCode, PackageParser.SDK_CODENAMES, outError); - if (targetSdkVersion < 0) { - return parseInput.error( - PackageManager.INSTALL_FAILED_OLDER_SDK - ); - } - - int type; - final int innerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - if (parser.getName().equals("extension-sdk")) { - final ParseResult result = - parseExtensionSdk(parseInput, parsingPackage, res, parser); - if (!result.isSuccess()) { - return result; - } - } else { - Slog.w(TAG, "Unknown element under <uses-sdk>: " + parser.getName() - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - } - XmlUtils.skipCurrentTag(parser); - } - - parsingPackage.setMinSdkVersion(minSdkVersion) - .setTargetSdkVersion(targetSdkVersion); - } - return parseInput.success(parsingPackage); - } - - private static ParseResult parseExtensionSdk( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, - com.android.internal.R.styleable.AndroidManifestExtensionSdk); - int sdkVersion = sa.getInt( - com.android.internal.R.styleable.AndroidManifestExtensionSdk_sdkVersion, -1); - int minVersion = sa.getInt( - com.android.internal.R.styleable.AndroidManifestExtensionSdk_minExtensionVersion, - -1); - sa.recycle(); - - if (sdkVersion < 0) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "<extension-sdk> must specify an sdkVersion >= 0"); - } - if (minVersion < 0) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "<extension-sdk> must specify minExtensionVersion >= 0"); - } - - try { - int version = SdkExtensions.getExtensionVersion(sdkVersion); - if (version < minVersion) { - return parseInput.error( - PackageManager.INSTALL_FAILED_OLDER_SDK, - "Package requires " + sdkVersion + " extension version " + minVersion - + " which exceeds device version " + version); - } - } catch (RuntimeException e) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Specified sdkVersion " + sdkVersion + " is not valid"); - } - return parseInput.success(parsingPackage); - } - - private static boolean parseRestrictUpdateHash( - int flags, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestRestrictUpdate); - final String hash = sa.getNonConfigurationString( - R.styleable.AndroidManifestRestrictUpdate_hash, - 0); - sa.recycle(); - - if (hash != null) { - final int hashLength = hash.length(); - final byte[] hashBytes = new byte[hashLength / 2]; - for (int i = 0; i < hashLength; i += 2) { - hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16) - << 4) - + Character.digit(hash.charAt(i + 1), 16)); - } - parsingPackage.setRestrictUpdateHash(hashBytes); - } else { - parsingPackage.setRestrictUpdateHash(null); - } - } - - XmlUtils.skipCurrentTag(parser); - return true; - } - - private static ParseResult parseQueries( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - - final int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - if (parser.getName().equals("intent")) { - String[] outError = new String[1]; - ComponentParseUtils.ParsedQueriesIntentInfo intentInfo = - ComponentParseUtils.parsedParsedQueriesIntentInfo( - parsingPackage, res, parser, outError - ); - if (intentInfo == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - Uri data = null; - String dataType = null; - String host = ""; - final int numActions = intentInfo.countActions(); - final int numSchemes = intentInfo.countDataSchemes(); - final int numTypes = intentInfo.countDataTypes(); - final int numHosts = intentInfo.getHosts().length; - if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) { - outError[0] = "intent tags must contain either an action or data."; - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - if (numActions > 1) { - outError[0] = "intent tag may have at most one action."; - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - if (numTypes > 1) { - outError[0] = "intent tag may have at most one data type."; - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - if (numSchemes > 1) { - outError[0] = "intent tag may have at most one data scheme."; - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - if (numHosts > 1) { - outError[0] = "intent tag may have at most one data host."; - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - Intent intent = new Intent(); - for (int i = 0, max = intentInfo.countCategories(); i < max; i++) { - intent.addCategory(intentInfo.getCategory(i)); - } - if (numHosts == 1) { - host = intentInfo.getHosts()[0]; - } - if (numSchemes == 1) { - data = new Uri.Builder() - .scheme(intentInfo.getDataScheme(0)) - .authority(host) - .build(); - } - if (numTypes == 1) { - dataType = intentInfo.getDataType(0); - } - intent.setDataAndType(data, dataType); - if (numActions == 1) { - intent.setAction(intentInfo.getAction(0)); - } - parsingPackage.addQueriesIntent(intent); - } else if (parser.getName().equals("package")) { - final TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestQueriesPackage); - final String packageName = - sa.getString(R.styleable.AndroidManifestQueriesPackage_name); - if (TextUtils.isEmpty(packageName)) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Package name is missing from package tag." - ); - } - parsingPackage.addQueriesPackage(packageName.intern()); - } else if (parser.getName().equals("provider")) { - final TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestQueriesProvider); - try { - final String authorities = - sa.getString(R.styleable.AndroidManifestQueriesProvider_authorities); - if (TextUtils.isEmpty(authorities)) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Authority missing from provider tag." - ); - } - StringTokenizer authoritiesTokenizer = new StringTokenizer(authorities, ";"); - while (authoritiesTokenizer.hasMoreElements()) { - parsingPackage.addQueriesProvider(authoritiesTokenizer.nextToken()); - } - } finally { - sa.recycle(); - } - } - } - return parseInput.success(parsingPackage); - } - - /** - * Parse the {@code application} XML tree at the current parse location in a - * <em>base APK</em> manifest. - * <p> - * When adding new features, carefully consider if they should also be - * supported by split APKs. - * - * @hide - */ - public static ParseResult parseBaseApplication( - ParseInput parseInput, - String[] separateProcesses, - PackageParser.Callback callback, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - int flags - ) throws XmlPullParserException, IOException { - final String pkgName = parsingPackage.getPackageName(); - - // TODO(b/135203078): Remove, replace with ParseResult - String[] outError = new String[1]; - TypedArray sa = null; - - try { - sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestApplication); - - - parsingPackage - .setIconRes( - sa.getResourceId(R.styleable.AndroidManifestApplication_icon, 0)) - .setRoundIconRes( - sa.getResourceId(R.styleable.AndroidManifestApplication_roundIcon, 0)); - - ParseResult result = parsePackageItemInfo( - parseInput, - parsingPackage, - "<application>", - sa, false /*nameRequired*/, - R.styleable.AndroidManifestApplication_name, - R.styleable.AndroidManifestApplication_label, - R.styleable.AndroidManifestApplication_icon, - R.styleable.AndroidManifestApplication_roundIcon, - R.styleable.AndroidManifestApplication_logo, - R.styleable.AndroidManifestApplication_banner - ); - if (!result.isSuccess()) { - return result; - } - - String name = parsingPackage.getName(); - if (name != null) { - parsingPackage.setClassName(name); - } - - String manageSpaceActivity = sa.getNonConfigurationString( - R.styleable.AndroidManifestApplication_manageSpaceActivity, - Configuration.NATIVE_CONFIG_VERSION); - if (manageSpaceActivity != null) { - String manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity); - - if (manageSpaceActivityName == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Empty class name in package " + pkgName - ); - } - - parsingPackage.setManageSpaceActivityName(manageSpaceActivityName); - } - - boolean allowBackup = sa.getBoolean( - R.styleable.AndroidManifestApplication_allowBackup, true); - parsingPackage.setAllowBackup(allowBackup); - - if (allowBackup) { - // backupAgent, killAfterRestore, fullBackupContent, backupInForeground, - // and restoreAnyVersion are only relevant if backup is possible for the - // given application. - String backupAgent = sa.getNonConfigurationString( - R.styleable.AndroidManifestApplication_backupAgent, - Configuration.NATIVE_CONFIG_VERSION); - if (backupAgent != null) { - String backupAgentName = buildClassName(pkgName, backupAgent); - if (backupAgentName == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Empty class name in package " + pkgName - ); - } - - if (PackageParser.DEBUG_BACKUP) { - Slog.v(TAG, "android:backupAgent = " + backupAgentName - + " from " + pkgName + "+" + backupAgent); - } - - parsingPackage.setBackupAgentName(backupAgentName); - - parsingPackage.setKillAfterRestore(sa.getBoolean( - R.styleable.AndroidManifestApplication_killAfterRestore, true)); - - parsingPackage.setRestoreAnyVersion(sa.getBoolean( - R.styleable.AndroidManifestApplication_restoreAnyVersion, false)); - - parsingPackage.setFullBackupOnly(sa.getBoolean( - R.styleable.AndroidManifestApplication_fullBackupOnly, false)); - - parsingPackage.setBackupInForeground(sa.getBoolean( - R.styleable.AndroidManifestApplication_backupInForeground, - false)); - } - - TypedValue v = sa.peekValue( - R.styleable.AndroidManifestApplication_fullBackupContent); - int fullBackupContent = 0; - - if (v != null) { - fullBackupContent = v.resourceId; - - if (v.resourceId == 0) { - if (PackageParser.DEBUG_BACKUP) { - Slog.v(TAG, "fullBackupContent specified as boolean=" + - (v.data == 0 ? "false" : "true")); - } - // "false" => -1, "true" => 0 - fullBackupContent = v.data == 0 ? -1 : 0; - } - - parsingPackage.setFullBackupContent(fullBackupContent); - } - if (PackageParser.DEBUG_BACKUP) { - Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName); - } - } - - parsingPackage - .setTheme( - sa.getResourceId(R.styleable.AndroidManifestApplication_theme, 0)) - .setDescriptionRes( - sa.getResourceId(R.styleable.AndroidManifestApplication_description, - 0)); - - if (sa.getBoolean( - R.styleable.AndroidManifestApplication_persistent, - false)) { - // Check if persistence is based on a feature being present - final String requiredFeature = sa.getNonResourceString(R.styleable - .AndroidManifestApplication_persistentWhenFeatureAvailable); - parsingPackage.setPersistent(requiredFeature == null - || callback.hasFeature(requiredFeature)); - } - - boolean requiredForAllUsers = sa.getBoolean( - R.styleable.AndroidManifestApplication_requiredForAllUsers, - false); - parsingPackage.setRequiredForAllUsers(requiredForAllUsers); - - String restrictedAccountType = sa.getString(R.styleable - .AndroidManifestApplication_restrictedAccountType); - if (restrictedAccountType != null && restrictedAccountType.length() > 0) { - parsingPackage.setRestrictedAccountType(restrictedAccountType); - } - - String requiredAccountType = sa.getString(R.styleable - .AndroidManifestApplication_requiredAccountType); - if (requiredAccountType != null && requiredAccountType.length() > 0) { - parsingPackage.setRequiredAccountType(requiredAccountType); - } - - parsingPackage.setForceQueryable( - sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false) - ); - - boolean debuggable = sa.getBoolean( - R.styleable.AndroidManifestApplication_debuggable, - false - ); - - parsingPackage.setDebuggable(debuggable); - - if (debuggable) { - // Debuggable implies profileable - parsingPackage.setProfileableByShell(true); - } - - parsingPackage.setVmSafeMode(sa.getBoolean( - R.styleable.AndroidManifestApplication_vmSafeMode, false)); - - boolean baseHardwareAccelerated = sa.getBoolean( - R.styleable.AndroidManifestApplication_hardwareAccelerated, - parsingPackage.getTargetSdkVersion() - >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); - parsingPackage.setBaseHardwareAccelerated(baseHardwareAccelerated); - - parsingPackage.setHasCode(sa.getBoolean( - R.styleable.AndroidManifestApplication_hasCode, true)); - - parsingPackage.setAllowTaskReparenting(sa.getBoolean( - R.styleable.AndroidManifestApplication_allowTaskReparenting, false)); - - parsingPackage.setAllowClearUserData(sa.getBoolean( - R.styleable.AndroidManifestApplication_allowClearUserData, true)); - - parsingPackage.setTestOnly(sa.getBoolean( - com.android.internal.R.styleable.AndroidManifestApplication_testOnly, - false)); - - parsingPackage.setLargeHeap(sa.getBoolean( - R.styleable.AndroidManifestApplication_largeHeap, false)); - - parsingPackage.setUsesCleartextTraffic(sa.getBoolean( - R.styleable.AndroidManifestApplication_usesCleartextTraffic, - parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.P)); - - parsingPackage.setSupportsRtl(sa.getBoolean( - R.styleable.AndroidManifestApplication_supportsRtl, - false /* default is no RTL support*/)); - - parsingPackage.setMultiArch(sa.getBoolean( - R.styleable.AndroidManifestApplication_multiArch, false)); - - parsingPackage.setExtractNativeLibs(sa.getBoolean( - R.styleable.AndroidManifestApplication_extractNativeLibs, true)); - - parsingPackage.setUseEmbeddedDex(sa.getBoolean( - R.styleable.AndroidManifestApplication_useEmbeddedDex, false)); - - parsingPackage.setDefaultToDeviceProtectedStorage(sa.getBoolean( - R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, - false)); - - parsingPackage.setDirectBootAware(sa.getBoolean( - R.styleable.AndroidManifestApplication_directBootAware, false)); - - if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) { - parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean( - R.styleable.AndroidManifestApplication_resizeableActivity, true)); - } else { - parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion( - parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N); - } - - parsingPackage.setAllowClearUserDataOnFailedRestore(sa.getBoolean( - R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, - true)); - - - parsingPackage.setAllowAudioPlaybackCapture(sa.getBoolean( - R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, - parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q)); - - parsingPackage.setRequestLegacyExternalStorage(sa.getBoolean( - R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, - parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q)); - - parsingPackage.setAllowNativeHeapPointerTagging(sa.getBoolean( - R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, true)); - - parsingPackage.setPreserveLegacyExternalStorage(sa.getBoolean( - R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage, - false)); - - parsingPackage - .setMaxAspectRatio( - sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0)) - .setMinAspectRatio( - sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0)) - .setNetworkSecurityConfigRes(sa.getResourceId( - R.styleable.AndroidManifestApplication_networkSecurityConfig, 0)) - .setCategory(sa.getInt(R.styleable.AndroidManifestApplication_appCategory, - ApplicationInfo.CATEGORY_UNDEFINED)); - - String str; - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestApplication_permission, 0); - parsingPackage.setPermission((str != null && str.length() > 0) ? str.intern() : null); - - if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestApplication_taskAffinity, - Configuration.NATIVE_CONFIG_VERSION); - } else { - // Some older apps have been seen to use a resource reference - // here that on older builds was ignored (with a warning). We - // need to continue to do this for them so they don't break. - str = sa.getNonResourceString( - R.styleable.AndroidManifestApplication_taskAffinity); - } - String packageName = parsingPackage.getPackageName(); - String taskAffinity = PackageParser.buildTaskAffinityName(packageName, - packageName, - str, outError); - - if (outError[0] != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.setTaskAffinity(taskAffinity); - String factory = sa.getNonResourceString( - R.styleable.AndroidManifestApplication_appComponentFactory); - if (factory != null) { - String appComponentFactory = buildClassName(packageName, factory); - if (appComponentFactory == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Empty class name in package " + pkgName - ); - } - - parsingPackage.setAppComponentFactory(appComponentFactory); - } - - parsingPackage.setUsesNonSdkApi(sa.getBoolean( - R.styleable.AndroidManifestApplication_usesNonSdkApi, false)); - - parsingPackage.setHasFragileUserData(sa.getBoolean( - R.styleable.AndroidManifestApplication_hasFragileUserData, false)); - - CharSequence pname; - if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { - pname = sa.getNonConfigurationString( - R.styleable.AndroidManifestApplication_process, - Configuration.NATIVE_CONFIG_VERSION); - } else { - // Some older apps have been seen to use a resource reference - // here that on older builds was ignored (with a warning). We - // need to continue to do this for them so they don't break. - pname = sa.getNonResourceString( - R.styleable.AndroidManifestApplication_process); - } - String processName = PackageParser.buildProcessName(packageName, null, pname, flags, - separateProcesses, outError); - - if (outError[0] != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage - .setProcessName(processName) - .setEnabled( - sa.getBoolean(R.styleable.AndroidManifestApplication_enabled, - true)); - - parsingPackage.setCrossProfile( - sa.getBoolean(R.styleable.AndroidManifestApplication_crossProfile, false)); - - parsingPackage.setIsGame(sa.getBoolean( - R.styleable.AndroidManifestApplication_isGame, false)); - - boolean cantSaveState = sa.getBoolean( - R.styleable.AndroidManifestApplication_cantSaveState, false); - parsingPackage.setCantSaveState(cantSaveState); - if (cantSaveState) { - // A heavy-weight application can not be in a custom process. - // We can do direct compare because we intern all strings. - if (processName != null && !processName.equals(packageName)) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "cantSaveState applications can not use custom processes" - ); - } - } - - String classLoaderName = sa.getString( - R.styleable.AndroidManifestApplication_classLoader); - parsingPackage - .setUiOptions(sa.getInt(R.styleable.AndroidManifestApplication_uiOptions, 0)) - .setClassLoaderName(classLoaderName) - .setZygotePreloadName( - sa.getString(R.styleable.AndroidManifestApplication_zygotePreloadName)); - - if (classLoaderName != null - && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Invalid class loader name: " + classLoaderName - ); - } - } finally { - if (sa != null) { - sa.recycle(); - } - } - - final int innerDepth = parser.getDepth(); - int type; - boolean hasActivityOrder = false; - boolean hasReceiverOrder = false; - boolean hasServiceOrder = false; - - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - switch (tagName) { - case "activity": - ComponentParseUtils.ParsedActivity activity = - ComponentParseUtils.parseActivity(separateProcesses, - parsingPackage, - res, parser, flags, - outError, false, - parsingPackage.isBaseHardwareAccelerated()); - if (activity == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - hasActivityOrder |= (activity.order != 0); - parsingPackage.addActivity(activity); - break; - case "receiver": - activity = ComponentParseUtils.parseActivity(separateProcesses, - parsingPackage, - res, parser, - flags, outError, - true, false); - if (activity == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - hasReceiverOrder |= (activity.order != 0); - parsingPackage.addReceiver(activity); - break; - case "service": - ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService( - separateProcesses, - parsingPackage, - res, parser, flags, - outError); - if (s == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - hasServiceOrder |= (s.order != 0); - parsingPackage.addService(s); - break; - case "provider": - ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider( - separateProcesses, - parsingPackage, - res, parser, flags, - outError - ); - if (p == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addProvider(p); - break; - case "activity-alias": - activity = ComponentParseUtils.parseActivityAlias( - parsingPackage, - res, - parser, - outError - ); - if (activity == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - hasActivityOrder |= (activity.order != 0); - parsingPackage.addActivity(activity); - break; - case "meta-data": - // note: application meta-data is stored off to the side, so it can - // remain null in the primary copy (we like to avoid extra copies because - // it can be large) - Bundle appMetaData = parseMetaData(parsingPackage, res, parser, - parsingPackage.getAppMetaData(), - outError); - if (appMetaData == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.setAppMetaData(appMetaData); - break; - case "static-library": - sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestStaticLibrary); - - // Note: don't allow this value to be a reference to a resource - // that may change. - String lname = sa.getNonResourceString( - R.styleable.AndroidManifestStaticLibrary_name); - final int version = sa.getInt( - R.styleable.AndroidManifestStaticLibrary_version, -1); - final int versionMajor = sa.getInt( - R.styleable.AndroidManifestStaticLibrary_versionMajor, - 0); - - sa.recycle(); - - // Since the app canot run without a static lib - fail if malformed - if (lname == null || version < 0) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Bad static-library declaration name: " + lname - + " version: " + version - ); - } - - if (parsingPackage.getSharedUserId() != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, - "sharedUserId not allowed in static shared library" - ); - } - - if (parsingPackage.getStaticSharedLibName() != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Multiple static-shared libs for package " + pkgName - ); - } - - parsingPackage.setStaticSharedLibName(lname.intern()); - if (version >= 0) { - parsingPackage.setStaticSharedLibVersion( - PackageInfo.composeLongVersionCode(versionMajor, version)); - } else { - parsingPackage.setStaticSharedLibVersion(version); - } - parsingPackage.setStaticSharedLibrary(true); - - XmlUtils.skipCurrentTag(parser); - - break; - case "library": - sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestLibrary); - - // Note: don't allow this value to be a reference to a resource - // that may change. - lname = sa.getNonResourceString( - R.styleable.AndroidManifestLibrary_name); - - sa.recycle(); - - if (lname != null) { - lname = lname.intern(); - if (!ArrayUtils.contains(parsingPackage.getLibraryNames(), lname)) { - parsingPackage.addLibraryName(lname); - } - } - - XmlUtils.skipCurrentTag(parser); - - break; - case "uses-static-library": - ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage, - res, parser); - if (!parseResult.isSuccess()) { - return parseResult; - } - break; - case "uses-library": - sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestUsesLibrary); - - // Note: don't allow this value to be a reference to a resource - // that may change. - lname = sa.getNonResourceString( - R.styleable.AndroidManifestUsesLibrary_name); - boolean req = sa.getBoolean( - R.styleable.AndroidManifestUsesLibrary_required, - true); - - sa.recycle(); - - if (lname != null) { - lname = lname.intern(); - if (req) { - parsingPackage.addUsesLibrary(lname); - } else { - parsingPackage.addUsesOptionalLibrary(lname); - } - } - - XmlUtils.skipCurrentTag(parser); - - break; - case "processes": - ArrayMap<String, ComponentParseUtils.ParsedProcess> processes = - ComponentParseUtils.parseProcesses(separateProcesses, - parsingPackage, - res, parser, flags, - outError); - if (processes == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.setProcesses(processes); - break; - case "uses-package": - // Dependencies for app installers; we don't currently try to - // enforce this. - XmlUtils.skipCurrentTag(parser); - break; - case "profileable": - sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestProfileable); - if (sa.getBoolean( - R.styleable.AndroidManifestProfileable_shell, false)) { - parsingPackage.setProfileableByShell(true); - } - XmlUtils.skipCurrentTag(parser); - break; - default: - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "Unknown element under <application>: " + tagName - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } else { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Bad element under <application>: " + tagName - ); - } - } - } - - if (TextUtils.isEmpty(parsingPackage.getStaticSharedLibName())) { - // Add a hidden app detail activity to normal apps which forwards user to App Details - // page. - ComponentParseUtils.ParsedActivity a = generateAppDetailsHiddenActivity( - parsingPackage, - outError - ); - // Ignore errors here - parsingPackage.addActivity(a); - } - - if (hasActivityOrder) { - parsingPackage.sortActivities(); - } - if (hasReceiverOrder) { - parsingPackage.sortReceivers(); - } - if (hasServiceOrder) { - parsingPackage.sortServices(); - } - // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after - // every activity info has had a chance to set it from its attributes. - setMaxAspectRatio(parsingPackage); - setMinAspectRatio(parsingPackage, callback); - - parsingPackage.setHasDomainUrls(hasDomainURLs(parsingPackage)); - - return parseInput.success(parsingPackage); - } - - private static ParseResult parseUsesStaticLibrary( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws XmlPullParserException, IOException { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestUsesStaticLibrary); - - // Note: don't allow this value to be a reference to a resource that may change. - String lname = sa.getNonResourceString( - R.styleable.AndroidManifestUsesLibrary_name); - final int version = sa.getInt( - R.styleable.AndroidManifestUsesStaticLibrary_version, -1); - String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable - .AndroidManifestUsesStaticLibrary_certDigest); - sa.recycle(); - - // Since an APK providing a static shared lib can only provide the lib - fail if malformed - if (lname == null || version < 0 || certSha256Digest == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Bad uses-static-library declaration name: " + lname + " version: " - + version + " certDigest" + certSha256Digest - ); - } - - // Can depend only on one version of the same library - List<String> usesStaticLibraries = parsingPackage.getUsesStaticLibraries(); - if (usesStaticLibraries != null && usesStaticLibraries.contains(lname)) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Depending on multiple versions of static library " + lname - ); - } - - lname = lname.intern(); - // We allow ":" delimiters in the SHA declaration as this is the format - // emitted by the certtool making it easy for developers to copy/paste. - certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); - - // Fot apps targeting O-MR1 we require explicit enumeration of all certs. - String[] additionalCertSha256Digests = EmptyArray.STRING; - if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) { - // TODO(b/135203078): Remove, replace with ParseResult - String[] outError = new String[1]; - additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError); - if (additionalCertSha256Digests == null || outError[0] != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - } else { - XmlUtils.skipCurrentTag(parser); - } - - final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; - certSha256Digests[0] = certSha256Digest; - System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, - 1, additionalCertSha256Digests.length); - - parsingPackage.addUsesStaticLibrary(lname) - .addUsesStaticLibraryVersion(version) - .addUsesStaticLibraryCertDigests(certSha256Digests); - - return parseInput.success(parsingPackage); - } - - private static String[] parseAdditionalCertificates( - Resources resources, - XmlResourceParser parser, - String[] outError - ) throws XmlPullParserException, IOException { - String[] certSha256Digests = EmptyArray.STRING; - - int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - final String nodeName = parser.getName(); - if (nodeName.equals("additional-certificate")) { - final TypedArray sa = resources.obtainAttributes(parser, com.android.internal. - R.styleable.AndroidManifestAdditionalCertificate); - String certSha256Digest = sa.getNonResourceString(com.android.internal. - R.styleable.AndroidManifestAdditionalCertificate_certDigest); - sa.recycle(); - - if (TextUtils.isEmpty(certSha256Digest)) { - outError[0] = "Bad additional-certificate declaration with empty" - + " certDigest:" + certSha256Digest; - XmlUtils.skipCurrentTag(parser); - sa.recycle(); - return null; - } - - // We allow ":" delimiters in the SHA declaration as this is the format - // emitted by the certtool making it easy for developers to copy/paste. - certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); - certSha256Digests = ArrayUtils.appendElement(String.class, - certSha256Digests, certSha256Digest); - } else { - XmlUtils.skipCurrentTag(parser); - } - } - - return certSha256Digests; - } - - /** - * Generate activity object that forwards user to App Details page automatically. - * This activity should be invisible to user and user should not know or see it. - * - * @hide - */ - @NonNull - private static ComponentParseUtils.ParsedActivity generateAppDetailsHiddenActivity( - ParsingPackage parsingPackage, - String[] outError - ) { - String packageName = parsingPackage.getPackageName(); - String processName = parsingPackage.getProcessName(); - boolean hardwareAccelerated = parsingPackage.isBaseHardwareAccelerated(); - int uiOptions = parsingPackage.getUiOptions(); - - // Build custom App Details activity info instead of parsing it from xml - ComponentParseUtils.ParsedActivity activity = new ComponentParseUtils.ParsedActivity(); - activity.setPackageName(packageName); - - activity.theme = android.R.style.Theme_NoDisplay; - activity.exported = true; - activity.className = PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME; - activity.setProcessName(processName, processName); - activity.uiOptions = uiOptions; - activity.taskAffinity = PackageParser.buildTaskAffinityName(packageName, - packageName, - ":app_details", outError); - activity.enabled = true; - activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE; - activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic(); - activity.configChanges = PackageParser.getActivityConfigChanges(0, 0); - activity.softInputMode = 0; - activity.persistableMode = ActivityInfo.PERSIST_NEVER; - activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; - activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; - activity.lockTaskLaunchMode = 0; - activity.directBootAware = false; - activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; - activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT; - activity.preferMinimalPostProcessing = ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT; - if (hardwareAccelerated) { - activity.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; - } - - return activity; - } - - /** - * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI - */ - private static boolean hasDomainURLs( - ParsingPackage parsingPackage) { - final List<ComponentParseUtils.ParsedActivity> activities = parsingPackage.getActivities(); - final int countActivities = activities.size(); - for (int n = 0; n < countActivities; n++) { - ComponentParseUtils.ParsedActivity activity = activities.get(n); - List<ComponentParseUtils.ParsedActivityIntentInfo> filters = activity.intents; - if (filters == null) continue; - final int countFilters = filters.size(); - for (int m = 0; m < countFilters; m++) { - ComponentParseUtils.ParsedActivityIntentInfo aii = filters.get(m); - if (!aii.hasAction(Intent.ACTION_VIEW)) continue; - if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue; - if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || - aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { - return true; - } - } - } - return false; - } - - /** - * Sets the max aspect ratio of every child activity that doesn't already have an aspect - * ratio set. - */ - private static void setMaxAspectRatio( - ParsingPackage parsingPackage) { - // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. - // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. - float maxAspectRatio = parsingPackage.getTargetSdkVersion() < O - ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; - - float packageMaxAspectRatio = parsingPackage.getMaxAspectRatio(); - if (packageMaxAspectRatio != 0) { - // Use the application max aspect ration as default if set. - maxAspectRatio = packageMaxAspectRatio; - } else { - Bundle appMetaData = parsingPackage.getAppMetaData(); - if (appMetaData != null && appMetaData.containsKey( - PackageParser.METADATA_MAX_ASPECT_RATIO)) { - maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, - maxAspectRatio); - } - } - - if (parsingPackage.getActivities() != null) { - for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) { - // If the max aspect ratio for the activity has already been set, skip. - if (activity.hasMaxAspectRatio()) { - continue; - } - - // By default we prefer to use a values defined on the activity directly than values - // defined on the application. We do not check the styled attributes on the activity - // as it would have already been set when we processed the activity. We wait to - // process the meta data here since this method is called at the end of processing - // the application and all meta data is guaranteed. - final float activityAspectRatio = activity.metaData != null - ? activity.metaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, - maxAspectRatio) - : maxAspectRatio; - - activity.setMaxAspectRatio(activity.resizeMode, activityAspectRatio); - } - } - } - - /** - * Sets the min aspect ratio of every child activity that doesn't already have an aspect - * ratio set. - */ - private static void setMinAspectRatio( - ParsingPackage parsingPackage, - PackageParser.Callback callback - ) { - final float minAspectRatio; - float packageMinAspectRatio = parsingPackage.getMinAspectRatio(); - if (packageMinAspectRatio != 0) { - // Use the application max aspect ration as default if set. - minAspectRatio = packageMinAspectRatio; - } else { - // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater. - // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD, - // except for watches which always supported 1:1. - minAspectRatio = parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q - ? 0 - : (callback != null && callback.hasFeature(FEATURE_WATCH)) - ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH - : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO; - } - - if (parsingPackage.getActivities() != null) { - for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) { - if (activity.hasMinAspectRatio()) { - continue; - } - activity.setMinAspectRatio(activity.resizeMode, minAspectRatio); - } - } - } - - private static ParseResult parseOverlay( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay); - String target = sa.getString( - R.styleable.AndroidManifestResourceOverlay_targetPackage); - String targetName = sa.getString( - R.styleable.AndroidManifestResourceOverlay_targetName); - String category = sa.getString( - R.styleable.AndroidManifestResourceOverlay_category); - int priority = sa.getInt(R.styleable.AndroidManifestResourceOverlay_priority, - 0); - boolean isStatic = sa.getBoolean( - R.styleable.AndroidManifestResourceOverlay_isStatic, false); - - if (target == null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "<overlay> does not specify a target package" - ); - } - - if (priority < 0 || priority > 9999) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "<overlay> priority must be between 0 and 9999" - ); - } - - // check to see if overlay should be excluded based on system property condition - String propName = sa.getString( - R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName); - String propValue = sa.getString( - R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue); - if (!checkOverlayRequiredSystemProperty(propName, propValue)) { - Slog.i(TAG, "Skipping target and overlay pair " + target + " and " - + parsingPackage.getBaseCodePath() - + ": overlay ignored due to required system property: " - + propName + " with value: " + propValue); - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Skipping target and overlay pair " + target + " and " - + parsingPackage.getBaseCodePath() - + ": overlay ignored due to required system property: " - + propName + " with value: " + propValue - ); - } - - parsingPackage - .setIsOverlay(true) - .setOverlayTarget(target) - .setOverlayTargetName(targetName) - .setOverlayCategory(category) - .setOverlayPriority(priority) - .setOverlayIsStatic(isStatic); - - sa.recycle(); - - XmlUtils.skipCurrentTag(parser); - return parseInput.success(parsingPackage); - } - - private static boolean parseProtectedBroadcast( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestProtectedBroadcast); - - // Note: don't allow this value to be a reference to a resource - // that may change. - String name = sa.getNonResourceString(R.styleable.AndroidManifestProtectedBroadcast_name); - - sa.recycle(); - - if (name != null) { - parsingPackage.addProtectedBroadcast(name); - } - - XmlUtils.skipCurrentTag(parser); - return true; - } - - private static boolean parseSupportScreens( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestSupportsScreens); - - int requiresSmallestWidthDp = sa.getInteger( - R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, - 0); - int compatibleWidthLimitDp = sa.getInteger( - R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, - 0); - int largestWidthLimitDp = sa.getInteger( - R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, - 0); - - // This is a trick to get a boolean and still able to detect - // if a value was actually set. - parsingPackage - .setSupportsSmallScreens( - sa.getInteger(R.styleable.AndroidManifestSupportsScreens_smallScreens, 1)) - .setSupportsNormalScreens( - sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1)) - .setSupportsLargeScreens( - sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1)) - .setSupportsXLargeScreens( - sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1)) - .setResizeable( - sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1)) - .setAnyDensity( - sa.getInteger(R.styleable.AndroidManifestSupportsScreens_anyDensity, 1)) - .setRequiresSmallestWidthDp(requiresSmallestWidthDp) - .setCompatibleWidthLimitDp(compatibleWidthLimitDp) - .setLargestWidthLimitDp(largestWidthLimitDp); - - sa.recycle(); - - XmlUtils.skipCurrentTag(parser); - return true; - } - - private static ParseResult parseInstrumentation( - ParseInput parseInput, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws XmlPullParserException, IOException { - // TODO(b/135203078): Remove, replace with ParseResult - String[] outError = new String[1]; - - ComponentParseUtils.ParsedInstrumentation parsedInstrumentation = - ComponentParseUtils.parseInstrumentation(parsingPackage, - res, parser, outError); - - if (parsedInstrumentation == null || outError[0] != null) { - return parseInput.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - outError[0] - ); - } - - parsingPackage.addInstrumentation(parsedInstrumentation); - - return parseInput.success(parsingPackage); - } - - private static boolean parseOriginalPackage( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestOriginalPackage); - - String orig = sa.getNonConfigurationString( - R.styleable.AndroidManifestOriginalPackage_name, - 0); - if (!parsingPackage.getPackageName().equals(orig)) { - if (parsingPackage.getOriginalPackages() == null) { - parsingPackage.setRealPackage(parsingPackage.getPackageName()); - } - parsingPackage.addOriginalPackage(orig); - } - - sa.recycle(); - - XmlUtils.skipCurrentTag(parser); - return true; - } - - private static boolean parseAdoptPermissions( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser - ) throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestOriginalPackage); - - String name = sa.getNonConfigurationString( - R.styleable.AndroidManifestOriginalPackage_name, - 0); - - sa.recycle(); - - if (name != null) { - parsingPackage.addAdoptPermission(name); - } - - XmlUtils.skipCurrentTag(parser); - return true; - } - - private static void convertNewPermissions( - ParsingPackage packageToParse) { - final int NP = PackageParser.NEW_PERMISSIONS.length; - StringBuilder newPermsMsg = null; - for (int ip = 0; ip < NP; ip++) { - final PackageParser.NewPermissionInfo npi - = PackageParser.NEW_PERMISSIONS[ip]; - if (packageToParse.getTargetSdkVersion() >= npi.sdkVersion) { - break; - } - if (!packageToParse.getRequestedPermissions().contains(npi.name)) { - if (newPermsMsg == null) { - newPermsMsg = new StringBuilder(128); - newPermsMsg.append(packageToParse.getPackageName()); - newPermsMsg.append(": compat added "); - } else { - newPermsMsg.append(' '); - } - newPermsMsg.append(npi.name); - packageToParse.addRequestedPermission(npi.name); - packageToParse.addImplicitPermission(npi.name); - } - } - if (newPermsMsg != null) { - Slog.i(TAG, newPermsMsg.toString()); - } - } - - private static void convertSplitPermissions(ParsingPackage packageToParse) { - List<SplitPermissionInfoParcelable> splitPermissions; - - try { - splitPermissions = ActivityThread.getPermissionManager().getSplitPermissions(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - - final int listSize = splitPermissions.size(); - for (int is = 0; is < listSize; is++) { - final SplitPermissionInfoParcelable spi = splitPermissions.get(is); - List<String> requestedPermissions = packageToParse.getRequestedPermissions(); - if (packageToParse.getTargetSdkVersion() >= spi.getTargetSdk() - || !requestedPermissions.contains(spi.getSplitPermission())) { - continue; - } - final List<String> newPerms = spi.getNewPermissions(); - for (int in = 0; in < newPerms.size(); in++) { - final String perm = newPerms.get(in); - if (!requestedPermissions.contains(perm)) { - packageToParse.addRequestedPermission(perm); - packageToParse.addImplicitPermission(perm); - } - } - } - } - - private static boolean checkOverlayRequiredSystemProperty(String propName, String propValue) { - if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) { - if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) { - // malformed condition - incomplete - Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName - + "=" + propValue + "' - require both requiredSystemPropertyName" - + " AND requiredSystemPropertyValue to be specified."); - return false; - } - // no valid condition set - so no exclusion criteria, overlay will be included. - return true; - } - - // check property value - make sure it is both set and equal to expected value - final String currValue = SystemProperties.get(propName); - return (currValue != null && currValue.equals(propValue)); - } - - /** - * This is a pre-density application which will get scaled - instead of being pixel perfect. - * This type of application is not resizable. - * - * @param parsingPackage The package which needs to be marked as unresizable. - */ - private static void adjustPackageToBeUnresizeableAndUnpipable( - ParsingPackage parsingPackage) { - if (parsingPackage.getActivities() != null) { - for (ComponentParseUtils.ParsedActivity a : parsingPackage.getActivities()) { - a.resizeMode = RESIZE_MODE_UNRESIZEABLE; - a.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE; - } - } - } - - private static String validateName(String name, boolean requireSeparator, - boolean requireFilename) { - final int N = name.length(); - boolean hasSep = false; - boolean front = true; - for (int i = 0; i < N; i++) { - final char c = name.charAt(i); - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { - front = false; - continue; - } - if (!front) { - if ((c >= '0' && c <= '9') || c == '_') { - continue; - } - } - if (c == '.') { - hasSep = true; - front = true; - continue; - } - return "bad character '" + c + "'"; - } - if (requireFilename && !FileUtils.isValidExtFilename(name)) { - return "Invalid filename"; - } - return hasSep || !requireSeparator - ? null : "must have at least one '.' separator"; - } - - public static Bundle parseMetaData( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, Bundle data, String[] outError) - throws XmlPullParserException, IOException { - - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestMetaData); - - if (data == null) { - data = new Bundle(); - } - - String name = sa.getNonConfigurationString( - R.styleable.AndroidManifestMetaData_name, 0); - if (name == null) { - outError[0] = "<meta-data> requires an android:name attribute"; - sa.recycle(); - return null; - } - - name = name.intern(); - - TypedValue v = sa.peekValue( - R.styleable.AndroidManifestMetaData_resource); - if (v != null && v.resourceId != 0) { - //Slog.i(TAG, "Meta data ref " + name + ": " + v); - data.putInt(name, v.resourceId); - } else { - v = sa.peekValue( - R.styleable.AndroidManifestMetaData_value); - //Slog.i(TAG, "Meta data " + name + ": " + v); - if (v != null) { - if (v.type == TypedValue.TYPE_STRING) { - CharSequence cs = v.coerceToString(); - data.putString(name, cs != null ? cs.toString() : null); - } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { - data.putBoolean(name, v.data != 0); - } else if (v.type >= TypedValue.TYPE_FIRST_INT - && v.type <= TypedValue.TYPE_LAST_INT) { - data.putInt(name, v.data); - } else if (v.type == TypedValue.TYPE_FLOAT) { - data.putFloat(name, v.getFloat()); - } else { - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, - "<meta-data> only supports string, integer, float, color, " - + "boolean, and resource reference types: " - + parser.getName() + " at " - + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - } else { - outError[0] = - "<meta-data> only supports string, integer, float, color, " - + "boolean, and resource reference types"; - data = null; - } - } - } else { - outError[0] = "<meta-data> requires an android:value or android:resource attribute"; - data = null; - } - } - - sa.recycle(); - - XmlUtils.skipCurrentTag(parser); - - return data; - } - - /** - * Collect certificates from all the APKs described in the given package, - * populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that - * all APK contents are signed correctly and consistently. - */ - public static void collectCertificates(AndroidPackage pkg, boolean skipVerify) - throws PackageParserException { - pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN); - - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); - try { - pkg.mutate().setSigningDetails(collectCertificates( - pkg.getBaseCodePath(), - skipVerify, - pkg.isStaticSharedLibrary(), - pkg.getSigningDetails(), - pkg.getTargetSdkVersion() - )); - - String[] splitCodePaths = pkg.getSplitCodePaths(); - if (!ArrayUtils.isEmpty(splitCodePaths)) { - for (int i = 0; i < splitCodePaths.length; i++) { - pkg.mutate().setSigningDetails(collectCertificates( - splitCodePaths[i], - skipVerify, - pkg.isStaticSharedLibrary(), - pkg.getSigningDetails(), - pkg.getTargetSdkVersion() - )); - } - } - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - - public static SigningDetails collectCertificates( - String baseCodePath, - boolean skipVerify, - boolean isStaticSharedLibrary, - @NonNull SigningDetails existingSigningDetails, - int targetSdk - ) throws PackageParserException { - int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( - targetSdk); - if (isStaticSharedLibrary) { - // must use v2 signing scheme - minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2; - } - SigningDetails verified; - if (skipVerify) { - // systemDir APKs are already trusted, save time by not verifying - verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification( - baseCodePath, minSignatureScheme); - } else { - verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme); - } - - // Verify that entries are signed consistently with the first pkg - // we encountered. Note that for splits, certificates may have - // already been populated during an earlier parse of a base APK. - if (existingSigningDetails == SigningDetails.UNKNOWN) { - return verified; - } else { - if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) { - throw new PackageParserException( - INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, - baseCodePath + " has mismatched certificates"); - } - - return existingSigningDetails; - } - } - - @Nullable - public static String buildClassName(String pkg, CharSequence clsSeq) { - if (clsSeq == null || clsSeq.length() <= 0) { - return null; - } - String cls = clsSeq.toString(); - char c = cls.charAt(0); - if (c == '.') { - return pkg + cls; - } - if (cls.indexOf('.') < 0) { - StringBuilder b = new StringBuilder(pkg); - b.append('.'); - b.append(cls); - return b.toString(); - } - return cls; - } - - public interface ParseInput { - ParseResult success(ParsingPackage result); - - ParseResult error(int parseError); - - ParseResult error(int parseError, String errorMessage); - } - - public static class ParseResult implements ParseInput { - - private static final boolean DEBUG_FILL_STACK_TRACE = false; - - private ParsingPackage result; - - private int parseError; - private String errorMessage; - - public ParseInput reset() { - this.result = null; - this.parseError = PackageManager.INSTALL_SUCCEEDED; - this.errorMessage = null; - return this; - } - - @Override - public ParseResult success(ParsingPackage result) { - if (parseError != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) { - throw new IllegalStateException("Cannot set to success after set to error"); - } - this.result = result; - return this; - } - - @Override - public ParseResult error(int parseError) { - return error(parseError, null); - } - - @Override - public ParseResult error(int parseError, String errorMessage) { - this.parseError = parseError; - this.errorMessage = errorMessage; - - if (DEBUG_FILL_STACK_TRACE) { - this.errorMessage += Arrays.toString(new Exception().getStackTrace()); - } - - return this; - } - - public ParsingPackage getResultAndNull() { - ParsingPackage result = this.result; - this.result = null; - return result; - } - - public boolean isSuccess() { - return parseError == PackageManager.INSTALL_SUCCEEDED; - } - - public int getParseError() { - return parseError; - } - - public String getErrorMessage() { - return errorMessage; - } - } -} diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java deleted file mode 100644 index 6852a8c2254d..000000000000 --- a/core/java/android/content/pm/parsing/ComponentParseUtils.java +++ /dev/null @@ -1,3793 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm.parsing; - -import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; -import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; - -import android.annotation.CallSuper; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.StringRes; -import android.app.ActivityTaskManager; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.ComponentName; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.content.pm.PathPermission; -import android.content.pm.PermissionInfo; -import android.content.pm.ProviderInfo; -import android.content.pm.ServiceInfo; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Build; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.PatternMatcher; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.AttributeSet; -import android.util.Log; -import android.util.Slog; -import android.util.TypedValue; -import android.view.Gravity; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.DataClass; -import com.android.internal.util.XmlUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; - -/** - * TODO(b/135203078): Move the inner classes out to separate files. - * TODO(b/135203078): Expose inner classes as immutable through interface methods. - * - * @hide - */ -public class ComponentParseUtils { - - private static final String TAG = ApkParseUtils.TAG; - - // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base? - public static class ParsedIntentInfo extends IntentFilter { - - /** - * <p> - * Implementation note: The serialized form for the intent list also contains the name - * of the concrete class that's stored in the list, and assumes that every element of the - * list is of the same type. This is very similar to the original parcelable mechanism. - * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable - * and is public API. It also declares Parcelable related methods as final which means - * we can't extend them. The approach of using composition instead of inheritance leads to - * a large set of cascading changes in the PackageManagerService, which seem undesirable. - * - * <p> - * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up - * to make sure their owner fields are consistent. See {@code fixupOwner}. - */ - public static void writeIntentsList(List<? extends ParsedIntentInfo> list, Parcel out, - int flags) { - if (list == null) { - out.writeInt(-1); - return; - } - - final int size = list.size(); - out.writeInt(size); - - // Don't bother writing the component name if the list is empty. - if (size > 0) { - ParsedIntentInfo info = list.get(0); - out.writeString(info.getClass().getName()); - - for (int i = 0; i < size; i++) { - list.get(i).writeIntentInfoToParcel(out, flags); - } - } - } - - public static <T extends ParsedIntentInfo> ArrayList<T> createIntentsList(Parcel in) { - int size = in.readInt(); - if (size == -1) { - return null; - } - - if (size == 0) { - return new ArrayList<>(0); - } - - String className = in.readString(); - final ArrayList<T> intentsList; - try { - final Class<T> cls = (Class<T>) Class.forName(className); - final Constructor<T> cons = cls.getConstructor(Parcel.class); - - intentsList = new ArrayList<>(size); - for (int i = 0; i < size; ++i) { - intentsList.add(cons.newInstance(in)); - } - } catch (ReflectiveOperationException ree) { - throw new AssertionError("Unable to construct intent list for: " - + className, ree); - } - - return intentsList; - } - - protected String packageName; - protected final String className; - - public boolean hasDefault; - public int labelRes; - public CharSequence nonLocalizedLabel; - public int icon; - - protected List<String> rawDataTypes; - - public void addRawDataType(String dataType) throws MalformedMimeTypeException { - if (rawDataTypes == null) { - rawDataTypes = new ArrayList<>(); - } - - rawDataTypes.add(dataType); - addDataType(dataType); - } - - public ParsedIntentInfo(String packageName, String className) { - this.packageName = packageName; - this.className = className; - } - - public ParsedIntentInfo(Parcel in) { - super(in); - packageName = in.readString(); - className = in.readString(); - hasDefault = (in.readInt() == 1); - labelRes = in.readInt(); - nonLocalizedLabel = in.readCharSequence(); - icon = in.readInt(); - } - - public void writeIntentInfoToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(packageName); - dest.writeString(className); - dest.writeInt(hasDefault ? 1 : 0); - dest.writeInt(labelRes); - dest.writeCharSequence(nonLocalizedLabel); - dest.writeInt(icon); - } - - public String getPackageName() { - return packageName; - } - - public String getClassName() { - return className; - } - } - - public static class ParsedActivityIntentInfo extends ParsedIntentInfo { - - public ParsedActivityIntentInfo(String packageName, String className) { - super(packageName, className); - } - - public ParsedActivityIntentInfo(Parcel in) { - super(in); - } - - public static final Creator<ParsedActivityIntentInfo> CREATOR = - new Creator<ParsedActivityIntentInfo>() { - @Override - public ParsedActivityIntentInfo createFromParcel(Parcel source) { - return new ParsedActivityIntentInfo(source); - } - - @Override - public ParsedActivityIntentInfo[] newArray(int size) { - return new ParsedActivityIntentInfo[size]; - } - }; - } - - public static class ParsedServiceIntentInfo extends ParsedIntentInfo { - - public ParsedServiceIntentInfo(String packageName, String className) { - super(packageName, className); - } - - public ParsedServiceIntentInfo(Parcel in) { - super(in); - } - - public static final Creator<ParsedServiceIntentInfo> CREATOR = - new Creator<ParsedServiceIntentInfo>() { - @Override - public ParsedServiceIntentInfo createFromParcel(Parcel source) { - return new ParsedServiceIntentInfo(source); - } - - @Override - public ParsedServiceIntentInfo[] newArray(int size) { - return new ParsedServiceIntentInfo[size]; - } - }; - } - - public static class ParsedProviderIntentInfo extends ParsedIntentInfo { - - public ParsedProviderIntentInfo(String packageName, String className) { - super(packageName, className); - } - - public ParsedProviderIntentInfo(Parcel in) { - super(in); - } - - public static final Creator<ParsedProviderIntentInfo> CREATOR = - new Creator<ParsedProviderIntentInfo>() { - @Override - public ParsedProviderIntentInfo createFromParcel(Parcel source) { - return new ParsedProviderIntentInfo(source); - } - - @Override - public ParsedProviderIntentInfo[] newArray(int size) { - return new ParsedProviderIntentInfo[size]; - } - }; - } - - public static class ParsedQueriesIntentInfo extends ParsedIntentInfo { - - public ParsedQueriesIntentInfo(String packageName, String className) { - super(packageName, className); - } - - public ParsedQueriesIntentInfo(Parcel in) { - super(in); - } - - public static final Creator<ParsedQueriesIntentInfo> CREATOR = - new Creator<ParsedQueriesIntentInfo>() { - @Override - public ParsedQueriesIntentInfo createFromParcel(Parcel source) { - return new ParsedQueriesIntentInfo(source); - } - - @Override - public ParsedQueriesIntentInfo[] newArray(int size) { - return new ParsedQueriesIntentInfo[size]; - } - }; - } - - public static class ParsedComponent<IntentInfoType extends ParsedIntentInfo> implements - Parcelable { - - // TODO(b/135203078): Replace with "name", as not all usages are an actual class - public String className; - public int icon; - public int labelRes; - public CharSequence nonLocalizedLabel; - public int logo; - public int banner; - - public int descriptionRes; - - // TODO(b/135203078): Make subclass that contains these fields only for the necessary - // subtypes - protected boolean enabled = true; - protected boolean directBootAware; - public int flags; - - private String packageName; - private String splitName; - - // TODO(b/135203078): Make nullable - public List<IntentInfoType> intents = new ArrayList<>(); - - private transient ComponentName componentName; - - protected Bundle metaData; - - public void setSplitName(String splitName) { - this.splitName = splitName; - } - - public String getSplitName() { - return splitName; - } - - @CallSuper - public void setPackageName(String packageName) { - this.packageName = packageName; - this.componentName = null; - } - - void setPackageNameInternal(String packageName) { - this.packageName = packageName; - this.componentName = null; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getPackageName() { - return packageName; - } - - public final boolean isDirectBootAware() { - return directBootAware; - } - - public final boolean isEnabled() { - return enabled; - } - - public final String getName() { - return className; - } - - public final Bundle getMetaData() { - return metaData; - } - - @UnsupportedAppUsage - public ComponentName getComponentName() { - if (componentName != null) { - return componentName; - } - if (className != null) { - componentName = new ComponentName(getPackageName(), - className); - } - return componentName; - } - - public void setFrom(ParsedComponent other) { - this.metaData = other.metaData; - this.className = other.className; - this.icon = other.icon; - this.labelRes = other.labelRes; - this.nonLocalizedLabel = other.nonLocalizedLabel; - this.logo = other.logo; - this.banner = other.banner; - - this.descriptionRes = other.descriptionRes; - - this.enabled = other.enabled; - this.directBootAware = other.directBootAware; - this.flags = other.flags; - - this.setPackageName(other.packageName); - this.setSplitName(other.getSplitName()); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(this.className); - dest.writeInt(this.icon); - dest.writeInt(this.labelRes); - dest.writeCharSequence(this.nonLocalizedLabel); - dest.writeInt(this.logo); - dest.writeInt(this.banner); - dest.writeInt(this.descriptionRes); - dest.writeBoolean(this.enabled); - dest.writeBoolean(this.directBootAware); - dest.writeInt(this.flags); - dest.writeString(this.packageName); - dest.writeString(this.splitName); - ParsedIntentInfo.writeIntentsList(this.intents, dest, flags); - dest.writeBundle(this.metaData); - } - - public ParsedComponent() { - } - - protected ParsedComponent(Parcel in) { - // We use the boot classloader for all classes that we load. - final ClassLoader boot = Object.class.getClassLoader(); - this.className = in.readString(); - this.icon = in.readInt(); - this.labelRes = in.readInt(); - this.nonLocalizedLabel = in.readCharSequence(); - this.logo = in.readInt(); - this.banner = in.readInt(); - this.descriptionRes = in.readInt(); - this.enabled = in.readByte() != 0; - this.directBootAware = in.readByte() != 0; - this.flags = in.readInt(); - this.packageName = in.readString(); - this.splitName = in.readString(); - this.intents = ParsedIntentInfo.createIntentsList(in); - this.metaData = in.readBundle(boot); - } - } - - // TODO(b/135203078): Document this. Maybe split out ParsedComponent to be actual components - // that can have their own processes, rather than something like permission which cannot. - public static class ParsedMainComponent<IntentInfoType extends ParsedIntentInfo> extends - ParsedComponent<IntentInfoType> { - - private String processName; - private String permission; - - public void setProcessName(String appProcessName, String processName) { - // TODO(b/135203078): Is this even necessary anymore? - this.processName = TextUtils.safeIntern( - processName == null ? appProcessName : processName); - } - - public String getProcessName() { - return processName; - } - - public void setPermission(String permission) { - // Empty string must be converted to null - this.permission = TextUtils.isEmpty(permission) ? null : permission.intern(); - } - - public String getPermission() { - return permission; - } - - @Override - public void setFrom(ParsedComponent other) { - super.setFrom(other); - if (other instanceof ParsedMainComponent) { - ParsedMainComponent otherMainComponent = (ParsedMainComponent) other; - this.setProcessName(otherMainComponent.getProcessName(), - otherMainComponent.getProcessName()); - this.setPermission(otherMainComponent.getPermission()); - } - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(this.processName); - dest.writeString(this.permission); - } - - public ParsedMainComponent() { - } - - protected ParsedMainComponent(Parcel in) { - super(in); - this.processName = TextUtils.safeIntern(in.readString()); - this.permission = TextUtils.safeIntern(in.readString()); - } - - public static final Creator<ParsedMainComponent> CREATOR = - new Creator<ParsedMainComponent>() { - @Override - public ParsedMainComponent createFromParcel(Parcel source) { - return new ParsedMainComponent(source); - } - - @Override - public ParsedMainComponent[] newArray(int size) { - return new ParsedMainComponent[size]; - } - }; - } - - public static class ParsedActivity extends ParsedMainComponent<ParsedActivityIntentInfo> - implements Parcelable { - - public boolean exported; - public int theme; - public int uiOptions; - - public String targetActivity; - - public String parentActivityName; - public String taskAffinity; - public int privateFlags; - - public int launchMode; - public int documentLaunchMode; - public int maxRecents; - public int configChanges; - public int softInputMode; - public int persistableMode; - public int lockTaskLaunchMode; - - public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - public int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; - - public float maxAspectRatio; - public boolean hasMaxAspectRatio; - - public float minAspectRatio; - public boolean hasMinAspectRatio; - - public String requestedVrComponent; - public int rotationAnimation = -1; - public int colorMode; - public boolean preferMinimalPostProcessing; - public int order; - - public ActivityInfo.WindowLayout windowLayout; - - @Override - public void setPackageName(String packageName) { - super.setPackageName(packageName); - for (ParsedIntentInfo intent : this.intents) { - intent.packageName = packageName; - } - } - - public boolean hasMaxAspectRatio() { - return hasMaxAspectRatio; - } - - public boolean hasMinAspectRatio() { - return hasMinAspectRatio; - } - - public void setMaxAspectRatio(int resizeMode, float maxAspectRatio) { - if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE - || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { - // Resizeable activities can be put in any aspect ratio. - return; - } - - if (maxAspectRatio < 1.0f && maxAspectRatio != 0) { - // Ignore any value lesser than 1.0. - return; - } - - this.maxAspectRatio = maxAspectRatio; - hasMaxAspectRatio = true; - } - - public void setMinAspectRatio(int resizeMode, float minAspectRatio) { - if (resizeMode == RESIZE_MODE_RESIZEABLE - || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { - // Resizeable activities can be put in any aspect ratio. - return; - } - - if (minAspectRatio < 1.0f && minAspectRatio != 0) { - // Ignore any value lesser than 1.0. - return; - } - - this.minAspectRatio = minAspectRatio; - hasMinAspectRatio = true; - } - - public void addIntent(ParsedActivityIntentInfo intent) { - this.intents.add(intent); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeBoolean(this.exported); - dest.writeInt(this.theme); - dest.writeInt(this.uiOptions); - dest.writeString(this.targetActivity); - dest.writeString(this.parentActivityName); - dest.writeString(this.taskAffinity); - dest.writeInt(this.privateFlags); - dest.writeInt(this.launchMode); - dest.writeInt(this.documentLaunchMode); - dest.writeInt(this.maxRecents); - dest.writeInt(this.configChanges); - dest.writeInt(this.softInputMode); - dest.writeInt(this.persistableMode); - dest.writeInt(this.lockTaskLaunchMode); - dest.writeInt(this.screenOrientation); - dest.writeInt(this.resizeMode); - dest.writeFloat(this.maxAspectRatio); - dest.writeBoolean(this.hasMaxAspectRatio); - dest.writeFloat(this.minAspectRatio); - dest.writeBoolean(this.hasMinAspectRatio); - dest.writeString(this.requestedVrComponent); - dest.writeInt(this.rotationAnimation); - dest.writeInt(this.colorMode); - dest.writeBoolean(this.preferMinimalPostProcessing); - dest.writeInt(this.order); - dest.writeBundle(this.metaData); - - if (windowLayout != null) { - dest.writeInt(1); - dest.writeInt(windowLayout.width); - dest.writeFloat(windowLayout.widthFraction); - dest.writeInt(windowLayout.height); - dest.writeFloat(windowLayout.heightFraction); - dest.writeInt(windowLayout.gravity); - dest.writeInt(windowLayout.minWidth); - dest.writeInt(windowLayout.minHeight); - } else { - dest.writeInt(0); - } - } - - public ParsedActivity() { - } - - protected ParsedActivity(Parcel in) { - super(in); - this.exported = in.readByte() != 0; - this.theme = in.readInt(); - this.uiOptions = in.readInt(); - this.targetActivity = in.readString(); - this.parentActivityName = in.readString(); - this.taskAffinity = in.readString(); - this.privateFlags = in.readInt(); - this.launchMode = in.readInt(); - this.documentLaunchMode = in.readInt(); - this.maxRecents = in.readInt(); - this.configChanges = in.readInt(); - this.softInputMode = in.readInt(); - this.persistableMode = in.readInt(); - this.lockTaskLaunchMode = in.readInt(); - this.screenOrientation = in.readInt(); - this.resizeMode = in.readInt(); - this.maxAspectRatio = in.readFloat(); - this.hasMaxAspectRatio = in.readByte() != 0; - this.minAspectRatio = in.readFloat(); - this.hasMinAspectRatio = in.readByte() != 0; - this.requestedVrComponent = in.readString(); - this.rotationAnimation = in.readInt(); - this.colorMode = in.readInt(); - this.preferMinimalPostProcessing = in.readByte() != 0; - this.order = in.readInt(); - this.metaData = in.readBundle(); - if (in.readInt() == 1) { - windowLayout = new ActivityInfo.WindowLayout(in); - } - } - - public static final Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() { - @Override - public ParsedActivity createFromParcel(Parcel source) { - return new ParsedActivity(source); - } - - @Override - public ParsedActivity[] newArray(int size) { - return new ParsedActivity[size]; - } - }; - } - - public static class ParsedService extends ParsedMainComponent<ParsedServiceIntentInfo> { - - public boolean exported; - public int flags; - public int foregroundServiceType; - public int order; - - @Override - public void setPackageName(String packageName) { - super.setPackageName(packageName); - for (ParsedIntentInfo intent : this.intents) { - intent.packageName = packageName; - } - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeBoolean(this.exported); - dest.writeBundle(this.metaData); - dest.writeInt(this.flags); - dest.writeInt(this.foregroundServiceType); - dest.writeInt(this.order); - } - - public ParsedService() { - } - - protected ParsedService(Parcel in) { - super(in); - this.exported = in.readByte() != 0; - this.metaData = in.readBundle(); - this.flags = in.readInt(); - this.foregroundServiceType = in.readInt(); - this.order = in.readInt(); - } - - public static final Creator<ParsedService> CREATOR = new Creator<ParsedService>() { - @Override - public ParsedService createFromParcel(Parcel source) { - return new ParsedService(source); - } - - @Override - public ParsedService[] newArray(int size) { - return new ParsedService[size]; - } - }; - } - - public static class ParsedProvider extends ParsedMainComponent<ParsedProviderIntentInfo> { - - protected boolean exported; - protected int flags; - protected int order; - private String authority; - protected boolean isSyncable; - private String readPermission; - private String writePermission; - protected boolean grantUriPermissions; - protected boolean forceUriPermissions; - protected boolean multiProcess; - protected int initOrder; - protected PatternMatcher[] uriPermissionPatterns; - protected PathPermission[] pathPermissions; - - public ParsedProvider(ParsedProvider other) { - this.setFrom(other); - } - - protected void setFrom(ParsedProvider other) { - super.setFrom(other); - this.exported = other.exported; - - this.intents.clear(); - if (other.intents != null) { - this.intents.addAll(other.intents); - } - - this.flags = other.flags; - this.order = other.order; - this.setAuthority(other.getAuthority()); - this.isSyncable = other.isSyncable; - this.setReadPermission(other.getReadPermission()); - this.setWritePermission(other.getWritePermission()); - this.grantUriPermissions = other.grantUriPermissions; - this.forceUriPermissions = other.forceUriPermissions; - this.multiProcess = other.multiProcess; - this.initOrder = other.initOrder; - this.uriPermissionPatterns = other.uriPermissionPatterns; - this.pathPermissions = other.pathPermissions; - } - - @Override - public void setPackageName(String packageName) { - super.setPackageName(packageName); - for (ParsedIntentInfo intent : this.intents) { - intent.packageName = packageName; - } - } - - public boolean isExported() { - return exported; - } - - @VisibleForTesting - public void setExported(boolean exported) { - this.exported = exported; - } - - public List<ParsedProviderIntentInfo> getIntents() { - return intents; - } - - public int getFlags() { - return flags; - } - - public int getOrder() { - return order; - } - - public void setAuthority(String authority) { - this.authority = TextUtils.safeIntern(authority); - } - - public String getAuthority() { - return authority; - } - - public void setSyncable(boolean isSyncable) { - this.isSyncable = isSyncable; - } - - public boolean isSyncable() { - return isSyncable; - } - - public void setReadPermission(String readPermission) { - // Empty string must be converted to null - this.readPermission = TextUtils.isEmpty(readPermission) - ? null : readPermission.intern(); - } - - public String getReadPermission() { - return readPermission; - } - - public void setWritePermission(String writePermission) { - // Empty string must be converted to null - this.writePermission = TextUtils.isEmpty(writePermission) - ? null : writePermission.intern(); - } - - public String getWritePermission() { - return writePermission; - } - - public boolean isGrantUriPermissions() { - return grantUriPermissions; - } - - public boolean isForceUriPermissions() { - return forceUriPermissions; - } - - public boolean isMultiProcess() { - return multiProcess; - } - - public int getInitOrder() { - return initOrder; - } - - public PatternMatcher[] getUriPermissionPatterns() { - return uriPermissionPatterns; - } - - public PathPermission[] getPathPermissions() { - return pathPermissions; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeBoolean(this.exported); - dest.writeInt(this.flags); - dest.writeInt(this.order); - dest.writeString(this.authority); - dest.writeBoolean(this.isSyncable); - dest.writeString(this.readPermission); - dest.writeString(this.writePermission); - dest.writeBoolean(this.grantUriPermissions); - dest.writeBoolean(this.forceUriPermissions); - dest.writeBoolean(this.multiProcess); - dest.writeInt(this.initOrder); - dest.writeTypedArray(this.uriPermissionPatterns, flags); - dest.writeTypedArray(this.pathPermissions, flags); - } - - public ParsedProvider() { - } - - protected ParsedProvider(Parcel in) { - super(in); - this.exported = in.readByte() != 0; - this.flags = in.readInt(); - this.order = in.readInt(); - this.authority = TextUtils.safeIntern(in.readString()); - this.isSyncable = in.readByte() != 0; - this.readPermission = TextUtils.safeIntern(in.readString()); - this.writePermission = TextUtils.safeIntern(in.readString()); - this.grantUriPermissions = in.readByte() != 0; - this.forceUriPermissions = in.readByte() != 0; - this.multiProcess = in.readByte() != 0; - this.initOrder = in.readInt(); - this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR); - this.pathPermissions = in.createTypedArray(PathPermission.CREATOR); - } - - public static final Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() { - @Override - public ParsedProvider createFromParcel(Parcel source) { - return new ParsedProvider(source); - } - - @Override - public ParsedProvider[] newArray(int size) { - return new ParsedProvider[size]; - } - }; - } - - /** - * A {@link android.R.styleable#AndroidManifestFeature <feature>} tag parsed from the - * manifest. - */ - // @DataClass verifier is broken, hence comment out for now - public static class ParsedFeature implements Parcelable { - /** Maximum length of featureId */ - public static final int MAX_FEATURE_ID_LEN = 50; - - /** Maximum amount of features per package */ - private static final int MAX_NUM_FEATURES = 1000; - - /** Id of the feature */ - public final @NonNull String id; - - /** User visible label fo the feature */ - public final @StringRes int label; - - /** Ids of previously declared features this feature inherits from */ - public final @NonNull List<String> inheritFrom; - - /** - * @return Is this set of features a valid combination for a single package? - */ - public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) { - if (features == null) { - return true; - } - - ArraySet<String> featureIds = new ArraySet<>(features.size()); - ArraySet<String> inheritFromFeatureIds = new ArraySet<>(); - - int numFeatures = features.size(); - if (numFeatures > MAX_NUM_FEATURES) { - return false; - } - - for (int featureNum = 0; featureNum < numFeatures; featureNum++) { - boolean wasAdded = featureIds.add(features.get(featureNum).id); - if (!wasAdded) { - // feature id is not unique - return false; - } - } - - for (int featureNum = 0; featureNum < numFeatures; featureNum++) { - ParsedFeature feature = features.get(featureNum); - - int numInheritFrom = feature.inheritFrom.size(); - for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) { - String inheritFrom = feature.inheritFrom.get(inheritFromNum); - - if (featureIds.contains(inheritFrom)) { - // Cannot inherit from a feature that is still defined - return false; - } - - boolean wasAdded = inheritFromFeatureIds.add(inheritFrom); - if (!wasAdded) { - // inheritFrom is not unique - return false; - } - } - } - - return true; - } - - - - // Code below generated by codegen v1.0.14. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - /** - * Creates a new ParsedFeature. - * - * @param id - * Id of the feature - * @param label - * User visible label fo the feature (if defined as resource) - * @param inheritFrom - * Ids of previously declared features this feature inherits from - */ - @DataClass.Generated.Member - public ParsedFeature( - @NonNull String id, - @StringRes int label, - @NonNull List<String> inheritFrom) { - this.id = id; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, id); - this.label = label; - com.android.internal.util.AnnotationValidations.validate( - StringRes.class, null, label); - this.inheritFrom = inheritFrom; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, inheritFrom); - - // onConstructed(); // You can define this method to get a callback - } - - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - dest.writeString(id); - dest.writeInt(label); - dest.writeStringList(inheritFrom); - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - protected ParsedFeature(@NonNull Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - String _id = in.readString(); - int _label = in.readInt(); - List<String> _inheritFrom = new ArrayList<>(); - in.readStringList(_inheritFrom); - - this.id = _id; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, id); - this.label = _label; - com.android.internal.util.AnnotationValidations.validate( - StringRes.class, null, label); - this.inheritFrom = _inheritFrom; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, inheritFrom); - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR - = new Parcelable.Creator<ParsedFeature>() { - @Override - public ParsedFeature[] newArray(int size) { - return new ParsedFeature[size]; - } - - @Override - public ParsedFeature createFromParcel(@NonNull Parcel in) { - return new ParsedFeature(in); - } - }; - - /*@DataClass.Generated( - time = 1576783172965L, - codegenVersion = "1.0.14", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java", - inputSignatures = "public final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass") - */ - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - - } - - public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> { - - public String backgroundPermission; - private String group; - public int requestRes; - public int protectionLevel; - public boolean tree; - - public ParsedPermissionGroup parsedPermissionGroup; - - public void setName(String className) { - this.className = className; - } - - public void setGroup(String group) { - this.group = TextUtils.safeIntern(group); - } - - public String getGroup() { - return group; - } - - public boolean isRuntime() { - return getProtection() == PermissionInfo.PROTECTION_DANGEROUS; - } - - public boolean isAppOp() { - return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0; - } - - @PermissionInfo.Protection - public int getProtection() { - return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; - } - - public int getProtectionFlags() { - return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE; - } - - public int calculateFootprint() { - int size = getName().length(); - if (nonLocalizedLabel != null) { - size += nonLocalizedLabel.length(); - } - return size; - } - - public ParsedPermission() { - } - - public ParsedPermission(ParsedPermission other) { - // TODO(b/135203078): Better way to copy this? Maybe refactor to the point where copy - // isn't needed. - this.className = other.className; - this.icon = other.icon; - this.labelRes = other.labelRes; - this.nonLocalizedLabel = other.nonLocalizedLabel; - this.logo = other.logo; - this.banner = other.banner; - this.descriptionRes = other.descriptionRes; - this.enabled = other.enabled; - this.directBootAware = other.directBootAware; - this.flags = other.flags; - this.setSplitName(other.getSplitName()); - this.setPackageName(other.getPackageName()); - - this.intents.addAll(other.intents); - - if (other.metaData != null) { - this.metaData = new Bundle(); - this.metaData.putAll(other.metaData); - } - - this.backgroundPermission = other.backgroundPermission; - this.setGroup(other.group); - this.requestRes = other.requestRes; - this.protectionLevel = other.protectionLevel; - this.tree = other.tree; - - this.parsedPermissionGroup = other.parsedPermissionGroup; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(this.backgroundPermission); - dest.writeString(this.group); - dest.writeInt(this.requestRes); - dest.writeInt(this.protectionLevel); - dest.writeBoolean(this.tree); - dest.writeParcelable(this.parsedPermissionGroup, flags); - } - - protected ParsedPermission(Parcel in) { - super(in); - // We use the boot classloader for all classes that we load. - final ClassLoader boot = Object.class.getClassLoader(); - this.backgroundPermission = in.readString(); - this.group = TextUtils.safeIntern(in.readString()); - this.requestRes = in.readInt(); - this.protectionLevel = in.readInt(); - this.tree = in.readBoolean(); - this.parsedPermissionGroup = in.readParcelable(boot); - } - - public static final Creator<ParsedPermission> CREATOR = new Creator<ParsedPermission>() { - @Override - public ParsedPermission createFromParcel(Parcel source) { - return new ParsedPermission(source); - } - - @Override - public ParsedPermission[] newArray(int size) { - return new ParsedPermission[size]; - } - }; - } - - public static class ParsedPermissionGroup extends ParsedComponent<ParsedIntentInfo> { - - public int requestDetailResourceId; - public int backgroundRequestResourceId; - public int backgroundRequestDetailResourceId; - - public int requestRes; - public int priority; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(this.requestDetailResourceId); - dest.writeInt(this.backgroundRequestResourceId); - dest.writeInt(this.backgroundRequestDetailResourceId); - dest.writeInt(this.requestRes); - dest.writeInt(this.priority); - } - - public ParsedPermissionGroup() { - } - - protected ParsedPermissionGroup(Parcel in) { - super(in); - this.requestDetailResourceId = in.readInt(); - this.backgroundRequestResourceId = in.readInt(); - this.backgroundRequestDetailResourceId = in.readInt(); - this.requestRes = in.readInt(); - this.priority = in.readInt(); - } - - public static final Creator<ParsedPermissionGroup> CREATOR = - new Creator<ParsedPermissionGroup>() { - @Override - public ParsedPermissionGroup createFromParcel(Parcel source) { - return new ParsedPermissionGroup(source); - } - - @Override - public ParsedPermissionGroup[] newArray(int size) { - return new ParsedPermissionGroup[size]; - } - }; - } - - public static class ParsedInstrumentation extends ParsedComponent<ParsedIntentInfo> { - - private String targetPackage; - private String targetProcesses; - public boolean handleProfiling; - public boolean functionalTest; - - public ParsedInstrumentation() { - } - - public void setTargetPackage(String targetPackage) { - this.targetPackage = TextUtils.safeIntern(targetPackage); - } - - public String getTargetPackage() { - return targetPackage; - } - - public void setTargetProcesses(String targetProcesses) { - this.targetProcesses = TextUtils.safeIntern(targetProcesses); - } - - public String getTargetProcesses() { - return targetProcesses; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(this.targetPackage); - dest.writeString(this.targetProcesses); - dest.writeBoolean(this.handleProfiling); - dest.writeBoolean(this.functionalTest); - } - - protected ParsedInstrumentation(Parcel in) { - super(in); - this.targetPackage = TextUtils.safeIntern(in.readString()); - this.targetProcesses = TextUtils.safeIntern(in.readString()); - this.handleProfiling = in.readByte() != 0; - this.functionalTest = in.readByte() != 0; - } - - public static final Creator<ParsedInstrumentation> CREATOR = - new Creator<ParsedInstrumentation>() { - @Override - public ParsedInstrumentation createFromParcel(Parcel source) { - return new ParsedInstrumentation(source); - } - - @Override - public ParsedInstrumentation[] newArray(int size) { - return new ParsedInstrumentation[size]; - } - }; - } - - public static class ParsedProcess implements Parcelable { - - public String name; - @Nullable - public ArraySet<String> deniedPermissions; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(this.name); - final int numDenied = this.deniedPermissions != null - ? this.deniedPermissions.size() : 0; - dest.writeInt(numDenied); - for (int i = 0; i < numDenied; i++) { - dest.writeString(this.deniedPermissions.valueAt(i)); - } - } - - public ParsedProcess() { - } - - public ParsedProcess(@NonNull ParsedProcess other) { - name = other.name; - if (other.deniedPermissions != null) { - deniedPermissions = new ArraySet<>(other.deniedPermissions); - } - } - - public void addStateFrom(@NonNull ParsedProcess other) { - if (other.deniedPermissions != null) { - for (int i = other.deniedPermissions.size() - 1; i >= 0; i--) { - if (deniedPermissions == null) { - deniedPermissions = new ArraySet<>(other.deniedPermissions.size()); - } - deniedPermissions.add(other.deniedPermissions.valueAt(i)); - } - } - } - - protected ParsedProcess(Parcel in) { - this.name = TextUtils.safeIntern(in.readString()); - final int numDenied = in.readInt(); - if (numDenied > 0) { - this.deniedPermissions = new ArraySet<>(numDenied); - this.deniedPermissions.add(TextUtils.safeIntern(in.readString())); - } - } - - public static final Creator<ParsedProcess> CREATOR = - new Creator<ParsedProcess>() { - @Override - public ParsedProcess createFromParcel(Parcel source) { - return new ParsedProcess(source); - } - - @Override - public ParsedProcess[] newArray(int size) { - return new ParsedProcess[size]; - } - }; - } - - public static ParsedActivity parseActivity( - String[] separateProcesses, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, int flags, String[] outError, - boolean receiver, boolean hardwareAccelerated) - throws XmlPullParserException, IOException { - - TypedArray sa = null; - boolean visibleToEphemeral; - boolean setExported; - - int targetSdkVersion = parsingPackage.getTargetSdkVersion(); - String packageName = parsingPackage.getPackageName(); - String packageProcessName = parsingPackage.getProcessName(); - ParsedActivity result = new ParsedActivity(); - - try { - sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); - - String tag = receiver ? "<receiver>" : "<activity>"; - - String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_name, 0); - if (name == null) { - outError[0] = tag + " does not specify android:name"; - return null; - } else { - String className = ApkParseUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { - outError[0] = tag + " invalid android:name"; - return null; - } else if (className == null) { - outError[0] = "Empty class name in package " + packageName; - return null; - } - - result.className = className; - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( - R.styleable.AndroidManifestActivity_roundIcon, 0) : 0; - if (roundIconVal != 0) { - result.icon = roundIconVal; - result.nonLocalizedLabel = null; - } else { - int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivity_icon, 0); - if (iconVal != 0) { - result.icon = iconVal; - result.nonLocalizedLabel = null; - } - } - - int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivity_logo, 0); - if (logoVal != 0) { - result.logo = logoVal; - } - - int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivity_banner, 0); - if (bannerVal != 0) { - result.banner = bannerVal; - } - - TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivity_label); - if (v != null && (result.labelRes = v.resourceId) == 0) { - result.nonLocalizedLabel = v.coerceToString(); - } - - result.setPackageNameInternal(packageName); - - CharSequence pname; - if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { - pname = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_process, - Configuration.NATIVE_CONFIG_VERSION); - } else { - // Some older apps have been seen to use a resource reference - // here that on older builds was ignored (with a warning). We - // need to continue to do this for them so they don't break. - pname = sa.getNonResourceString(R.styleable.AndroidManifestActivity_process); - } - - result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName, - packageProcessName, pname, - flags, separateProcesses, outError)); - - result.descriptionRes = sa.getResourceId( - R.styleable.AndroidManifestActivity_description, 0); - - result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivity_enabled, true); - - setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported); - if (setExported) { - result.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, - false); - } - - result.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0); - - result.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, - parsingPackage.getUiOptions()); - - String parentName = sa.getNonConfigurationString( - R.styleable.AndroidManifestActivity_parentActivityName, - Configuration.NATIVE_CONFIG_VERSION); - if (parentName != null) { - String parentClassName = ApkParseUtils.buildClassName(packageName, parentName); - if (parentClassName == null) { - Log.e(TAG, - "Activity " + result.className - + " specified invalid parentActivityName " + - parentName); - } else { - result.parentActivityName = parentClassName; - } - } - - String str; - str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0); - if (str == null) { - result.setPermission(parsingPackage.getPermission()); - } else { - result.setPermission(str); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestActivity_taskAffinity, - Configuration.NATIVE_CONFIG_VERSION); - result.taskAffinity = PackageParser.buildTaskAffinityName( - packageName, - parsingPackage.getTaskAffinity(), str, outError); - - result.setSplitName( - sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0)); - - result.flags = 0; - if (sa.getBoolean( - R.styleable.AndroidManifestActivity_multiprocess, false)) { - result.flags |= ActivityInfo.FLAG_MULTIPROCESS; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) { - result.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) { - result.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) { - result.flags |= ActivityInfo.FLAG_NO_HISTORY; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) { - result.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) { - result.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) { - result.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting, - (parsingPackage.getFlags() & ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) - != 0)) { - result.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, - false)) { - result.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false) - || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) { - result.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) { - result.flags |= ActivityInfo.FLAG_IMMERSIVE; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) { - result.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY; - } - - boolean directBootAware; - - if (!receiver) { - if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated, - hardwareAccelerated)) { - result.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; - } - - result.launchMode = sa.getInt( - R.styleable.AndroidManifestActivity_launchMode, - ActivityInfo.LAUNCH_MULTIPLE); - result.documentLaunchMode = sa.getInt( - R.styleable.AndroidManifestActivity_documentLaunchMode, - ActivityInfo.DOCUMENT_LAUNCH_NONE); - result.maxRecents = sa.getInt( - R.styleable.AndroidManifestActivity_maxRecents, - ActivityTaskManager.getDefaultAppRecentsLimitStatic()); - result.configChanges = PackageParser.getActivityConfigChanges( - sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0), - sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0)); - result.softInputMode = sa.getInt( - R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); - - result.persistableMode = sa.getInteger( - R.styleable.AndroidManifestActivity_persistableMode, - ActivityInfo.PERSIST_ROOT_ONLY); - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) { - result.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, - false)) { - result.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, - false)) { - result.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) { - result.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING; - } - - int screenOrientation = sa.getInt( - R.styleable.AndroidManifestActivity_screenOrientation, - SCREEN_ORIENTATION_UNSPECIFIED); - result.screenOrientation = screenOrientation; - - int resizeMode = getActivityResizeMode(parsingPackage, sa, screenOrientation); - result.resizeMode = resizeMode; - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, - false)) { - result.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) { - result.flags |= FLAG_ALWAYS_FOCUSABLE; - } - - if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio) - && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio) - == TypedValue.TYPE_FLOAT) { - result.setMaxAspectRatio(resizeMode, - sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio, - 0 /*default*/)); - } - - if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio) - && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio) - == TypedValue.TYPE_FLOAT) { - result.setMinAspectRatio(resizeMode, - sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio, - 0 /*default*/)); - } - - result.lockTaskLaunchMode = - sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0); - - directBootAware = sa.getBoolean( - R.styleable.AndroidManifestActivity_directBootAware, - false); - - result.requestedVrComponent = - sa.getString(R.styleable.AndroidManifestActivity_enableVrMode); - - result.rotationAnimation = - sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, - ROTATION_ANIMATION_UNSPECIFIED); - - result.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, - ActivityInfo.COLOR_MODE_DEFAULT); - - result.preferMinimalPostProcessing = sa.getBoolean( - R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, - ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT); - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) { - result.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) { - result.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON; - } - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked, - false)) { - result.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED; - } - } else { - result.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - result.configChanges = 0; - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) { - result.flags |= ActivityInfo.FLAG_SINGLE_USER; - } - directBootAware = sa.getBoolean( - R.styleable.AndroidManifestActivity_directBootAware, - false); - } - - result.directBootAware = directBootAware; - - if (directBootAware) { - parsingPackage.setPartiallyDirectBootAware(true); - } - - // can't make this final; we may set it later via meta-data - visibleToEphemeral = sa.getBoolean( - R.styleable.AndroidManifestActivity_visibleToInstantApps, false); - if (visibleToEphemeral) { - result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; - parsingPackage.setVisibleToInstantApps(true); - } - } finally { - if (sa != null) { - sa.recycle(); - } - } - - - if (receiver && (parsingPackage.getPrivateFlags() - & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { - // A heavy-weight application can not have receives in its main process - if (result.getProcessName().equals(packageName)) { - outError[0] = "Heavy-weight applications can not have receivers in main process"; - return null; - } - } - - if (outError[0] != null) { - return null; - } - - int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - if (parser.getName().equals("intent-filter")) { - ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName, - result.className); - if (!parseIntentInfo(intentInfo, parsingPackage, res, parser, - true /*allowGlobs*/, - true /*allowAutoVerify*/, outError)) { - return null; - } - if (intentInfo.countActions() == 0) { - Slog.w(TAG, "No actions in intent filter at " - + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - } else { - result.order = Math.max(intentInfo.getOrder(), result.order); - result.addIntent(intentInfo); - } - // adjust activity flags when we implicitly expose it via a browsable filter - final int visibility = visibleToEphemeral - ? IntentFilter.VISIBILITY_EXPLICIT - : !receiver && isImplicitlyExposedIntent(intentInfo) - ? IntentFilter.VISIBILITY_IMPLICIT - : IntentFilter.VISIBILITY_NONE; - intentInfo.setVisibilityToInstantApp(visibility); - if (intentInfo.isVisibleToInstantApp()) { - result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; - } - if (intentInfo.isImplicitlyVisibleToInstantApp()) { - result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; - } - if (PackageParser.LOG_UNSAFE_BROADCASTS && receiver - && (targetSdkVersion >= Build.VERSION_CODES.O)) { - for (int i = 0; i < intentInfo.countActions(); i++) { - final String action = intentInfo.getAction(i); - if (action == null || !action.startsWith("android.")) continue; - if (!PackageParser.SAFE_BROADCASTS.contains(action)) { - Slog.w(TAG, "Broadcast " + action + " may never be delivered to " - + packageName + " as requested at: " - + parser.getPositionDescription()); - } - } - } - } else if (!receiver && parser.getName().equals("preferred")) { - ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName, - result.className); - if (!parseIntentInfo(intentInfo, parsingPackage, res, parser, - false /*allowGlobs*/, - false /*allowAutoVerify*/, outError)) { - return null; - } - // adjust activity flags when we implicitly expose it via a browsable filter - final int visibility = visibleToEphemeral - ? IntentFilter.VISIBILITY_EXPLICIT - : !receiver && isImplicitlyExposedIntent(intentInfo) - ? IntentFilter.VISIBILITY_IMPLICIT - : IntentFilter.VISIBILITY_NONE; - intentInfo.setVisibilityToInstantApp(visibility); - if (intentInfo.isVisibleToInstantApp()) { - result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; - } - if (intentInfo.isImplicitlyVisibleToInstantApp()) { - result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; - } - - if (intentInfo.countActions() == 0) { - Slog.w(TAG, "No actions in preferred at " - + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - } else { - parsingPackage.addPreferredActivityFilter(intentInfo); - } - } else if (parser.getName().equals("meta-data")) { - if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, - result.metaData, - outError)) == null) { - return null; - } - } else if (!receiver && parser.getName().equals("layout")) { - result.windowLayout = parseLayout(res, parser); - } else { - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "Problem in package " + parsingPackage.getBaseCodePath() + ":"); - if (receiver) { - Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - } else { - Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - } - XmlUtils.skipCurrentTag(parser); - continue; - } else { - if (receiver) { - outError[0] = "Bad element under <receiver>: " + parser.getName(); - } else { - outError[0] = "Bad element under <activity>: " + parser.getName(); - } - return null; - } - } - } - - if (!setExported) { - result.exported = result.intents.size() > 0; - } - - return result; - } - - public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) { - return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE) - || intentInfo.hasAction(Intent.ACTION_SEND) - || intentInfo.hasAction(Intent.ACTION_SENDTO) - || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE); - } - - public static int getActivityResizeMode( - ParsingPackage parsingPackage, - TypedArray sa, - int screenOrientation - ) { - int privateFlags = parsingPackage.getPrivateFlags(); - final boolean appExplicitDefault = (privateFlags - & (ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE - | ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0; - - if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity) - || appExplicitDefault) { - // Activity or app explicitly set if it is resizeable or not; - final boolean appResizeable = (privateFlags - & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0; - if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, - appResizeable)) { - return ActivityInfo.RESIZE_MODE_RESIZEABLE; - } else { - return ActivityInfo.RESIZE_MODE_UNRESIZEABLE; - } - } - - if ((privateFlags - & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) - != 0) { - // The activity or app didn't explicitly set the resizing option, however we want to - // make it resize due to the sdk version it is targeting. - return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; - } - - // resize preference isn't set and target sdk version doesn't support resizing apps by - // default. For the app to be resizeable if it isn't fixed orientation or immersive. - if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { - return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; - } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { - return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; - } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { - return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; - } else { - return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; - } - } - - public static ParsedService parseService( - String[] separateProcesses, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, int flags, String[] outError - ) throws XmlPullParserException, IOException { - TypedArray sa = null; - boolean visibleToEphemeral; - boolean setExported; - - String packageName = parsingPackage.getPackageName(); - String packageProcessName = parsingPackage.getProcessName(); - ParsedService result = new ParsedService(); - - try { - sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestService); - - String name = sa.getNonConfigurationString(R.styleable.AndroidManifestService_name, 0); - if (name == null) { - outError[0] = "<service> does not specify android:name"; - return null; - } else { - String className = ApkParseUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { - outError[0] = "<service> invalid android:name"; - return null; - } else if (className == null) { - outError[0] = "Empty class name in package " + packageName; - return null; - } - - result.className = className; - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( - R.styleable.AndroidManifestService_roundIcon, 0) : 0; - if (roundIconVal != 0) { - result.icon = roundIconVal; - result.nonLocalizedLabel = null; - } else { - int iconVal = sa.getResourceId(R.styleable.AndroidManifestService_icon, 0); - if (iconVal != 0) { - result.icon = iconVal; - result.nonLocalizedLabel = null; - } - } - - int logoVal = sa.getResourceId(R.styleable.AndroidManifestService_logo, 0); - if (logoVal != 0) { - result.logo = logoVal; - } - - int bannerVal = sa.getResourceId(R.styleable.AndroidManifestService_banner, 0); - if (bannerVal != 0) { - result.banner = bannerVal; - } - - TypedValue v = sa.peekValue(R.styleable.AndroidManifestService_label); - if (v != null && (result.labelRes = v.resourceId) == 0) { - result.nonLocalizedLabel = v.coerceToString(); - } - - result.setPackageNameInternal(packageName); - - CharSequence pname; - if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { - pname = sa.getNonConfigurationString(R.styleable.AndroidManifestService_process, - Configuration.NATIVE_CONFIG_VERSION); - } else { - // Some older apps have been seen to use a resource reference - // here that on older builds was ignored (with a warning). We - // need to continue to do this for them so they don't break. - pname = sa.getNonResourceString(R.styleable.AndroidManifestService_process); - } - - result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName, - packageProcessName, pname, - flags, separateProcesses, outError)); - - result.descriptionRes = sa.getResourceId( - R.styleable.AndroidManifestService_description, 0); - - result.enabled = sa.getBoolean(R.styleable.AndroidManifestService_enabled, true); - - setExported = sa.hasValue( - R.styleable.AndroidManifestService_exported); - if (setExported) { - result.exported = sa.getBoolean( - R.styleable.AndroidManifestService_exported, false); - } - - String str = sa.getNonConfigurationString( - R.styleable.AndroidManifestService_permission, 0); - if (str == null) { - result.setPermission(parsingPackage.getPermission()); - } else { - result.setPermission(str); - } - - result.setSplitName( - sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0)); - - result.foregroundServiceType = sa.getInt( - R.styleable.AndroidManifestService_foregroundServiceType, - ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE); - - result.flags = 0; - if (sa.getBoolean( - R.styleable.AndroidManifestService_stopWithTask, - false)) { - result.flags |= ServiceInfo.FLAG_STOP_WITH_TASK; - } - if (sa.getBoolean( - R.styleable.AndroidManifestService_isolatedProcess, - false)) { - result.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS; - } - if (sa.getBoolean( - R.styleable.AndroidManifestService_externalService, - false)) { - result.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE; - } - if (sa.getBoolean( - R.styleable.AndroidManifestService_useAppZygote, - false)) { - result.flags |= ServiceInfo.FLAG_USE_APP_ZYGOTE; - } - if (sa.getBoolean( - R.styleable.AndroidManifestService_singleUser, - false)) { - result.flags |= ServiceInfo.FLAG_SINGLE_USER; - } - - result.directBootAware = sa.getBoolean( - R.styleable.AndroidManifestService_directBootAware, - false); - if (result.directBootAware) { - parsingPackage.setPartiallyDirectBootAware(true); - } - - visibleToEphemeral = sa.getBoolean( - R.styleable.AndroidManifestService_visibleToInstantApps, false); - if (visibleToEphemeral) { - result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; - parsingPackage.setVisibleToInstantApps(true); - } - } finally { - if (sa != null) { - sa.recycle(); - } - } - - if (parsingPackage.cantSaveState()) { - // A heavy-weight application can not have services in its main process - // We can do direct compare because we intern all strings. - if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) { - outError[0] = "Heavy-weight applications can not have services in main process"; - return null; - } - } - - int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - if (parser.getName().equals("intent-filter")) { - ParsedServiceIntentInfo intent = new ParsedServiceIntentInfo(packageName, - result.className); - if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/, - false /*allowAutoVerify*/, - outError)) { - return null; - } - if (visibleToEphemeral) { - intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); - result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; - } - result.order = Math.max(intent.getOrder(), result.order); - result.intents.add(intent); - } else if (parser.getName().equals("meta-data")) { - if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, - result.metaData, - outError)) == null) { - return null; - } - } else { - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "Unknown element under <service>: " - + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } else { - outError[0] = "Bad element under <service>: " + parser.getName(); - return null; - } - } - } - - if (!setExported) { - result.exported = result.intents.size() > 0; - } - - return result; - } - - public static ParsedProvider parseProvider( - String[] separateProcesses, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, int flags, String[] outError) - throws XmlPullParserException, IOException { - TypedArray sa = null; - String cpname; - boolean visibleToEphemeral; - - int targetSdkVersion = parsingPackage.getTargetSdkVersion(); - String packageName = parsingPackage.getPackageName(); - String packageProcessName = parsingPackage.getProcessName(); - ParsedProvider result = new ParsedProvider(); - - try { - sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestProvider); - - String name = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_name, 0); - if (name == null) { - outError[0] = "<provider> does not specify android:name"; - return null; - } else { - String className = ApkParseUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { - outError[0] = "<provider> invalid android:name"; - return null; - } else if (className == null) { - outError[0] = "Empty class name in package " + packageName; - return null; - } - - result.className = className; - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( - R.styleable.AndroidManifestProvider_roundIcon, 0) : 0; - if (roundIconVal != 0) { - result.icon = roundIconVal; - result.nonLocalizedLabel = null; - } else { - int iconVal = sa.getResourceId(R.styleable.AndroidManifestProvider_icon, 0); - if (iconVal != 0) { - result.icon = iconVal; - result.nonLocalizedLabel = null; - } - } - - int logoVal = sa.getResourceId(R.styleable.AndroidManifestProvider_logo, 0); - if (logoVal != 0) { - result.logo = logoVal; - } - - int bannerVal = sa.getResourceId(R.styleable.AndroidManifestProvider_banner, 0); - if (bannerVal != 0) { - result.banner = bannerVal; - } - - TypedValue v = sa.peekValue(R.styleable.AndroidManifestProvider_label); - if (v != null && (result.labelRes = v.resourceId) == 0) { - result.nonLocalizedLabel = v.coerceToString(); - } - - result.setPackageNameInternal(packageName); - - CharSequence pname; - if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { - pname = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_process, - Configuration.NATIVE_CONFIG_VERSION); - } else { - // Some older apps have been seen to use a resource reference - // here that on older builds was ignored (with a warning). We - // need to continue to do this for them so they don't break. - pname = sa.getNonResourceString(R.styleable.AndroidManifestProvider_process); - } - - result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName, - packageProcessName, pname, - flags, separateProcesses, outError)); - - result.descriptionRes = sa.getResourceId( - R.styleable.AndroidManifestProvider_description, 0); - - result.enabled = sa.getBoolean(R.styleable.AndroidManifestProvider_enabled, true); - - boolean providerExportedDefault = false; - - if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { - // For compatibility, applications targeting API level 16 or lower - // should have their content providers exported by default, unless they - // specify otherwise. - providerExportedDefault = true; - } - - result.exported = sa.getBoolean( - R.styleable.AndroidManifestProvider_exported, - providerExportedDefault); - - cpname = sa.getNonConfigurationString( - R.styleable.AndroidManifestProvider_authorities, 0); - - result.isSyncable = sa.getBoolean( - R.styleable.AndroidManifestProvider_syncable, - false); - - String permission = sa.getNonConfigurationString( - R.styleable.AndroidManifestProvider_permission, 0); - String str = sa.getNonConfigurationString( - R.styleable.AndroidManifestProvider_readPermission, 0); - if (str == null) { - str = permission; - } - if (str == null) { - result.setReadPermission(parsingPackage.getPermission()); - } else { - result.setReadPermission(str); - } - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestProvider_writePermission, 0); - if (str == null) { - str = permission; - } - if (str == null) { - result.setWritePermission(parsingPackage.getPermission()); - } else { - result.setWritePermission(str); - } - - result.grantUriPermissions = sa.getBoolean( - R.styleable.AndroidManifestProvider_grantUriPermissions, - false); - - result.forceUriPermissions = sa.getBoolean( - R.styleable.AndroidManifestProvider_forceUriPermissions, - false); - - result.multiProcess = sa.getBoolean( - R.styleable.AndroidManifestProvider_multiprocess, - false); - - result.initOrder = sa.getInt( - R.styleable.AndroidManifestProvider_initOrder, - 0); - - result.setSplitName( - sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0)); - - result.flags = 0; - - if (sa.getBoolean( - R.styleable.AndroidManifestProvider_singleUser, - false)) { - result.flags |= ProviderInfo.FLAG_SINGLE_USER; - } - - result.directBootAware = sa.getBoolean( - R.styleable.AndroidManifestProvider_directBootAware, - false); - if (result.directBootAware) { - parsingPackage.setPartiallyDirectBootAware(true); - } - - visibleToEphemeral = - sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false); - if (visibleToEphemeral) { - result.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; - parsingPackage.setVisibleToInstantApps(true); - } - } finally { - if (sa != null) { - sa.recycle(); - } - } - - if ((parsingPackage.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) - != 0) { - // A heavy-weight application can not have providers in its main process - if (result.getProcessName().equals(packageName)) { - outError[0] = "Heavy-weight applications can not have providers in main process"; - return null; - } - } - - if (cpname == null) { - outError[0] = "<provider> does not include authorities attribute"; - return null; - } - if (cpname.length() <= 0) { - outError[0] = "<provider> has empty authorities attribute"; - return null; - } - result.setAuthority(cpname); - - if (!parseProviderTags(parsingPackage, res, parser, visibleToEphemeral, result, outError)) { - return null; - } - - return result; - } - - public static ParsedQueriesIntentInfo parsedParsedQueriesIntentInfo( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - String[] outError - ) throws IOException, XmlPullParserException { - ParsedQueriesIntentInfo intentInfo = new ParsedQueriesIntentInfo( - parsingPackage.getPackageName(), - null - ); - if (!parseIntentInfo( - intentInfo, - parsingPackage, - res, - parser, - true /*allowGlobs*/, - true /*allowAutoVerify*/, - outError - )) { - return null; - } - return intentInfo; - } - - private static boolean parseProviderTags( - ParsingPackage parsingPackage, - Resources res, XmlResourceParser parser, - boolean visibleToEphemeral, ParsedProvider outInfo, String[] outError) - throws XmlPullParserException, IOException { - int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - if (parser.getName().equals("intent-filter")) { - ParsedProviderIntentInfo intent = new ParsedProviderIntentInfo( - parsingPackage.getPackageName(), outInfo.className); - if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/, - false /*allowAutoVerify*/, - outError)) { - return false; - } - if (visibleToEphemeral) { - intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); - outInfo.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; - } - outInfo.order = Math.max(intent.getOrder(), outInfo.order); - outInfo.intents.add(intent); - - } else if (parser.getName().equals("meta-data")) { - Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, - outInfo.metaData, outError); - if (metaData == null) { - return false; - } else { - outInfo.metaData = metaData; - } - - } else if (parser.getName().equals("grant-uri-permission")) { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestGrantUriPermission); - - PatternMatcher pa = null; - - String str = sa.getNonConfigurationString( - R.styleable.AndroidManifestGrantUriPermission_path, 0); - if (str != null) { - pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); - if (str != null) { - pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); - if (str != null) { - pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); - } - - sa.recycle(); - - if (pa != null) { - if (outInfo.uriPermissionPatterns == null) { - outInfo.uriPermissionPatterns = new PatternMatcher[1]; - outInfo.uriPermissionPatterns[0] = pa; - } else { - final int N = outInfo.uriPermissionPatterns.length; - PatternMatcher[] newp = new PatternMatcher[N + 1]; - System.arraycopy(outInfo.uriPermissionPatterns, 0, newp, 0, N); - newp[N] = pa; - outInfo.uriPermissionPatterns = newp; - } - outInfo.grantUriPermissions = true; - } else { - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "Unknown element under <path-permission>: " - + parser.getName() + " at " + parsingPackage.getBaseCodePath() - + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } else { - outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; - return false; - } - } - XmlUtils.skipCurrentTag(parser); - - } else if (parser.getName().equals("path-permission")) { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestPathPermission); - - PathPermission pa = null; - - String permission = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_permission, 0); - String readPermission = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_readPermission, 0); - if (readPermission == null) { - readPermission = permission; - } - String writePermission = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_writePermission, 0); - if (writePermission == null) { - writePermission = permission; - } - - boolean havePerm = false; - if (readPermission != null) { - readPermission = readPermission.intern(); - havePerm = true; - } - if (writePermission != null) { - writePermission = writePermission.intern(); - havePerm = true; - } - - if (!havePerm) { - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: " - + parser.getName() + " at " + parsingPackage.getBaseCodePath() - + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } else { - outError[0] = "No readPermission or writePermssion for <path-permission>"; - return false; - } - } - - String path = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_path, 0); - if (path != null) { - pa = new PathPermission(path, - PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); - } - - path = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_pathPrefix, 0); - if (path != null) { - pa = new PathPermission(path, - PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); - } - - path = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_pathPattern, 0); - if (path != null) { - pa = new PathPermission(path, - PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); - } - - path = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0); - if (path != null) { - pa = new PathPermission(path, - PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission); - } - - sa.recycle(); - - if (pa != null) { - if (outInfo.pathPermissions == null) { - outInfo.pathPermissions = new PathPermission[1]; - outInfo.pathPermissions[0] = pa; - } else { - final int N = outInfo.pathPermissions.length; - PathPermission[] newp = new PathPermission[N + 1]; - System.arraycopy(outInfo.pathPermissions, 0, newp, 0, N); - newp[N] = pa; - outInfo.pathPermissions = newp; - } - } else { - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " - + parser.getName() + " at " + parsingPackage.getBaseCodePath() - + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; - return false; - } - XmlUtils.skipCurrentTag(parser); - - } else { - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "Unknown element under <provider>: " - + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } else { - outError[0] = "Bad element under <provider>: " + parser.getName(); - return false; - } - } - } - return true; - } - - public static ParsedActivity parseActivityAlias( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - String[] outError) - throws XmlPullParserException, IOException { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestActivityAlias); - - String targetActivity = sa.getNonConfigurationString( - R.styleable.AndroidManifestActivityAlias_targetActivity, - Configuration.NATIVE_CONFIG_VERSION); - if (targetActivity == null) { - outError[0] = "<activity-alias> does not specify android:targetActivity"; - sa.recycle(); - return null; - } - - String packageName = parsingPackage.getPackageName(); - targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity); - if (targetActivity == null) { - outError[0] = "Empty class name in package " + packageName; - sa.recycle(); - return null; - } - - ParsedActivity target = null; - - List<ParsedActivity> activities = parsingPackage.getActivities(); - final int NA = activities.size(); - for (int i = 0; i < NA; i++) { - ParsedActivity t = activities.get(i); - if (targetActivity.equals(t.className)) { - target = t; - break; - } - } - - if (target == null) { - outError[0] = "<activity-alias> target activity " + targetActivity - + " not found in manifest with activities = " + parsingPackage.getActivities() - + ", parsedActivities = " + activities; - sa.recycle(); - return null; - } - - ParsedActivity result = new ParsedActivity(); - result.setPackageNameInternal(target.getPackageName()); - result.targetActivity = targetActivity; - result.configChanges = target.configChanges; - result.flags = target.flags; - result.privateFlags = target.privateFlags; - result.icon = target.icon; - result.logo = target.logo; - result.banner = target.banner; - result.labelRes = target.labelRes; - result.nonLocalizedLabel = target.nonLocalizedLabel; - result.launchMode = target.launchMode; - result.lockTaskLaunchMode = target.lockTaskLaunchMode; - result.descriptionRes = target.descriptionRes; - result.screenOrientation = target.screenOrientation; - result.taskAffinity = target.taskAffinity; - result.theme = target.theme; - result.softInputMode = target.softInputMode; - result.uiOptions = target.uiOptions; - result.parentActivityName = target.parentActivityName; - result.maxRecents = target.maxRecents; - result.windowLayout = target.windowLayout; - result.resizeMode = target.resizeMode; - result.maxAspectRatio = target.maxAspectRatio; - result.hasMaxAspectRatio = target.hasMaxAspectRatio; - result.minAspectRatio = target.minAspectRatio; - result.hasMinAspectRatio = target.hasMinAspectRatio; - result.requestedVrComponent = target.requestedVrComponent; - result.directBootAware = target.directBootAware; - - result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName()); - - // Not all attributes from the target ParsedActivity are copied to the alias. - // Careful when adding an attribute and determine whether or not it should be copied. -// result.enabled = target.enabled; -// result.exported = target.exported; -// result.permission = target.permission; -// result.splitName = target.splitName; -// result.documentLaunchMode = target.documentLaunchMode; -// result.persistableMode = target.persistableMode; -// result.rotationAnimation = target.rotationAnimation; -// result.colorMode = target.colorMode; -// result.intents.addAll(target.intents); -// result.order = target.order; -// result.metaData = target.metaData; - - String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivityAlias_name, - 0); - if (name == null) { - outError[0] = "<activity-alias> does not specify android:name"; - return null; - } else { - String className = ApkParseUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { - outError[0] = "<activity-alias> invalid android:name"; - return null; - } else if (className == null) { - outError[0] = "Empty class name in package " + packageName; - return null; - } - - result.className = className; - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( - R.styleable.AndroidManifestActivityAlias_roundIcon, 0) : 0; - if (roundIconVal != 0) { - result.icon = roundIconVal; - result.nonLocalizedLabel = null; - } else { - int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_icon, 0); - if (iconVal != 0) { - result.icon = iconVal; - result.nonLocalizedLabel = null; - } - } - - int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_logo, 0); - if (logoVal != 0) { - result.logo = logoVal; - } - - int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_banner, 0); - if (bannerVal != 0) { - result.banner = bannerVal; - } - - TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivityAlias_label); - if (v != null && (result.labelRes = v.resourceId) == 0) { - result.nonLocalizedLabel = v.coerceToString(); - } - - result.setPackageNameInternal(packageName); - - result.descriptionRes = sa.getResourceId( - R.styleable.AndroidManifestActivityAlias_description, 0); - - result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivityAlias_enabled, true); - - final boolean setExported = sa.hasValue( - R.styleable.AndroidManifestActivityAlias_exported); - if (setExported) { - result.exported = sa.getBoolean( - R.styleable.AndroidManifestActivityAlias_exported, false); - } - - String str; - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestActivityAlias_permission, 0); - if (str != null) { - result.setPermission(str); - } - - String parentName = sa.getNonConfigurationString( - R.styleable.AndroidManifestActivityAlias_parentActivityName, - Configuration.NATIVE_CONFIG_VERSION); - if (parentName != null) { - String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(), - parentName); - if (parentClassName == null) { - Log.e(TAG, "Activity alias " + result.className + - " specified invalid parentActivityName " + parentName); - outError[0] = null; - } else { - result.parentActivityName = parentClassName; - } - } - - // TODO add visibleToInstantApps attribute to activity alias - final boolean visibleToEphemeral = - ((result.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0); - - sa.recycle(); - - if (outError[0] != null) { - return null; - } - - int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("intent-filter")) { - ParsedActivityIntentInfo intent = new ParsedActivityIntentInfo(packageName, - result.className); - if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/, - true /*allowAutoVerify*/, outError)) { - return null; - } - if (intent.countActions() == 0) { - Slog.w(TAG, "No actions in intent filter at " - + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - } else { - result.order = Math.max(intent.getOrder(), result.order); - result.addIntent(intent); - } - // adjust activity flags when we implicitly expose it via a browsable filter - final int visibility = visibleToEphemeral - ? IntentFilter.VISIBILITY_EXPLICIT - : isImplicitlyExposedIntent(intent) - ? IntentFilter.VISIBILITY_IMPLICIT - : IntentFilter.VISIBILITY_NONE; - intent.setVisibilityToInstantApp(visibility); - if (intent.isVisibleToInstantApp()) { - result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; - } - if (intent.isImplicitlyVisibleToInstantApp()) { - result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; - } - } else if (tagName.equals("meta-data")) { - if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, - result.metaData, - outError)) == null) { - return null; - } - } else { - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "Unknown element under <activity-alias>: " + tagName - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } else { - outError[0] = "Bad element under <activity-alias>: " + tagName; - return null; - } - } - } - - if (!setExported) { - result.exported = result.intents.size() > 0; - } - - return result; - } - - public static ParsedFeature parseFeature( - Resources res, - XmlResourceParser parser, - String[] outError - ) throws IOException, XmlPullParserException { - String featureId; - int label; - List<String> inheritFrom = null; - - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature); - if (sa == null) { - outError[0] = "<feature> could not be parsed"; - return null; - } - - try { - featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId, - 0); - if (featureId == null) { - outError[0] = "<featureId> does not specify android:featureId"; - return null; - } - if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) { - outError[0] = "<featureId> is too long. Max length is " - + ParsedFeature.MAX_FEATURE_ID_LEN; - return null; - } - - label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0); - if (label == Resources.ID_NULL) { - outError[0] = "<featureId> does not specify android:label"; - return null; - } - } finally { - sa.recycle(); - } - - int type; - final int innerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("inherit-from")) { - sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom); - if (sa == null) { - outError[0] = "<inherit-from> could not be parsed"; - return null; - } - - try { - String inheritFromId = sa.getNonConfigurationString( - R.styleable.AndroidManifestFeatureInheritFrom_featureId,0); - - if (inheritFrom == null) { - inheritFrom = new ArrayList<>(); - } - inheritFrom.add(inheritFromId); - } finally { - sa.recycle(); - } - } else { - outError[0] = "Bad element under <feature>: " + tagName; - return null; - } - } - - if (inheritFrom == null) { - inheritFrom = Collections.emptyList(); - } else { - ((ArrayList) inheritFrom).trimToSize(); - } - - return new ParsedFeature(featureId, label, inheritFrom); - } - - public static ParsedPermission parsePermission( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - String[] outError - ) throws IOException, XmlPullParserException { - TypedArray sa = null; - String packageName = parsingPackage.getPackageName(); - ParsedPermission result = new ParsedPermission(); - - try { - sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission); - - String name = sa.getNonConfigurationString(R.styleable.AndroidManifestPermission_name, - 0); - if (name == null) { - outError[0] = "<permission> does not specify android:name"; - return null; - } else { - String className = ApkParseUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { - outError[0] = "<permission> invalid android:name"; - return null; - } else if (className == null) { - outError[0] = "Empty class name in package " + packageName; - return null; - } - - result.className = className; - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( - R.styleable.AndroidManifestPermission_roundIcon, 0) : 0; - if (roundIconVal != 0) { - result.icon = roundIconVal; - result.nonLocalizedLabel = null; - } else { - int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermission_icon, 0); - if (iconVal != 0) { - result.icon = iconVal; - result.nonLocalizedLabel = null; - } - } - - int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermission_logo, 0); - if (logoVal != 0) { - result.logo = logoVal; - } - - int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermission_banner, 0); - if (bannerVal != 0) { - result.banner = bannerVal; - } - - TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermission_label); - if (v != null && (result.labelRes = v.resourceId) == 0) { - result.nonLocalizedLabel = v.coerceToString(); - } - - result.setPackageNameInternal(packageName); - - result.descriptionRes = sa.getResourceId( - R.styleable.AndroidManifestPermission_description, 0); - - if (sa.hasValue( - R.styleable.AndroidManifestPermission_backgroundPermission)) { - if ("android".equals(packageName)) { - result.backgroundPermission = sa.getNonResourceString( - R.styleable - .AndroidManifestPermission_backgroundPermission); - } else { - Slog.w(TAG, packageName + " defines a background permission. Only the " - + "'android' package can do that."); - } - } - - // Note: don't allow this value to be a reference to a resource - // that may change. - result.setGroup(sa.getNonResourceString( - R.styleable.AndroidManifestPermission_permissionGroup)); - - result.requestRes = sa.getResourceId( - R.styleable.AndroidManifestPermission_request, 0); - - result.protectionLevel = sa.getInt( - R.styleable.AndroidManifestPermission_protectionLevel, - PermissionInfo.PROTECTION_NORMAL); - - result.flags = sa.getInt( - R.styleable.AndroidManifestPermission_permissionFlags, 0); - - // For now only platform runtime permissions can be restricted - if (!result.isRuntime() || !"android".equals(result.getPackageName())) { - result.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED; - result.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED; - } else { - // The platform does not get to specify conflicting permissions - if ((result.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0 - && (result.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) { - throw new IllegalStateException("Permission cannot be both soft and hard" - + " restricted: " + result.getName()); - } - } - - } finally { - if (sa != null) { - sa.recycle(); - } - } - - if (result.protectionLevel == -1) { - outError[0] = "<permission> does not specify protectionLevel"; - return null; - } - - result.protectionLevel = PermissionInfo.fixProtectionLevel(result.protectionLevel); - - if (result.getProtectionFlags() != 0) { - if ((result.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0 - && (result.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) - == 0 - && (result.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) != - PermissionInfo.PROTECTION_SIGNATURE) { - outError[0] = "<permission> protectionLevel specifies a non-instant flag but is " - + "not based on signature type"; - return null; - } - } - - boolean success = parseAllMetaData(parsingPackage, res, parser, - "<permission>", result, outError); - if (!success || outError[0] != null) { - return null; - } - - return result; - } - - public static ParsedPermission parsePermissionTree( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - String[] outError - ) throws IOException, XmlPullParserException { - TypedArray sa = null; - String packageName = parsingPackage.getPackageName(); - ParsedPermission result = new ParsedPermission(); - - try { - sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree); - - String name = sa.getNonConfigurationString( - R.styleable.AndroidManifestPermissionTree_name, 0); - if (name == null) { - outError[0] = "<permission-tree> does not specify android:name"; - return null; - } else { - String className = ApkParseUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { - outError[0] = "<permission-tree> invalid android:name"; - return null; - } else if (className == null) { - outError[0] = "Empty class name in package " + packageName; - return null; - } - - result.className = className; - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( - R.styleable.AndroidManifestPermissionTree_roundIcon, 0) : 0; - if (roundIconVal != 0) { - result.icon = roundIconVal; - result.nonLocalizedLabel = null; - } else { - int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_icon, 0); - if (iconVal != 0) { - result.icon = iconVal; - result.nonLocalizedLabel = null; - } - } - - int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_logo, 0); - if (logoVal != 0) { - result.logo = logoVal; - } - - int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_banner, 0); - if (bannerVal != 0) { - result.banner = bannerVal; - } - - TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionTree_label); - if (v != null && (result.labelRes = v.resourceId) == 0) { - result.nonLocalizedLabel = v.coerceToString(); - } - - result.setPackageNameInternal(packageName); - } finally { - if (sa != null) { - sa.recycle(); - } - } - - int index = result.getName().indexOf('.'); - if (index > 0) { - index = result.getName().indexOf('.', index + 1); - } - if (index < 0) { - outError[0] = - "<permission-tree> name has less than three segments: " + result.getName(); - return null; - } - - result.descriptionRes = 0; - result.requestRes = 0; - result.protectionLevel = PermissionInfo.PROTECTION_NORMAL; - result.tree = true; - - boolean success = parseAllMetaData(parsingPackage, res, parser, - "<permission-tree>", result, outError); - if (!success || outError[0] != null) { - return null; - } - - return result; - } - - public static ParsedPermissionGroup parsePermissionGroup( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - String[] outError - ) throws IOException, XmlPullParserException { - TypedArray sa = null; - String packageName = parsingPackage.getPackageName(); - ParsedPermissionGroup result = new ParsedPermissionGroup(); - - try { - sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup); - - String name = sa.getNonConfigurationString( - R.styleable.AndroidManifestPermissionGroup_name, 0); - if (name == null) { - outError[0] = "<permission> does not specify android:name"; - return null; - } else { - String className = ApkParseUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { - outError[0] = "<permission> invalid android:name"; - return null; - } else if (className == null) { - outError[0] = "Empty class name in package " + packageName; - return null; - } - - result.className = className; - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( - R.styleable.AndroidManifestPermissionGroup_roundIcon, 0) : 0; - if (roundIconVal != 0) { - result.icon = roundIconVal; - result.nonLocalizedLabel = null; - } else { - int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_icon, 0); - if (iconVal != 0) { - result.icon = iconVal; - result.nonLocalizedLabel = null; - } - } - - int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_logo, 0); - if (logoVal != 0) { - result.logo = logoVal; - } - - int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_banner, 0); - if (bannerVal != 0) { - result.banner = bannerVal; - } - - TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionGroup_label); - if (v != null && (result.labelRes = v.resourceId) == 0) { - result.nonLocalizedLabel = v.coerceToString(); - } - - result.setPackageNameInternal(packageName); - - result.descriptionRes = sa.getResourceId( - R.styleable.AndroidManifestPermissionGroup_description, 0); - - result.requestDetailResourceId = sa.getResourceId( - R.styleable.AndroidManifestPermissionGroup_requestDetail, 0); - result.backgroundRequestResourceId = sa.getResourceId( - R.styleable.AndroidManifestPermissionGroup_backgroundRequest, - 0); - result.backgroundRequestDetailResourceId = sa.getResourceId( - R.styleable - .AndroidManifestPermissionGroup_backgroundRequestDetail, 0); - - result.requestRes = sa.getResourceId( - R.styleable.AndroidManifestPermissionGroup_request, 0); - result.flags = sa.getInt( - R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, - 0); - result.priority = sa.getInt( - R.styleable.AndroidManifestPermissionGroup_priority, 0); - - } finally { - if (sa != null) { - sa.recycle(); - } - } - - boolean success = parseAllMetaData(parsingPackage, res, parser, - "<permission-group>", result, outError); - if (!success || outError[0] != null) { - return null; - } - - return result; - } - - public static ParsedInstrumentation parseInstrumentation( - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - String[] outError - ) throws IOException, XmlPullParserException { - TypedArray sa = null; - String packageName = parsingPackage.getPackageName(); - ParsedInstrumentation result = new ParsedInstrumentation(); - - try { - sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation); - - // TODO(b/135203078): Re-share all of the configuration for this. ParseComponentArgs was - // un-used for this, but can be adjusted and re-added to share all the initial result - // parsing for icon/logo/name/etc in all of these parse methods. - String name = sa.getNonConfigurationString( - R.styleable.AndroidManifestInstrumentation_name, 0); - if (name == null) { - outError[0] = "<instrumentation> does not specify android:name"; - return null; - } else { - String className = ApkParseUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { - outError[0] = "<instrumentation> invalid android:name"; - return null; - } else if (className == null) { - outError[0] = "Empty class name in package " + packageName; - return null; - } - - result.className = className; - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( - R.styleable.AndroidManifestInstrumentation_roundIcon, 0) : 0; - if (roundIconVal != 0) { - result.icon = roundIconVal; - result.nonLocalizedLabel = null; - } else { - int iconVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_icon, 0); - if (iconVal != 0) { - result.icon = iconVal; - result.nonLocalizedLabel = null; - } - } - - int logoVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_logo, 0); - if (logoVal != 0) { - result.logo = logoVal; - } - - int bannerVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_banner, 0); - if (bannerVal != 0) { - result.banner = bannerVal; - } - - TypedValue v = sa.peekValue(R.styleable.AndroidManifestInstrumentation_label); - if (v != null && (result.labelRes = v.resourceId) == 0) { - result.nonLocalizedLabel = v.coerceToString(); - } - - result.setPackageNameInternal(packageName); - - String str; - // Note: don't allow this value to be a reference to a resource - // that may change. - str = sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage); - result.setTargetPackage(str); - - str = sa.getNonResourceString( - R.styleable.AndroidManifestInstrumentation_targetProcesses); - result.setTargetProcesses(str); - result.handleProfiling = sa.getBoolean( - R.styleable.AndroidManifestInstrumentation_handleProfiling, false); - result.functionalTest = sa.getBoolean( - R.styleable.AndroidManifestInstrumentation_functionalTest, false); - - } finally { - if (sa != null) { - sa.recycle(); - } - } - - boolean success = parseAllMetaData(parsingPackage, res, parser, - "<instrumentation>", result, outError); - if (!success || outError[0] != null) { - return null; - } - - return result; - } - - private static @Nullable ArraySet<String> parseDenyPermission( - ArraySet<String> perms, - Resources res, - XmlResourceParser parser, - String[] outError - ) throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestDenyPermission); - if (sa == null) { - outError[0] = "<deny-permission> could not be parsed"; - return null; - } - - try { - String perm = sa.getNonConfigurationString( - R.styleable.AndroidManifestDenyPermission_name,0); - if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) { - if (perms == null) { - perms = new ArraySet<>(); - } - perms.add(perm); - } - } finally { - sa.recycle(); - } - XmlUtils.skipCurrentTag(parser); - return perms; - } - - private static ArraySet<String> parseAllowPermission( - ArraySet<String> perms, - Resources res, - XmlResourceParser parser, - String[] outError - ) throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAllowPermission); - if (sa == null) { - outError[0] = "<allow-permission> could not be parsed"; - return null; - } - - try { - String perm = sa.getNonConfigurationString( - R.styleable.AndroidManifestAllowPermission_name,0); - if (perm != null && perm.equals(android.Manifest.permission.INTERNET) - && perms != null) { - perms.remove(perm); - if (perms.size() <= 0) { - perms = null; - } - } - } finally { - sa.recycle(); - } - XmlUtils.skipCurrentTag(parser); - return perms; - } - - public static ParsedProcess parseProcess( - ArraySet<String> perms, - String[] separateProcesses, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - int flags, - String[] outError - ) throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess); - if (sa == null) { - outError[0] = "<process> could not be parsed"; - return null; - } - - ParsedProcess proc = new ParsedProcess(); - if (perms != null) { - proc.deniedPermissions = new ArraySet(perms); - } - - try { - proc.name = sa.getNonConfigurationString( - R.styleable.AndroidManifestProcess_process,0); - proc.name = PackageParser.buildProcessName(parsingPackage.getPackageName(), - parsingPackage.getPackageName(), proc.name, flags, separateProcesses, outError); - if (outError[0] != null) { - return null; - } - if (proc.name == null || proc.name.length() <= 0) { - outError[0] = "<process> does not specify android:process"; - return null; - } - } finally { - sa.recycle(); - } - - int type; - final int innerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("deny-permission")) { - proc.deniedPermissions = parseDenyPermission(proc.deniedPermissions, res, parser, - outError); - if (outError[0] != null) { - return null; - } - } else if (tagName.equals("allow-permission")) { - proc.deniedPermissions = parseAllowPermission(proc.deniedPermissions, res, parser, - outError); - if (outError[0] != null) { - return null; - } - } else { - Slog.w(TAG, "Unknown element under <process>: " + tagName - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - } - - return proc; - } - - public static ArrayMap<String, ParsedProcess> parseProcesses( - String[] separateProcesses, - ParsingPackage parsingPackage, - Resources res, - XmlResourceParser parser, - int flags, - String[] outError - ) throws IOException, XmlPullParserException { - ArraySet<String> deniedPerms = null; - ArrayMap<String, ParsedProcess> processes = new ArrayMap<>(); - - int type; - final int innerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("deny-permission")) { - deniedPerms = parseDenyPermission(deniedPerms, res, parser, outError); - if (outError[0] != null) { - return null; - } - } else if (tagName.equals("allow-permission")) { - deniedPerms = parseAllowPermission(deniedPerms, res, parser, outError); - if (outError[0] != null) { - return null; - } - } else if (tagName.equals("process")) { - ParsedProcess proc = parseProcess(deniedPerms, separateProcesses, parsingPackage, - res, parser, flags, outError); - if (outError[0] != null) { - return null; - } - if (processes.get(proc.name) != null) { - outError[0] = "<process> specified existing name '" + proc.name + "'"; - return null; - } - processes.put(proc.name, proc); - } else { - Slog.w(TAG, "Unknown element under <processes>: " + tagName - + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - } - - return processes; - } - - public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) { - TypedArray sw = res.obtainAttributes(attrs, - R.styleable.AndroidManifestLayout); - int width = -1; - float widthFraction = -1f; - int height = -1; - float heightFraction = -1f; - final int widthType = sw.getType( - R.styleable.AndroidManifestLayout_defaultWidth); - if (widthType == TypedValue.TYPE_FRACTION) { - widthFraction = sw.getFraction( - R.styleable.AndroidManifestLayout_defaultWidth, - 1, 1, -1); - } else if (widthType == TypedValue.TYPE_DIMENSION) { - width = sw.getDimensionPixelSize( - R.styleable.AndroidManifestLayout_defaultWidth, - -1); - } - final int heightType = sw.getType( - R.styleable.AndroidManifestLayout_defaultHeight); - if (heightType == TypedValue.TYPE_FRACTION) { - heightFraction = sw.getFraction( - R.styleable.AndroidManifestLayout_defaultHeight, - 1, 1, -1); - } else if (heightType == TypedValue.TYPE_DIMENSION) { - height = sw.getDimensionPixelSize( - R.styleable.AndroidManifestLayout_defaultHeight, - -1); - } - int gravity = sw.getInt( - R.styleable.AndroidManifestLayout_gravity, - Gravity.CENTER); - int minWidth = sw.getDimensionPixelSize( - R.styleable.AndroidManifestLayout_minWidth, - -1); - int minHeight = sw.getDimensionPixelSize( - R.styleable.AndroidManifestLayout_minHeight, - -1); - sw.recycle(); - return new ActivityInfo.WindowLayout(width, widthFraction, - height, heightFraction, gravity, minWidth, minHeight); - } - - public static boolean parseIntentInfo( - ParsedIntentInfo intentInfo, - ParsingPackage parsingPackage, - Resources res, XmlResourceParser parser, boolean allowGlobs, - boolean allowAutoVerify, String[] outError - ) throws XmlPullParserException, IOException { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestIntentFilter); - - int priority = sa.getInt( - R.styleable.AndroidManifestIntentFilter_priority, 0); - intentInfo.setPriority(priority); - - int order = sa.getInt( - R.styleable.AndroidManifestIntentFilter_order, 0); - intentInfo.setOrder(order); - - TypedValue v = sa.peekValue( - R.styleable.AndroidManifestIntentFilter_label); - if (v != null && (intentInfo.labelRes = v.resourceId) == 0) { - intentInfo.nonLocalizedLabel = v.coerceToString(); - } - - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( - R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0; - if (roundIconVal != 0) { - intentInfo.icon = roundIconVal; - } else { - intentInfo.icon = sa.getResourceId( - R.styleable.AndroidManifestIntentFilter_icon, 0); - } - - if (allowAutoVerify) { - intentInfo.setAutoVerify(sa.getBoolean( - R.styleable.AndroidManifestIntentFilter_autoVerify, - false)); - } - - sa.recycle(); - - int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - String nodeName = parser.getName(); - if (nodeName.equals("action")) { - String value = parser.getAttributeValue( - PackageParser.ANDROID_RESOURCES, "name"); - if (TextUtils.isEmpty(value)) { - outError[0] = "No value supplied for <android:name>"; - return false; - } - XmlUtils.skipCurrentTag(parser); - - intentInfo.addAction(value); - } else if (nodeName.equals("category")) { - String value = parser.getAttributeValue( - PackageParser.ANDROID_RESOURCES, "name"); - if (TextUtils.isEmpty(value)) { - outError[0] = "No value supplied for <android:name>"; - return false; - } - XmlUtils.skipCurrentTag(parser); - - intentInfo.addCategory(value); - - } else if (nodeName.equals("data")) { - sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestData); - - String str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_mimeType, 0); - if (str != null) { - try { - intentInfo.addRawDataType(str); - } catch (IntentFilter.MalformedMimeTypeException e) { - outError[0] = e.toString(); - sa.recycle(); - return false; - } - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_mimeGroup, 0); - if (str != null) { - intentInfo.addMimeGroup(str); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_scheme, 0); - if (str != null) { - intentInfo.addDataScheme(str); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_ssp, 0); - if (str != null) { - intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_sspPrefix, 0); - if (str != null) { - intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_sspPattern, 0); - if (str != null) { - if (!allowGlobs) { - outError[0] = "sspPattern not allowed here; ssp must be literal"; - return false; - } - intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB); - } - - String host = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_host, 0); - String port = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_port, 0); - if (host != null) { - intentInfo.addDataAuthority(host, port); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_path, 0); - if (str != null) { - intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_pathPrefix, 0); - if (str != null) { - intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_pathPattern, 0); - if (str != null) { - if (!allowGlobs) { - outError[0] = "pathPattern not allowed here; path must be literal"; - return false; - } - intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_pathAdvancedPattern, 0); - if (str != null) { - if (!allowGlobs) { - outError[0] = "pathAdvancedPattern not allowed here; path must be literal"; - return false; - } - intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB); - } - - sa.recycle(); - XmlUtils.skipCurrentTag(parser); - } else if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "Unknown element under <intent-filter>: " - + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - } else { - outError[0] = "Bad element under <intent-filter>: " + parser.getName(); - return false; - } - } - - intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT); - - if (PackageParser.DEBUG_PARSER) { - final StringBuilder cats = new StringBuilder("Intent d="); - cats.append(intentInfo.hasDefault); - cats.append(", cat="); - - final Iterator<String> it = intentInfo.categoriesIterator(); - if (it != null) { - while (it.hasNext()) { - cats.append(' '); - cats.append(it.next()); - } - } - Slog.d(TAG, cats.toString()); - } - - return true; - } - - private static boolean parseAllMetaData( - ParsingPackage parsingPackage, - Resources res, XmlResourceParser parser, String tag, - ParsedComponent outInfo, - String[] outError - ) throws XmlPullParserException, IOException { - int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - if (parser.getName().equals("meta-data")) { - if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, - outInfo.metaData, outError)) == null) { - return false; - } - } else { - if (!PackageParser.RIGID_PARSER) { - Slog.w(TAG, "Unknown element under " + tag + ": " - + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } else { - outError[0] = "Bad element under " + tag + ": " + parser.getName(); - } - } - } - - return true; - } - - public static boolean isImplicitlyExposedIntent(IntentFilter intent) { - return intent.hasCategory(Intent.CATEGORY_BROWSABLE) - || intent.hasAction(Intent.ACTION_SEND) - || intent.hasAction(Intent.ACTION_SENDTO) - || intent.hasAction(Intent.ACTION_SEND_MULTIPLE); - } -} diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java deleted file mode 100644 index d06865b65f2d..000000000000 --- a/core/java/android/content/pm/parsing/PackageImpl.java +++ /dev/null @@ -1,3379 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package android.content.pm.parsing; - -import static android.os.Build.VERSION_CODES.DONUT; - -import static java.util.Collections.emptyMap; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.ConfigurationInfo; -import android.content.pm.FeatureGroupInfo; -import android.content.pm.FeatureInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.content.pm.ProviderInfo; -import android.content.pm.ServiceInfo; -import android.content.pm.SharedLibraryInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; -import android.content.pm.parsing.ComponentParseUtils.ParsedFeature; -import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; -import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; -import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; -import android.content.pm.parsing.ComponentParseUtils.ParsedService; -import android.content.res.TypedArray; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.os.Parcel; -import android.os.UserHandle; -import android.os.storage.StorageManager; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.SparseArray; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.CollectionUtils; -import com.android.server.SystemConfig; - -import java.security.PublicKey; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -/** - * The backing data for a package that was parsed from disk. - * - * TODO(b/135203078): Convert Lists used as sets into Sets, to better express intended use case - * TODO(b/135203078): Field nullability annotations - * TODO(b/135203078): Convert = 1 fields into Booleans - * TODO(b/135203078): Make all lists nullable and Collections.unmodifiable immutable when returned. - * Prefer add/set methods if adding is necessary. - * TODO(b/135203078): Consider comments to disable auto-format and single-line, single-space all the - * get/set methods to make this class far more compact. Maybe even separate some logic into parent - * classes, assuming there is no overhead. - * TODO(b/135203078): Copy documentation from PackageParser#Package for the relevant fields included - * here. Should clarify and clean up any differences. Also consider renames if it helps make - * things clearer. - * TODO(b/135203078): Intern all possibl e String values? Initial refactor just mirrored old - * behavior. - * - * @hide - */ -public final class PackageImpl implements ParsingPackage, ParsedPackage, AndroidPackage, - AndroidPackageWrite { - - private static final String TAG = "PackageImpl"; - - // Resource boolean are -1, so 1 means we don't know the value. - private int supportsSmallScreens = 1; - private int supportsNormalScreens = 1; - private int supportsLargeScreens = 1; - private int supportsXLargeScreens = 1; - private int resizeable = 1; - private int anyDensity = 1; - - private long[] lastPackageUsageTimeInMills = - new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT]; - - private int versionCode; - private int versionCodeMajor; - private int baseRevisionCode; - private String versionName; - - private boolean coreApp; - private int compileSdkVersion; - private String compileSdkVersionCodename; - - private String packageName; - private String realPackage; - private String manifestPackageName; - private String baseCodePath; - - private boolean requiredForAllUsers; - private String restrictedAccountType; - private String requiredAccountType; - - private boolean baseHardwareAccelerated; - - private String overlayTarget; - private String overlayTargetName; - private String overlayCategory; - private int overlayPriority; - private boolean overlayIsStatic; - private Map<String, String> overlayables = emptyMap(); - - private String staticSharedLibName; - private long staticSharedLibVersion; - private ArrayList<String> libraryNames; - private ArrayList<String> usesLibraries; - private ArrayList<String> usesOptionalLibraries; - - private ArrayList<String> usesStaticLibraries; - private long[] usesStaticLibrariesVersions; - private String[][] usesStaticLibrariesCertDigests; - - private String sharedUserId; - - private int sharedUserLabel; - private ArrayList<ConfigurationInfo> configPreferences; - private ArrayList<FeatureInfo> reqFeatures; - private ArrayList<FeatureGroupInfo> featureGroups; - - private byte[] restrictUpdateHash; - - private ArrayList<String> originalPackages; - private ArrayList<String> adoptPermissions; - - private ArrayList<String> requestedPermissions; - private ArrayList<String> implicitPermissions; - - private ArraySet<String> upgradeKeySets; - private Map<String, ArraySet<PublicKey>> keySetMapping; - - private ArrayList<String> protectedBroadcasts; - - @Nullable - private ArrayList<ComponentParseUtils.ParsedActivity> activities; - - @Nullable - private ArrayList<ComponentParseUtils.ParsedActivity> receivers; - - @Nullable - private ArrayList<ComponentParseUtils.ParsedService> services; - - @Nullable - private ArrayList<ComponentParseUtils.ParsedProvider> providers; - - @Nullable - private ArrayList<ComponentParseUtils.ParsedFeature> features; - - @Nullable - private ArrayList<ComponentParseUtils.ParsedPermission> permissions; - - @Nullable - private ArrayList<ComponentParseUtils.ParsedPermissionGroup> permissionGroups; - - @Nullable - private ArrayList<ComponentParseUtils.ParsedInstrumentation> instrumentations; - - private ArrayList<ParsedActivityIntentInfo> preferredActivityFilters; - - private Bundle appMetaData; - - private String volumeUuid; - private String applicationVolumeUuid; - private PackageParser.SigningDetails signingDetails; - - private String codePath; - - private boolean use32BitAbi; - private boolean visibleToInstantApps; - - private String cpuAbiOverride; - - private boolean isStub; - - // TODO(b/135203078): Remove, should be unused - private int preferredOrder; - - private boolean forceQueryable; - - @Nullable - private ArrayList<Intent> queriesIntents; - - @Nullable - private ArrayList<String> queriesPackages; - - @Nullable - private ArraySet<String> queriesProviders; - - @Nullable - private ArrayMap<String, ComponentParseUtils.ParsedProcess> processes; - - private String[] splitClassLoaderNames; - private String[] splitCodePaths; - private SparseArray<int[]> splitDependencies; - private int[] splitFlags; - private String[] splitNames; - private int[] splitRevisionCodes; - - // TODO(b/135203078): Audit applicationInfo.something usages, which may be different from - // package.something usages. There were differing cases of package.field = versus - // package.appInfo.field =. This class assumes some obvious ones, like packageName, - // were collapsible, but kept the following separate. - - private String applicationInfoBaseResourcePath; - private String applicationInfoCodePath; - private String applicationInfoResourcePath; - private String[] applicationInfoSplitResourcePaths; - - private String appComponentFactory; - private String backupAgentName; - private int banner; - private int category; - private String classLoaderName; - private String className; - private int compatibleWidthLimitDp; - private String credentialProtectedDataDir; - private String dataDir; - private int descriptionRes; - private String deviceProtectedDataDir; - private boolean enabled; - private boolean crossProfile; - private int flags; - private int fullBackupContent; - private boolean hiddenUntilInstalled; - private int icon; - private int iconRes; - private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION; - private int labelRes; - private int largestWidthLimitDp; - private int logo; - private String manageSpaceActivityName; - private float maxAspectRatio; - private float minAspectRatio; - private int minSdkVersion; - private String name; - private String nativeLibraryDir; - private String nativeLibraryRootDir; - private boolean nativeLibraryRootRequiresIsa; - private int networkSecurityConfigRes; - private CharSequence nonLocalizedLabel; - private String permission; - private String primaryCpuAbi; - private int privateFlags; - private String processName; - private int requiresSmallestWidthDp; - private int roundIconRes; - private String secondaryCpuAbi; - private String secondaryNativeLibraryDir; - private String seInfo; - private String seInfoUser; - private int targetSandboxVersion; - private int targetSdkVersion; - private String taskAffinity; - private int theme; - private int uid = -1; - private int uiOptions; - private String[] usesLibraryFiles; - private List<SharedLibraryInfo> usesLibraryInfos; - private String zygotePreloadName; - private boolean preserveLegacyExternalStorage; - - @Nullable - private ArraySet<String> mimeGroups; - - @VisibleForTesting - public PackageImpl( - String packageName, - String baseCodePath, - TypedArray manifestArray, - boolean isCoreApp - ) { - this.packageName = TextUtils.safeIntern(packageName); - this.manifestPackageName = this.packageName; - this.baseCodePath = baseCodePath; - - this.versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0); - this.versionCodeMajor = manifestArray.getInteger( - R.styleable.AndroidManifest_versionCodeMajor, 0); - this.baseRevisionCode = manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode, - 0); - setVersionName(manifestArray.getNonConfigurationString( - R.styleable.AndroidManifest_versionName, 0)); - this.coreApp = isCoreApp; - - this.compileSdkVersion = manifestArray.getInteger( - R.styleable.AndroidManifest_compileSdkVersion, 0); - setCompileSdkVersionCodename(manifestArray.getNonConfigurationString( - R.styleable.AndroidManifest_compileSdkVersionCodename, 0)); - } - - private PackageImpl(String packageName) { - this.packageName = TextUtils.safeIntern(packageName); - this.manifestPackageName = this.packageName; - } - - @VisibleForTesting - public static ParsingPackage forParsing(String packageName) { - return new PackageImpl(packageName); - } - - @VisibleForTesting - public static ParsingPackage forParsing( - String packageName, - String baseCodePath, - TypedArray manifestArray, - boolean isCoreApp) { - return new PackageImpl(packageName, baseCodePath, manifestArray, isCoreApp); - } - - /** - * Mock an unavailable {@link AndroidPackage} to use when removing a package from the system. - * This can occur if the package was installed on a storage device that has since been removed. - * Since the infrastructure uses {@link AndroidPackage}, but for this case only cares about - * volumeUuid, just fake it rather than having separate method paths. - */ - public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) { - return new PackageImpl(packageName) - .setVolumeUuid(volumeUuid) - .hideAsParsed() - .hideAsFinal(); - } - - @Override - public ParsedPackage hideAsParsed() { - return this; - } - - @Override - public AndroidPackage hideAsFinal() { - updateFlags(); - return this; - } - - @Override - @Deprecated - public AndroidPackageWrite mutate() { - return this; - } - - private void updateFlags() { - if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 - && targetSdkVersion - >= Build.VERSION_CODES.DONUT)) { - this.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; - } - if (supportsNormalScreens != 0) { - this.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; - } - if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 - && targetSdkVersion - >= Build.VERSION_CODES.DONUT)) { - this.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; - } - if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 - && targetSdkVersion - >= Build.VERSION_CODES.GINGERBREAD)) { - this.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; - } - if (resizeable < 0 || (resizeable > 0 - && targetSdkVersion - >= Build.VERSION_CODES.DONUT)) { - this.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; - } - if (anyDensity < 0 || (anyDensity > 0 - && targetSdkVersion - >= Build.VERSION_CODES.DONUT)) { - this.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; - } - } - - @Override - public boolean usesCompatibilityMode() { - int flags = 0; - - if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 - && targetSdkVersion - >= Build.VERSION_CODES.DONUT)) { - flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; - } - if (supportsNormalScreens != 0) { - flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; - } - if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 - && targetSdkVersion - >= Build.VERSION_CODES.DONUT)) { - flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; - } - if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 - && targetSdkVersion - >= Build.VERSION_CODES.GINGERBREAD)) { - flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; - } - if (resizeable < 0 || (resizeable > 0 - && targetSdkVersion - >= Build.VERSION_CODES.DONUT)) { - flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; - } - if (anyDensity < 0 || (anyDensity > 0 - && targetSdkVersion - >= Build.VERSION_CODES.DONUT)) { - flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; - } - - return targetSdkVersion < DONUT - || (flags & (ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS - | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES - | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)) == 0; - } - - @Override - public String getBaseCodePath() { - return baseCodePath; - } - - @Override - public int getTargetSdkVersion() { - return targetSdkVersion; - } - - @Override - public String getPackageName() { - return packageName; - } - - @Override - public String getProcessName() { - return processName; - } - - @Override - public String getPermission() { - return permission; - } - - @Override - public String getStaticSharedLibName() { - return staticSharedLibName; - } - - @Override - public long getStaticSharedLibVersion() { - return staticSharedLibVersion; - } - - @Override - public String getSharedUserId() { - return sharedUserId; - } - - @Override - public List<String> getRequestedPermissions() { - return requestedPermissions == null ? Collections.emptyList() : requestedPermissions; - } - - @Nullable - @Override - public List<ParsedInstrumentation> getInstrumentations() { - return instrumentations; - } - - @Override - public Map<String, ArraySet<PublicKey>> getKeySetMapping() { - return keySetMapping == null ? emptyMap() : keySetMapping; - } - - @Override - public float getMaxAspectRatio() { - return maxAspectRatio; - } - - @Override - public float getMinAspectRatio() { - return minAspectRatio; - } - - @NonNull - @Override - public List<String> getLibraryNames() { - return libraryNames == null ? Collections.emptyList() : libraryNames; - } - - @Override - public List<ParsedActivity> getActivities() { - return activities == null ? Collections.emptyList() - : activities; - } - - @Override - public Bundle getAppMetaData() { - return appMetaData; - } - - @Nullable - @Override - public List<String> getUsesLibraries() { - return usesLibraries; - } - - @Nullable - @Override - public List<String> getUsesStaticLibraries() { - return usesStaticLibraries; - } - - @Nullable - @Override - public ArrayMap<String, ComponentParseUtils.ParsedProcess> getProcesses() { - return processes; - } - - @Override - public boolean isBaseHardwareAccelerated() { - return baseHardwareAccelerated; - } - - @Override - public int getUiOptions() { - return uiOptions; - } - - // TODO(b/135203078): Checking flags directly can be error prone, - // consider separate interface methods? - @Override - public int getFlags() { - return flags; - } - - // TODO(b/135203078): Checking flags directly can be error prone, - // consider separate interface methods? - @Override - public int getPrivateFlags() { - return privateFlags; - } - - @Override - public String getTaskAffinity() { - return taskAffinity; - } - - @Nullable - @Override - public List<String> getOriginalPackages() { - return originalPackages; - } - - @Override - public PackageParser.SigningDetails getSigningDetails() { - return signingDetails; - } - - @Override - public String getVolumeUuid() { - return volumeUuid; - } - - @Nullable - @Override - public List<ParsedPermissionGroup> getPermissionGroups() { - return permissionGroups; - } - - @Nullable - @Override - public List<ParsedPermission> getPermissions() { - return permissions; - } - - @Nullable - @Override - public List<ParsedFeature> getFeatures() { - return features; - } - - @Override - public String getCpuAbiOverride() { - return cpuAbiOverride; - } - - @Override - public String getPrimaryCpuAbi() { - return primaryCpuAbi; - } - - @Override - public String getSecondaryCpuAbi() { - return secondaryCpuAbi; - } - - @Override - public boolean isUse32BitAbi() { - return use32BitAbi; - } - - @Override - public boolean isForceQueryable() { - return forceQueryable; - } - - @Override - public String getCodePath() { - return codePath; - } - - @Override - public String getNativeLibraryDir() { - return nativeLibraryDir; - } - - @Override - public String getNativeLibraryRootDir() { - return nativeLibraryRootDir; - } - - @Override - public boolean isNativeLibraryRootRequiresIsa() { - return nativeLibraryRootRequiresIsa; - } - - // TODO(b/135203078): Does nothing, remove? - @Override - public int getPreferredOrder() { - return preferredOrder; - } - - @Override - public long getLongVersionCode() { - return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); - } - - @Override - public PackageImpl setIsOverlay(boolean isOverlay) { - this.privateFlags = isOverlay - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY; - return this; - } - - @Override - public PackageImpl setExternalStorage(boolean externalStorage) { - this.flags = externalStorage - ? this.flags | ApplicationInfo.FLAG_EXTERNAL_STORAGE - : this.flags & ~ApplicationInfo.FLAG_EXTERNAL_STORAGE; - return this; - } - - @Override - public PackageImpl setIsolatedSplitLoading(boolean isolatedSplitLoading) { - this.privateFlags = isolatedSplitLoading - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING; - return this; - } - - @Override - public PackageImpl sortActivities() { - Collections.sort(this.activities, (a1, a2) -> Integer.compare(a2.order, a1.order)); - return this; - } - - @Override - public PackageImpl sortReceivers() { - Collections.sort(this.receivers, (a1, a2) -> Integer.compare(a2.order, a1.order)); - return this; - } - - @Override - public PackageImpl sortServices() { - Collections.sort(this.services, (a1, a2) -> Integer.compare(a2.order, a1.order)); - return this; - } - - @Override - public PackageImpl setBaseRevisionCode(int baseRevisionCode) { - this.baseRevisionCode = baseRevisionCode; - return this; - } - - @Override - public PackageImpl setPreferredOrder(int preferredOrder) { - this.preferredOrder = preferredOrder; - return this; - } - - @Override - public PackageImpl setVersionName(String versionName) { - this.versionName = TextUtils.safeIntern(versionName); - return this; - } - - @Override - public ParsingPackage setCompileSdkVersion(int compileSdkVersion) { - this.compileSdkVersion = compileSdkVersion; - return this; - } - - @Override - public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) { - this.compileSdkVersionCodename = TextUtils.safeIntern(compileSdkVersionCodename); - return this; - } - - @Override - public PackageImpl setMaxAspectRatio(float maxAspectRatio) { - this.maxAspectRatio = maxAspectRatio; - return this; - } - - @Override - public PackageImpl setMinAspectRatio(float minAspectRatio) { - this.minAspectRatio = minAspectRatio; - return this; - } - - @Override - public PackageImpl setMinSdkVersion(int minSdkVersion) { - this.minSdkVersion = minSdkVersion; - return this; - } - - @Override - public PackageImpl setTargetSdkVersion(int targetSdkVersion) { - this.targetSdkVersion = targetSdkVersion; - return this; - } - - @Override - public PackageImpl setRealPackage(String realPackage) { - this.realPackage = realPackage; - return this; - } - - @Override - public PackageImpl addConfigPreference(ConfigurationInfo configPreference) { - this.configPreferences = ArrayUtils.add(this.configPreferences, configPreference); - return this; - } - - @Override - public PackageImpl addReqFeature(FeatureInfo reqFeature) { - this.reqFeatures = ArrayUtils.add(this.reqFeatures, reqFeature); - return this; - } - - @Override - public PackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) { - this.featureGroups = ArrayUtils.add(this.featureGroups, featureGroup); - return this; - } - - @Override - public PackageImpl addProtectedBroadcast(String protectedBroadcast) { - if (this.protectedBroadcasts == null - || !this.protectedBroadcasts.contains(protectedBroadcast)) { - this.protectedBroadcasts = ArrayUtils.add(this.protectedBroadcasts, - TextUtils.safeIntern(protectedBroadcast)); - } - return this; - } - - @Override - public PackageImpl addInstrumentation(ParsedInstrumentation instrumentation) { - this.instrumentations = ArrayUtils.add(this.instrumentations, instrumentation); - return this; - } - - @Override - public PackageImpl addOriginalPackage(String originalPackage) { - this.originalPackages = ArrayUtils.add(this.originalPackages, originalPackage); - return this; - } - - @Override - public ParsingPackage addOverlayable(String overlayableName, String actorName) { - this.overlayables = CollectionUtils.add(this.overlayables, - TextUtils.safeIntern(overlayableName), TextUtils.safeIntern(actorName)); - return this; - } - - @Override - public PackageImpl addAdoptPermission(String adoptPermission) { - this.adoptPermissions = ArrayUtils.add(this.adoptPermissions, adoptPermission); - return this; - } - - @Override - public PackageImpl addFeature(ParsedFeature feature) { - this.features = ArrayUtils.add(this.features, feature); - return this; - } - - @Override - public PackageImpl addPermission(ParsedPermission permission) { - this.permissions = ArrayUtils.add(this.permissions, permission); - return this; - } - - @Override - public PackageImpl removePermission(int index) { - this.permissions.remove(index); - return this; - } - - @Override - public PackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) { - this.permissionGroups = ArrayUtils.add(this.permissionGroups, permissionGroup); - return this; - } - - @Override - public PackageImpl addRequestedPermission(String permission) { - this.requestedPermissions = ArrayUtils.add(this.requestedPermissions, - TextUtils.safeIntern(permission)); - return this; - } - - @Override - public PackageImpl addImplicitPermission(String permission) { - this.implicitPermissions = ArrayUtils.add(this.implicitPermissions, - TextUtils.safeIntern(permission)); - return this; - } - - @Override - public PackageImpl addKeySet(String keySetName, PublicKey publicKey) { - if (keySetMapping == null) { - keySetMapping = new ArrayMap<>(); - } - - ArraySet<PublicKey> publicKeys = keySetMapping.get(keySetName); - if (publicKeys == null) { - publicKeys = new ArraySet<>(); - keySetMapping.put(keySetName, publicKeys); - } - - publicKeys.add(publicKey); - - return this; - } - - @Override - public ParsingPackage addActivity(ParsedActivity parsedActivity) { - this.activities = ArrayUtils.add(this.activities, parsedActivity); - addMimeGroupsFromComponent(parsedActivity); - return this; - } - - @Override - public ParsingPackage addReceiver(ParsedActivity parsedReceiver) { - this.receivers = ArrayUtils.add(this.receivers, parsedReceiver); - addMimeGroupsFromComponent(parsedReceiver); - return this; - } - - @Override - public ParsingPackage addService(ParsedService parsedService) { - this.services = ArrayUtils.add(this.services, parsedService); - addMimeGroupsFromComponent(parsedService); - return this; - } - - @Override - public ParsingPackage addProvider(ParsedProvider parsedProvider) { - this.providers = ArrayUtils.add(this.providers, parsedProvider); - addMimeGroupsFromComponent(parsedProvider); - return this; - } - - @Override - public PackageImpl addLibraryName(String libraryName) { - this.libraryNames = ArrayUtils.add(this.libraryNames, TextUtils.safeIntern(libraryName)); - return this; - } - - @Override - public PackageImpl addUsesLibrary(String libraryName) { - this.usesLibraries = ArrayUtils.add(this.usesLibraries, TextUtils.safeIntern(libraryName)); - return this; - } - - @Override - public PackageImpl addUsesOptionalLibrary(String libraryName) { - this.usesOptionalLibraries = ArrayUtils.add(this.usesOptionalLibraries, - TextUtils.safeIntern(libraryName)); - return this; - } - - @Override - public PackageImpl removeUsesOptionalLibrary(String libraryName) { - this.usesOptionalLibraries = ArrayUtils.remove(this.usesOptionalLibraries, libraryName); - return this; - } - - @Override - public PackageImpl addUsesStaticLibrary(String libraryName) { - this.usesStaticLibraries = ArrayUtils.add(this.usesStaticLibraries, - TextUtils.safeIntern(libraryName)); - return this; - } - - @Override - public PackageImpl addUsesStaticLibraryVersion(long version) { - this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions, - version, true); - return this; - } - - @Override - public PackageImpl addUsesStaticLibraryCertDigests(String[] certSha256Digests) { - this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class, - this.usesStaticLibrariesCertDigests, certSha256Digests, true); - return this; - } - - @Override - public PackageImpl addPreferredActivityFilter( - ParsedActivityIntentInfo parsedActivityIntentInfo) { - this.preferredActivityFilters = ArrayUtils.add(this.preferredActivityFilters, - parsedActivityIntentInfo); - return this; - } - - @Override - public PackageImpl addQueriesIntent(Intent intent) { - this.queriesIntents = ArrayUtils.add(this.queriesIntents, intent); - return this; - } - - @Override - public PackageImpl addQueriesPackage(String packageName) { - this.queriesPackages = ArrayUtils.add(this.queriesPackages, - TextUtils.safeIntern(packageName)); - return this; - } - - @Override - public ParsingPackage addQueriesProvider(String authority) { - this.queriesProviders = ArrayUtils.add(this.queriesProviders, authority); - return this; - } - - @Override - public PackageImpl setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes) { - this.processes = processes; - return this; - } - - @Override - public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) { - if (supportsSmallScreens == 1) { - return this; - } - - this.supportsSmallScreens = supportsSmallScreens; - return this; - } - - @Override - public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) { - if (supportsNormalScreens == 1) { - return this; - } - - this.supportsNormalScreens = supportsNormalScreens; - return this; - } - - @Override - public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) { - if (supportsLargeScreens == 1) { - return this; - } - - this.supportsLargeScreens = supportsLargeScreens; - return this; - } - - @Override - public PackageImpl setSupportsXLargeScreens(int supportsXLargeScreens) { - if (supportsXLargeScreens == 1) { - return this; - } - - this.supportsXLargeScreens = supportsXLargeScreens; - return this; - } - - @Override - public PackageImpl setResizeable(int resizeable) { - if (resizeable == 1) { - return this; - } - - this.resizeable = resizeable; - return this; - } - - @Override - public PackageImpl setAnyDensity(int anyDensity) { - if (anyDensity == 1) { - return this; - } - - this.anyDensity = anyDensity; - return this; - } - - @Override - public PackageImpl setRequiresSmallestWidthDp(int requiresSmallestWidthDp) { - this.requiresSmallestWidthDp = requiresSmallestWidthDp; - return this; - } - - @Override - public PackageImpl setCompatibleWidthLimitDp(int compatibleWidthLimitDp) { - this.compatibleWidthLimitDp = compatibleWidthLimitDp; - return this; - } - - @Override - public PackageImpl setLargestWidthLimitDp(int largestWidthLimitDp) { - this.largestWidthLimitDp = largestWidthLimitDp; - return this; - } - - @Override - public PackageImpl setInstallLocation(int installLocation) { - this.installLocation = installLocation; - return this; - } - - @Override - public PackageImpl setTargetSandboxVersion(int targetSandboxVersion) { - this.targetSandboxVersion = targetSandboxVersion; - return this; - } - - @Override - public PackageImpl setRequiredForAllUsers(boolean requiredForAllUsers) { - this.requiredForAllUsers = requiredForAllUsers; - return this; - } - - @Override - public PackageImpl setRestrictedAccountType(String restrictedAccountType) { - this.restrictedAccountType = restrictedAccountType; - return this; - } - - @Override - public PackageImpl setRequiredAccountType(String requiredAccountType) { - this.requiredAccountType = requiredAccountType; - return this; - } - - @Override - public PackageImpl setBaseHardwareAccelerated(boolean baseHardwareAccelerated) { - this.baseHardwareAccelerated = baseHardwareAccelerated; - - this.flags = baseHardwareAccelerated - ? this.flags | ApplicationInfo.FLAG_HARDWARE_ACCELERATED - : this.flags & ~ApplicationInfo.FLAG_HARDWARE_ACCELERATED; - - return this; - } - - @Override - public PackageImpl setHasDomainUrls(boolean hasDomainUrls) { - this.privateFlags = hasDomainUrls - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; - return this; - } - - @Override - public PackageImpl setAppMetaData(Bundle appMetaData) { - this.appMetaData = appMetaData; - return this; - } - - @Override - public PackageImpl setOverlayTarget(String overlayTarget) { - this.overlayTarget = overlayTarget; - return this; - } - - @Override - public PackageImpl setOverlayTargetName(String overlayTargetName) { - this.overlayTargetName = overlayTargetName; - return this; - } - - @Override - public PackageImpl setOverlayCategory(String overlayCategory) { - this.overlayCategory = overlayCategory; - return this; - } - - @Override - public PackageImpl setOverlayPriority(int overlayPriority) { - this.overlayPriority = overlayPriority; - return this; - } - - @Override - public PackageImpl setOverlayIsStatic(boolean overlayIsStatic) { - this.overlayIsStatic = overlayIsStatic; - return this; - } - - @Override - public PackageImpl setStaticSharedLibName(String staticSharedLibName) { - this.staticSharedLibName = TextUtils.safeIntern(staticSharedLibName); - return this; - } - - @Override - public PackageImpl setStaticSharedLibVersion(long staticSharedLibVersion) { - this.staticSharedLibVersion = staticSharedLibVersion; - return this; - } - - @Override - public PackageImpl setSharedUserId(String sharedUserId) { - this.sharedUserId = TextUtils.safeIntern(sharedUserId); - return this; - } - - @Override - public PackageImpl setSharedUserLabel(int sharedUserLabel) { - this.sharedUserLabel = sharedUserLabel; - return this; - } - - @Override - public PackageImpl setRestrictUpdateHash(byte[] restrictUpdateHash) { - this.restrictUpdateHash = restrictUpdateHash; - return this; - } - - @Override - public PackageImpl setUpgradeKeySets(ArraySet<String> upgradeKeySets) { - this.upgradeKeySets = upgradeKeySets; - return this; - } - - @Override - public PackageImpl setVolumeUuid(String volumeUuid) { - this.volumeUuid = volumeUuid; - return this; - } - - @Deprecated - @Override - public PackageImpl setApplicationVolumeUuid(String applicationVolumeUuid) { - this.applicationVolumeUuid = applicationVolumeUuid; - return this; - } - - @Override - public PackageImpl setSigningDetails(PackageParser.SigningDetails signingDetails) { - this.signingDetails = signingDetails; - return this; - } - - @Override - public PackageImpl setCodePath(String codePath) { - this.codePath = codePath; - return this; - } - - @Override - public PackageImpl setUse32BitAbi(boolean use32BitAbi) { - this.use32BitAbi = use32BitAbi; - return this; - } - - @Override - public PackageImpl setCpuAbiOverride(String cpuAbiOverride) { - this.cpuAbiOverride = cpuAbiOverride; - return this; - } - - @Override - public PackageImpl setForceQueryable(boolean forceQueryable) { - this.forceQueryable = forceQueryable; - return this; - } - - // TODO(b/135203078): Remove and move PackageManagerService#renameStaticSharedLibraryPackage - // into initial package parsing - @Override - public PackageImpl setPackageName(String packageName) { - this.packageName = packageName.intern(); - - if (permissions != null) { - for (ParsedPermission permission : permissions) { - permission.setPackageName(this.packageName); - } - } - - if (permissionGroups != null) { - for (ParsedPermissionGroup permissionGroup : permissionGroups) { - permissionGroup.setPackageName(this.packageName); - } - } - - if (activities != null) { - for (ParsedActivity parsedActivity : activities) { - parsedActivity.setPackageName(this.packageName); - } - } - - if (receivers != null) { - for (ParsedActivity receiver : receivers) { - receiver.setPackageName(this.packageName); - } - } - - if (providers != null) { - for (ParsedProvider provider : providers) { - provider.setPackageName(this.packageName); - } - } - - if (services != null) { - for (ParsedService service : services) { - service.setPackageName(this.packageName); - } - } - - if (instrumentations != null) { - for (ParsedInstrumentation instrumentation : instrumentations) { - instrumentation.setPackageName(this.packageName); - } - } - - return this; - } - - // Under this is parseBaseApplication - - @Override - public PackageImpl setAllowBackup(boolean allowBackup) { - this.flags = allowBackup - ? this.flags | ApplicationInfo.FLAG_ALLOW_BACKUP - : this.flags & ~ApplicationInfo.FLAG_ALLOW_BACKUP; - return this; - } - - @Override - public PackageImpl setKillAfterRestore(boolean killAfterRestore) { - this.flags = killAfterRestore - ? this.flags | ApplicationInfo.FLAG_KILL_AFTER_RESTORE - : this.flags & ~ApplicationInfo.FLAG_KILL_AFTER_RESTORE; - return this; - } - - @Override - public PackageImpl setRestoreAnyVersion(boolean restoreAnyVersion) { - this.flags = restoreAnyVersion - ? this.flags | ApplicationInfo.FLAG_RESTORE_ANY_VERSION - : this.flags & ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; - return this; - } - - @Override - public PackageImpl setFullBackupOnly(boolean fullBackupOnly) { - this.flags = fullBackupOnly - ? this.flags | ApplicationInfo.FLAG_FULL_BACKUP_ONLY - : this.flags & ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY; - return this; - } - - @Override - public PackageImpl setPersistent(boolean persistent) { - this.flags = persistent - ? this.flags | ApplicationInfo.FLAG_PERSISTENT - : this.flags & ~ApplicationInfo.FLAG_PERSISTENT; - return this; - } - - @Override - public PackageImpl setDebuggable(boolean debuggable) { - this.flags = debuggable - ? this.flags | ApplicationInfo.FLAG_DEBUGGABLE - : this.flags & ~ApplicationInfo.FLAG_DEBUGGABLE; - return this; - } - - @Override - public PackageImpl setProfileableByShell(boolean profileableByShell) { - this.privateFlags = profileableByShell - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL; - return this; - } - - @Override - public PackageImpl setVmSafeMode(boolean vmSafeMode) { - this.flags = vmSafeMode - ? this.flags | ApplicationInfo.FLAG_VM_SAFE_MODE - : this.flags & ~ApplicationInfo.FLAG_VM_SAFE_MODE; - return this; - } - - @Override - public PackageImpl setHasCode(boolean hasCode) { - this.flags = hasCode - ? this.flags | ApplicationInfo.FLAG_HAS_CODE - : this.flags & ~ApplicationInfo.FLAG_HAS_CODE; - return this; - } - - @Override - public PackageImpl setAllowTaskReparenting(boolean allowTaskReparenting) { - this.flags = allowTaskReparenting - ? this.flags | ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING - : this.flags & ~ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; - return this; - } - - @Override - public PackageImpl setAllowClearUserData(boolean allowClearUserData) { - this.flags = allowClearUserData - ? this.flags | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA - : this.flags & ~ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; - return this; - } - - @Override - public PackageImpl setLargeHeap(boolean largeHeap) { - this.flags = largeHeap - ? this.flags | ApplicationInfo.FLAG_LARGE_HEAP - : this.flags & ~ApplicationInfo.FLAG_LARGE_HEAP; - return this; - } - - @Override - public PackageImpl setUsesCleartextTraffic(boolean usesCleartextTraffic) { - this.flags = usesCleartextTraffic - ? this.flags | ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC - : this.flags & ~ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC; - return this; - } - - @Override - public PackageImpl setSupportsRtl(boolean supportsRtl) { - this.flags = supportsRtl - ? this.flags | ApplicationInfo.FLAG_SUPPORTS_RTL - : this.flags & ~ApplicationInfo.FLAG_SUPPORTS_RTL; - return this; - } - - @Override - public PackageImpl setTestOnly(boolean testOnly) { - this.flags = testOnly - ? this.flags | ApplicationInfo.FLAG_TEST_ONLY - : this.flags & ~ApplicationInfo.FLAG_TEST_ONLY; - return this; - } - - @Override - public PackageImpl setMultiArch(boolean multiArch) { - this.flags = multiArch - ? this.flags | ApplicationInfo.FLAG_MULTIARCH - : this.flags & ~ApplicationInfo.FLAG_MULTIARCH; - return this; - } - - @Override - public PackageImpl setExtractNativeLibs(boolean extractNativeLibs) { - this.flags = extractNativeLibs - ? this.flags | ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS - : this.flags & ~ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS; - return this; - } - - @Override - public PackageImpl setIsGame(boolean isGame) { - this.flags = isGame - ? this.flags | ApplicationInfo.FLAG_IS_GAME - : this.flags & ~ApplicationInfo.FLAG_IS_GAME; - return this; - } - - @Override - public PackageImpl setBackupInForeground(boolean backupInForeground) { - this.privateFlags = backupInForeground - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; - return this; - } - - @Override - public PackageImpl setUseEmbeddedDex(boolean useEmbeddedDex) { - this.privateFlags = useEmbeddedDex - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX; - return this; - } - - @Override - public PackageImpl setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage) { - this.privateFlags = defaultToDeviceProtectedStorage - ? this.privateFlags | ApplicationInfo - .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE - : this.privateFlags & ~ApplicationInfo - .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; - return this; - } - - @Override - public PackageImpl setDirectBootAware(boolean directBootAware) { - this.privateFlags = directBootAware - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; - return this; - } - - @Override - public PackageImpl setPartiallyDirectBootAware(boolean partiallyDirectBootAware) { - this.privateFlags = partiallyDirectBootAware - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; - return this; - } - - @Override - public PackageImpl setActivitiesResizeModeResizeableViaSdkVersion( - boolean resizeableViaSdkVersion - ) { - this.privateFlags = resizeableViaSdkVersion - ? this.privateFlags | ApplicationInfo - .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION - : this.privateFlags & ~ApplicationInfo - .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; - return this; - } - - @Override - public PackageImpl setActivitiesResizeModeResizeable(boolean resizeable) { - this.privateFlags = resizeable - ? this.privateFlags | ApplicationInfo - .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE - : this.privateFlags & ~ApplicationInfo - .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; - - this.privateFlags = !resizeable - ? this.privateFlags | ApplicationInfo - .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE - : this.privateFlags & ~ApplicationInfo - .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; - return this; - } - - @Override - public PackageImpl setAllowClearUserDataOnFailedRestore( - boolean allowClearUserDataOnFailedRestore - ) { - this.privateFlags = allowClearUserDataOnFailedRestore - ? this.privateFlags | ApplicationInfo - .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE - : this.privateFlags & ~ApplicationInfo - .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE; - return this; - } - - @Override - public PackageImpl setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture) { - this.privateFlags = allowAudioPlaybackCapture - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE; - return this; - } - - @Override - public PackageImpl setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage) { - this.privateFlags = requestLegacyExternalStorage - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE; - return this; - } - - @Override - public PackageImpl setAllowNativeHeapPointerTagging(boolean allowNativeHeapPointerTagging) { - this.privateFlags = allowNativeHeapPointerTagging - ? this.privateFlags | ApplicationInfo - .PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING - : this.privateFlags & ~ApplicationInfo - .PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING; - return this; - } - - @Override - public PackageImpl setPreserveLegacyExternalStorage(boolean preserveLegacyExternalStorage) { - this.preserveLegacyExternalStorage = preserveLegacyExternalStorage; - return this; - } - - @Override - public PackageImpl setUsesNonSdkApi(boolean usesNonSdkApi) { - this.privateFlags = usesNonSdkApi - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API; - return this; - } - - @Override - public PackageImpl setHasFragileUserData(boolean hasFragileUserData) { - this.privateFlags = hasFragileUserData - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA; - return this; - } - - @Override - public PackageImpl setCantSaveState(boolean cantSaveState) { - this.privateFlags = cantSaveState - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE; - return this; - } - - @Override - public boolean cantSaveState() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0; - } - - @Override - public boolean isLibrary() { - return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames); - } - - // TODO(b/135203078): This does nothing until the final stage without applyPolicy being - // part of PackageParser - @Override - public boolean isSystemApp() { - return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; - } - - // TODO(b/135203078): This does nothing until the final stage without applyPolicy being - // part of PackageParser - @Override - public boolean isSystemExt() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0; - } - - // TODO(b/135203078): This does nothing until the final stage without applyPolicy being - // part of PackageParser - @Override - public boolean isUpdatedSystemApp() { - return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; - } - - @Override - public PackageImpl setStaticSharedLibrary(boolean staticSharedLibrary) { - this.privateFlags = staticSharedLibrary - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY; - return this; - } - - @Override - public boolean isStaticSharedLibrary() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0; - } - - @Override - public PackageImpl setVisibleToInstantApps(boolean visibleToInstantApps) { - this.visibleToInstantApps = visibleToInstantApps; - return this; - } - - @Override - public PackageImpl setIconRes(int iconRes) { - this.iconRes = iconRes; - return this; - } - - @Override - public PackageImpl setRoundIconRes(int roundIconRes) { - this.roundIconRes = roundIconRes; - return this; - } - - @Override - public PackageImpl setClassName(String className) { - this.className = className; - return this; - } - - @Override - public PackageImpl setManageSpaceActivityName(String manageSpaceActivityName) { - this.manageSpaceActivityName = manageSpaceActivityName; - return this; - } - - @Override - public PackageImpl setBackupAgentName(String backupAgentName) { - this.backupAgentName = backupAgentName; - return this; - } - - @Override - public PackageImpl setFullBackupContent(int fullBackupContent) { - this.fullBackupContent = fullBackupContent; - return this; - } - - @Override - public PackageImpl setTheme(int theme) { - this.theme = theme; - return this; - } - - @Override - public PackageImpl setDescriptionRes(int descriptionRes) { - this.descriptionRes = descriptionRes; - return this; - } - - @Override - public PackageImpl setNetworkSecurityConfigRes(int networkSecurityConfigRes) { - this.networkSecurityConfigRes = networkSecurityConfigRes; - return this; - } - - @Override - public PackageImpl setCategory(int category) { - this.category = category; - return this; - } - - @Override - public PackageImpl setPermission(String permission) { - this.permission = permission; - return this; - } - - @Override - public PackageImpl setTaskAffinity(String taskAffinity) { - this.taskAffinity = taskAffinity; - return this; - } - - @Override - public PackageImpl setAppComponentFactory(String appComponentFactory) { - this.appComponentFactory = appComponentFactory; - return this; - } - - @Override - public PackageImpl setProcessName(String processName) { - if (processName == null) { - this.processName = packageName; - } else { - this.processName = processName; - } - return this; - } - - @Override - public PackageImpl setEnabled(boolean enabled) { - this.enabled = enabled; - return this; - } - - @Override - public PackageImpl setCrossProfile(boolean crossProfile) { - this.crossProfile = crossProfile; - return this; - } - - @Override - public PackageImpl setUiOptions(int uiOptions) { - this.uiOptions = uiOptions; - return this; - } - - @Override - public PackageImpl setClassLoaderName(String classLoaderName) { - this.classLoaderName = classLoaderName; - return this; - } - - @Override - public PackageImpl setZygotePreloadName(String zygotePreloadName) { - this.zygotePreloadName = zygotePreloadName; - return this; - } - - // parsePackageItemInfo - - @Override - public String getName() { - return name; - } - - @Override - public PackageImpl setName(String name) { - this.name = name; - return this; - } - - @Override - public PackageImpl setIcon(int icon) { - this.icon = icon; - return this; - } - - @Override - public PackageImpl setNonLocalizedLabel(CharSequence nonLocalizedLabel) { - this.nonLocalizedLabel = nonLocalizedLabel; - return this; - } - - @Override - public PackageImpl setLogo(int logo) { - this.logo = logo; - return this; - } - - @Override - public PackageImpl setBanner(int banner) { - this.banner = banner; - return this; - } - - @Override - public PackageImpl setLabelRes(int labelRes) { - this.labelRes = labelRes; - return this; - } - - @Override - public PackageImpl asSplit( - String[] splitNames, - String[] splitCodePaths, - int[] splitRevisionCodes, - SparseArray<int[]> splitDependencies - ) { - this.splitNames = splitNames; - - if (this.splitNames != null) { - for (int index = 0; index < this.splitNames.length; index++) { - splitNames[index] = TextUtils.safeIntern(splitNames[index]); - } - } - - this.splitCodePaths = splitCodePaths; - this.splitRevisionCodes = splitRevisionCodes; - this.splitDependencies = splitDependencies; - - int count = splitNames.length; - this.splitFlags = new int[count]; - this.splitClassLoaderNames = new String[count]; - return this; - } - - @Override - public String[] getSplitNames() { - return splitNames; - } - - @Override - public String[] getSplitCodePaths() { - return splitCodePaths; - } - - @Override - public PackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) { - this.splitFlags[splitIndex] = splitHasCode - ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE - : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE; - return this; - } - - @Override - public PackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) { - this.splitClassLoaderNames[splitIndex] = classLoaderName; - return this; - } - - @Override - public List<String> makeListAllCodePaths() { - ArrayList<String> paths = new ArrayList<>(); - paths.add(baseCodePath); - - if (!ArrayUtils.isEmpty(splitCodePaths)) { - Collections.addAll(paths, splitCodePaths); - } - return paths; - } - - @Override - public PackageImpl setBaseCodePath(String baseCodePath) { - this.baseCodePath = baseCodePath; - return this; - } - - @Override - public PackageImpl setSplitCodePaths(String[] splitCodePaths) { - this.splitCodePaths = splitCodePaths; - return this; - } - - @Override - public String toString() { - return "Package{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + packageName + "}"; - } - - @Override - public PackageImpl setPrimaryCpuAbi(String primaryCpuAbi) { - this.primaryCpuAbi = primaryCpuAbi; - return this; - } - - @Override - public PackageImpl setSecondaryCpuAbi(String secondaryCpuAbi) { - this.secondaryCpuAbi = secondaryCpuAbi; - return this; - } - - @Override - public PackageImpl setNativeLibraryRootDir(String nativeLibraryRootDir) { - this.nativeLibraryRootDir = nativeLibraryRootDir; - return this; - } - - @Override - public PackageImpl setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa) { - this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; - return this; - } - - @Override - public PackageImpl setNativeLibraryDir(String nativeLibraryDir) { - this.nativeLibraryDir = nativeLibraryDir; - return this; - } - - @Override - public PackageImpl setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir) { - this.secondaryNativeLibraryDir = secondaryNativeLibraryDir; - return this; - } - - @Deprecated - @Override - public PackageImpl setApplicationInfoCodePath(String applicationInfoCodePath) { - this.applicationInfoCodePath = applicationInfoCodePath; - return this; - } - - @Deprecated - @Override - public PackageImpl setApplicationInfoResourcePath(String applicationInfoResourcePath) { - this.applicationInfoResourcePath = applicationInfoResourcePath; - return this; - } - - @Deprecated - @Override - public PackageImpl setApplicationInfoBaseResourcePath( - String applicationInfoBaseResourcePath) { - this.applicationInfoBaseResourcePath = applicationInfoBaseResourcePath; - return this; - } - - @Deprecated - @Override - public PackageImpl setApplicationInfoSplitResourcePaths( - String[] applicationInfoSplitResourcePaths) { - this.applicationInfoSplitResourcePaths = applicationInfoSplitResourcePaths; - return this; - } - - @Override - public boolean isDirectBootAware() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0; - } - - @Override - public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) { - if (activities != null) { - for (ParsedActivity parsedActivity : activities) { - parsedActivity.directBootAware = allComponentsDirectBootAware; - } - } - - if (receivers != null) { - for (ParsedActivity parsedReceiver : receivers) { - parsedReceiver.directBootAware = allComponentsDirectBootAware; - } - } - - if (providers != null) { - for (ParsedProvider parsedProvider : providers) { - parsedProvider.directBootAware = allComponentsDirectBootAware; - } - } - - if (services != null) { - for (ParsedService parsedService : services) { - parsedService.directBootAware = allComponentsDirectBootAware; - } - } - - return this; - } - - @Override - public PackageImpl setSystem(boolean system) { - this.flags = system - ? this.flags | ApplicationInfo.FLAG_SYSTEM - : this.flags & ~ApplicationInfo.FLAG_SYSTEM; - return this; - } - - @Override - public PackageImpl setSystemExt(boolean systemExt) { - this.privateFlags = systemExt - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT; - return this; - } - - @Override - public PackageImpl setIsStub(boolean isStub) { - this.isStub = isStub; - return this; - } - - @Override - public PackageImpl setCoreApp(boolean coreApp) { - this.coreApp = coreApp; - return this; - } - - @Override - public ParsedPackage capPermissionPriorities() { - if (permissionGroups != null && !permissionGroups.isEmpty()) { - for (int i = permissionGroups.size() - 1; i >= 0; --i) { - // TODO(b/135203078): Builder/immutability - permissionGroups.get(i).priority = 0; - } - } - return this; - } - - @Override - public ParsedPackage clearProtectedBroadcasts() { - if (protectedBroadcasts != null) { - protectedBroadcasts.clear(); - } - return this; - } - - @Override - public ParsedPackage markNotActivitiesAsNotExportedIfSingleUser() { - // ignore export request for single user receivers - if (receivers != null) { - for (ParsedActivity receiver : receivers) { - if ((receiver.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) { - receiver.exported = false; - } - } - } - // ignore export request for single user services - if (services != null) { - for (ParsedService service : services) { - if ((service.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) { - service.exported = false; - } - } - } - // ignore export request for single user providers - if (providers != null) { - for (ParsedProvider provider : providers) { - if ((provider.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) { - provider.exported = false; - } - } - } - - return this; - } - - @Override - public ParsedPackage setPrivileged(boolean privileged) { - this.privateFlags = privileged - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRIVILEGED - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; - return this; - } - - @Override - public ParsedPackage setOem(boolean oem) { - this.privateFlags = oem - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_OEM - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_OEM; - return this; - } - - @Override - public ParsedPackage setVendor(boolean vendor) { - this.privateFlags = vendor - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_VENDOR - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_VENDOR; - return this; - } - - @Override - public ParsedPackage setProduct(boolean product) { - this.privateFlags = product - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRODUCT - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRODUCT; - return this; - } - - @Override - public ParsedPackage setOdm(boolean odm) { - this.privateFlags = odm - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ODM - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ODM; - return this; - } - - @Override - public ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey) { - this.privateFlags = signedWithPlatformKey - ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY - : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY; - return this; - } - - @Override - public ParsedPackage clearOriginalPackages() { - if (originalPackages != null) { - originalPackages.clear(); - } - return this; - } - - @Override - public ParsedPackage clearAdoptPermissions() { - if (adoptPermissions != null) { - adoptPermissions.clear(); - } - return this; - } - - @Override - public PackageImpl addUsesLibrary(int index, String libraryName) { - this.usesLibraries = ArrayUtils.add(usesLibraries, index, libraryName); - return this; - } - - @Override - public ParsedPackage removeUsesLibrary(String libraryName) { - this.usesLibraries = ArrayUtils.remove(this.usesLibraries, libraryName); - return this; - } - - @Override - public PackageImpl addUsesOptionalLibrary(int index, String libraryName) { - this.usesOptionalLibraries = ArrayUtils.add(usesOptionalLibraries, index, libraryName); - return this; - } - - @Nullable - @Override - public List<String> getUsesOptionalLibraries() { - return usesOptionalLibraries; - } - - @Override - public int getVersionCode() { - return versionCode; - } - - @Nullable - @Override - public long[] getUsesStaticLibrariesVersions() { - return usesStaticLibrariesVersions; - } - - @Override - public PackageImpl setPackageSettingCallback(PackageSettingCallback packageSettingCallback) { - packageSettingCallback.setAndroidPackage(this); - return this; - } - - @Override - public PackageImpl setUpdatedSystemApp(boolean updatedSystemApp) { - this.flags = updatedSystemApp - ? this.flags | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP - : this.flags & ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - return this; - } - - @Override - public boolean isPrivileged() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; - } - - @Override - public PackageImpl setSeInfo(String seInfo) { - this.seInfo = seInfo; - return this; - } - - @Override - public PackageImpl setSeInfoUser(String seInfoUser) { - this.seInfoUser = seInfoUser; - return this; - } - - @Override - public PackageImpl initForUser(int userId) { - // TODO(b/135203078): Move this user state to some other data structure - this.uid = UserHandle.getUid(userId, UserHandle.getAppId(this.uid)); - - if ("android".equals(packageName)) { - dataDir = Environment.getDataSystemDirectory().getAbsolutePath(); - return this; - } - - deviceProtectedDataDir = Environment - .getDataUserDePackageDirectory(applicationVolumeUuid, userId, packageName) - .getAbsolutePath(); - credentialProtectedDataDir = Environment - .getDataUserCePackageDirectory(applicationVolumeUuid, userId, packageName) - .getAbsolutePath(); - - if ((privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0 - && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { - dataDir = deviceProtectedDataDir; - } else { - dataDir = credentialProtectedDataDir; - } - return this; - } - - @Override - public ParsedPackage setFactoryTest(boolean factoryTest) { - this.flags = factoryTest - ? this.flags | ApplicationInfo.FLAG_FACTORY_TEST - : this.flags & ~ApplicationInfo.FLAG_FACTORY_TEST; - return this; - } - - @Override - public String getManifestPackageName() { - return manifestPackageName; - } - - @Override - public String getRealPackage() { - return realPackage; - } - - @Override - public String getOverlayTarget() { - return overlayTarget; - } - - @Override - public String getOverlayTargetName() { - return overlayTargetName; - } - - @Override - public Map<String, String> getOverlayables() { - return overlayables; - } - - @Override - public boolean isOverlayIsStatic() { - return overlayIsStatic; - } - - @Override - public int[] getSplitFlags() { - return splitFlags; - } - - @Deprecated - @Override - public String getApplicationInfoVolumeUuid() { - return applicationVolumeUuid; - } - - @Nullable - @Override - public List<String> getProtectedBroadcasts() { - return protectedBroadcasts; - } - - @Nullable - @Override - public Set<String> getUpgradeKeySets() { - return upgradeKeySets; - } - - @Nullable - @Override - public String[][] getUsesStaticLibrariesCertDigests() { - return usesStaticLibrariesCertDigests; - } - - @Override - public int getOverlayPriority() { - return overlayPriority; - } - - @Deprecated - @Override - public String getAppInfoPackageName() { - return packageName; - } - - @Override - public UUID getStorageUuid() { - return StorageManager.convert(applicationVolumeUuid); - } - - @Override - public int getUid() { - return uid; - } - - @Override - public boolean isStub() { - return isStub; - } - - @Deprecated - @Override - public String getAppInfoCodePath() { - return applicationInfoCodePath; - } - - @Override - public boolean isSystem() { - return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; - } - - @Override - public boolean isMatch(int flags) { - if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { - return isSystem(); - } - return true; - } - - @Override - public boolean isVisibleToInstantApps() { - return visibleToInstantApps; - } - - @Override - public PackageImpl setLastPackageUsageTimeInMills(int reason, long time) { - lastPackageUsageTimeInMills[reason] = time; - return this; - } - - @Override - public List<SharedLibraryInfo> getUsesLibraryInfos() { - return usesLibraryInfos; - } - - @NonNull - @Override - public List<String> getAllCodePaths() { - return makeListAllCodePaths(); - } - - @Nullable - @Override - public String[] getUsesLibraryFiles() { - return usesLibraryFiles; - } - - @Override - public PackageImpl setUsesLibraryInfos( - @Nullable List<SharedLibraryInfo> usesLibraryInfos) { - this.usesLibraryInfos = usesLibraryInfos; - return this; - } - - @Override - public PackageImpl setUsesLibraryFiles(@Nullable String[] usesLibraryFiles) { - this.usesLibraryFiles = usesLibraryFiles; - return this; - } - - @Override - public PackageImpl setUid(int uid) { - this.uid = uid; - return this; - } - - @Override - public List<String> getAdoptPermissions() { - return adoptPermissions; - } - - @Override - public ApplicationInfo toAppInfoWithoutState() { - updateFlags(); - - ApplicationInfo appInfo = new ApplicationInfo(); - appInfo.packageName = packageName; - appInfo.flags = flags; - appInfo.privateFlags = privateFlags; - - appInfo.appComponentFactory = appComponentFactory; - appInfo.backupAgentName = backupAgentName; - appInfo.banner = banner; - appInfo.category = category; - appInfo.classLoaderName = classLoaderName; - appInfo.className = className; - appInfo.compatibleWidthLimitDp = compatibleWidthLimitDp; - appInfo.compileSdkVersion = compileSdkVersion; - appInfo.compileSdkVersionCodename = compileSdkVersionCodename; - appInfo.credentialProtectedDataDir = credentialProtectedDataDir; - appInfo.dataDir = dataDir; - appInfo.descriptionRes = descriptionRes; - appInfo.deviceProtectedDataDir = deviceProtectedDataDir; - appInfo.enabled = enabled; - appInfo.fullBackupContent = fullBackupContent; - appInfo.hiddenUntilInstalled = hiddenUntilInstalled; - appInfo.icon = icon; - appInfo.iconRes = iconRes; - appInfo.installLocation = installLocation; - appInfo.labelRes = labelRes; - appInfo.largestWidthLimitDp = largestWidthLimitDp; - appInfo.logo = logo; - appInfo.manageSpaceActivityName = manageSpaceActivityName; - appInfo.maxAspectRatio = maxAspectRatio; - appInfo.metaData = appMetaData; - appInfo.minAspectRatio = minAspectRatio; - appInfo.minSdkVersion = minSdkVersion; - appInfo.name = className; - if (appInfo.name != null) { - appInfo.name = appInfo.name.trim(); - } - appInfo.nativeLibraryDir = nativeLibraryDir; - appInfo.nativeLibraryRootDir = nativeLibraryRootDir; - appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; - appInfo.networkSecurityConfigRes = networkSecurityConfigRes; - appInfo.nonLocalizedLabel = nonLocalizedLabel; - if (appInfo.nonLocalizedLabel != null) { - appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim(); - } - appInfo.packageName = packageName; - appInfo.permission = permission; - appInfo.primaryCpuAbi = primaryCpuAbi; - appInfo.processName = getProcessName(); - appInfo.requiresSmallestWidthDp = requiresSmallestWidthDp; - appInfo.roundIconRes = roundIconRes; - appInfo.secondaryCpuAbi = secondaryCpuAbi; - appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir; - appInfo.seInfo = seInfo; - appInfo.seInfoUser = seInfoUser; - appInfo.sharedLibraryFiles = usesLibraryFiles; - appInfo.sharedLibraryInfos = ArrayUtils.isEmpty(usesLibraryInfos) ? null : usesLibraryInfos; - appInfo.splitClassLoaderNames = splitClassLoaderNames; - appInfo.splitDependencies = splitDependencies; - appInfo.splitNames = splitNames; - appInfo.storageUuid = StorageManager.convert(volumeUuid); - appInfo.targetSandboxVersion = targetSandboxVersion; - appInfo.targetSdkVersion = targetSdkVersion; - appInfo.taskAffinity = taskAffinity; - appInfo.theme = theme; - appInfo.uid = uid; - appInfo.uiOptions = uiOptions; - appInfo.volumeUuid = volumeUuid; - appInfo.zygotePreloadName = zygotePreloadName; - appInfo.crossProfile = isCrossProfile(); - - appInfo.setBaseCodePath(baseCodePath); - appInfo.setBaseResourcePath(baseCodePath); - appInfo.setCodePath(codePath); - appInfo.setResourcePath(codePath); - appInfo.setSplitCodePaths(splitCodePaths); - appInfo.setSplitResourcePaths(splitCodePaths); - appInfo.setVersionCode(getLongVersionCode()); - - // TODO(b/135203078): Can this be removed? Looks only used in ActivityInfo. -// appInfo.showUserIcon = pkg.getShowUserIcon(); - // TODO(b/135203078): Unused? -// appInfo.resourceDirs = pkg.getResourceDirs(); - // TODO(b/135203078): Unused? -// appInfo.enabledSetting = pkg.getEnabledSetting(); - // TODO(b/135203078): See PackageImpl#getHiddenApiEnforcementPolicy -// appInfo.mHiddenApiPolicy = pkg.getHiddenApiPolicy(); - - return appInfo; - } - - @Override - public PackageImpl setVersionCode(int versionCode) { - this.versionCode = versionCode; - return this; - } - - @Override - public PackageImpl setHiddenUntilInstalled(boolean hidden) { - this.hiddenUntilInstalled = hidden; - return this; - } - - @Override - public String getSeInfo() { - return seInfo; - } - - @Deprecated - @Override - public String getAppInfoResourcePath() { - return applicationInfoResourcePath; - } - - @Override - public boolean isForwardLocked() { - // TODO(b/135203078): Unused? Move to debug flag? - return false; - } - - @Override - public byte[] getRestrictUpdateHash() { - return restrictUpdateHash; - } - - @Override - public boolean hasComponentClassName(String className) { - if (activities != null) { - for (ParsedActivity parsedActivity : activities) { - if (Objects.equals(className, parsedActivity.className)) { - return true; - } - } - } - - if (receivers != null) { - for (ParsedActivity receiver : receivers) { - if (Objects.equals(className, receiver.className)) { - return true; - } - } - } - - if (providers != null) { - for (ParsedProvider provider : providers) { - if (Objects.equals(className, provider.className)) { - return true; - } - } - } - - if (services != null) { - for (ParsedService service : services) { - if (Objects.equals(className, service.className)) { - return true; - } - } - } - - if (instrumentations != null) { - for (ParsedInstrumentation instrumentation : instrumentations) { - if (Objects.equals(className, instrumentation.className)) { - return true; - } - } - } - - return false; - } - - @Override - public boolean isDefaultToDeviceProtectedStorage() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) - != 0; - } - - @Override - public boolean isInternal() { - return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0; - } - - @Override - public int getBaseRevisionCode() { - return baseRevisionCode; - } - - @Override - public int[] getSplitRevisionCodes() { - return splitRevisionCodes; - } - - @Override - public boolean canHaveOatDir() { - // The following app types CANNOT have oat directory - // - non-updated system apps - return !isSystem() || isUpdatedSystemApp(); - } - - @Override - public long getLatestPackageUseTimeInMills() { - long latestUse = 0L; - for (long use : lastPackageUsageTimeInMills) { - latestUse = Math.max(latestUse, use); - } - return latestUse; - } - - @Override - public long getLatestForegroundPackageUseTimeInMills() { - int[] foregroundReasons = { - PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY, - PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE - }; - - long latestUse = 0L; - for (int reason : foregroundReasons) { - latestUse = Math.max(latestUse, lastPackageUsageTimeInMills[reason]); - } - return latestUse; - } - - @Override - public boolean isCoreApp() { - return coreApp; - } - - @Override - public String getVersionName() { - return versionName; - } - - @Override - public PackageImpl setVersionCodeMajor(int versionCodeMajor) { - this.versionCodeMajor = versionCodeMajor; - return this; - } - - @Override - public long[] getLastPackageUsageTimeInMills() { - return lastPackageUsageTimeInMills; - } - - @Override - public String getDataDir() { - return dataDir; - } - - @Override - public boolean isExternal() { - return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; - } - - @Override - public List<String> getImplicitPermissions() { - return implicitPermissions == null ? Collections.emptyList() : implicitPermissions; - } - - /** - * TODO(b/135203078): Remove, ensure b/140256621 is fixed or irrelevant - * TODO(b/140256621): Remove after fixing instant app check - * @deprecated This method always returns false because there's no paired set method - */ - @Deprecated - @Override - public boolean isInstantApp() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; - } - - @Override - public boolean hasRequestedLegacyExternalStorage() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0; - } - - @Override - public boolean isVendor() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; - } - - @Override - public boolean isProduct() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; - } - - @Override - public boolean isOem() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; - } - - @Override - public boolean isEncryptionAware() { - boolean isPartiallyDirectBootAware = - (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0; - return isDirectBootAware() || isPartiallyDirectBootAware; - } - - @Override - public boolean isEmbeddedDexUsed() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX) != 0; - } - - @Deprecated - @Override - public String getAppInfoProcessName() { - return processName; - } - - @Override - public List<String> getAllCodePathsExcludingResourceOnly() { - ArrayList<String> paths = new ArrayList<>(); - if ((flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { - paths.add(baseCodePath); - } - if (!ArrayUtils.isEmpty(splitCodePaths)) { - for (int i = 0; i < splitCodePaths.length; i++) { - if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { - paths.add(splitCodePaths[i]); - } - } - } - return paths; - } - - @Deprecated - @Override - public String getAppInfoName() { - return name; - } - - private boolean isSignedWithPlatformKey() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0; - } - - private boolean usesNonSdkApi() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API) != 0; - } - - private boolean isPackageWhitelistedForHiddenApis() { - return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName); - } - - private boolean isAllowedToUseHiddenApis() { - if (isSignedWithPlatformKey()) { - return true; - } else if (isSystemApp() || isUpdatedSystemApp()) { - return usesNonSdkApi() || isPackageWhitelistedForHiddenApis(); - } else { - return false; - } - } - - @Override - public int getHiddenApiEnforcementPolicy() { - if (isAllowedToUseHiddenApis()) { - return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; - } - - // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done - // entirely through ApplicationInfo and shouldn't touch this specific class, but that - // may not always hold true. -// if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) { -// return mHiddenApiPolicy; -// } - return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED; - } - - @Nullable - @Override - public SparseArray<int[]> getSplitDependencies() { - return splitDependencies; - } - - @Override - public boolean requestsIsolatedSplitLoading() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) != 0; - } - - @Deprecated - @Override - public String getAppInfoClassLoaderName() { - return classLoaderName; - } - - @Override - public String getClassLoaderName() { - return classLoaderName; - } - - @Override - public String[] getSplitClassLoaderNames() { - return splitClassLoaderNames; - } - - @Override - public String getOverlayCategory() { - return overlayCategory; - } - - @Override - public boolean isProfileableByShell() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0; - } - - @Nullable - @Override - public List<ParsedActivityIntentInfo> getPreferredActivityFilters() { - return preferredActivityFilters; - } - - @Override - public boolean isHiddenUntilInstalled() { - return hiddenUntilInstalled; - } - - @Override - public int getMinSdkVersion() { - return minSdkVersion; - } - - @Override - public String getRestrictedAccountType() { - return restrictedAccountType; - } - - @Override - public String getRequiredAccountType() { - return requiredAccountType; - } - - @Override - public int getInstallLocation() { - return installLocation; - } - - @Override - public List<ParsedActivity> getReceivers() { - return receivers; - } - - @Override - public List<ParsedService> getServices() { - return services; - } - - @Override - public List<ParsedProvider> getProviders() { - return providers; - } - - @Override - public int getSharedUserLabel() { - return sharedUserLabel; - } - - @Override - public int getVersionCodeMajor() { - return versionCodeMajor; - } - - @Override - public boolean isRequiredForAllUsers() { - return requiredForAllUsers; - } - - @Override - public int getCompileSdkVersion() { - return compileSdkVersion; - } - - @Override - public String getCompileSdkVersionCodeName() { - return compileSdkVersionCodename; - } - - @Nullable - @Override - public List<ConfigurationInfo> getConfigPreferences() { - return configPreferences; - } - - @Nullable - @Override - public List<FeatureInfo> getReqFeatures() { - return reqFeatures; - } - - @Override - public List<FeatureGroupInfo> getFeatureGroups() { - return featureGroups; - } - - @Override - public String getDeviceProtectedDataDir() { - return deviceProtectedDataDir; - } - - @Override - public String getCredentialProtectedDataDir() { - return credentialProtectedDataDir; - } - - @Override - public String getSeInfoUser() { - return seInfoUser; - } - - @Override - public String getClassName() { - return className; - } - - @Override - public int getTheme() { - return theme; - } - - @Override - public int getRequiresSmallestWidthDp() { - return requiresSmallestWidthDp; - } - - @Override - public int getCompatibleWidthLimitDp() { - return compatibleWidthLimitDp; - } - - @Override - public int getLargestWidthLimitDp() { - return largestWidthLimitDp; - } - - @Override - public String getScanSourceDir() { - return applicationInfoCodePath; - } - - @Override - public String getScanPublicSourceDir() { - return applicationInfoResourcePath; - } - - @Override - public String getPublicSourceDir() { - return applicationInfoBaseResourcePath; - } - - @Override - public String[] getSplitPublicSourceDirs() { - return applicationInfoSplitResourcePaths; - } - - @Override - public String getSecondaryNativeLibraryDir() { - return secondaryNativeLibraryDir; - } - - @Override - public boolean isEnabled() { - return enabled; - } - - @Override - public boolean isCrossProfile() { - return crossProfile; - } - - @Override - public String getManageSpaceActivityName() { - return manageSpaceActivityName; - } - - @Override - public int getDescriptionRes() { - return descriptionRes; - } - - @Override - public String getBackupAgentName() { - return backupAgentName; - } - - @Override - public int getFullBackupContent() { - return fullBackupContent; - } - - @Override - public int getNetworkSecurityConfigRes() { - return networkSecurityConfigRes; - } - - @Override - public int getCategory() { - return category; - } - - @Override - public int getTargetSandboxVersion() { - return targetSandboxVersion; - } - - @Override - public String getAppComponentFactory() { - return appComponentFactory; - } - - @Override - public int getIconRes() { - return iconRes; - } - - @Override - public int getRoundIconRes() { - return roundIconRes; - } - - @Override - public String getZygotePreloadName() { - return zygotePreloadName; - } - - @Override - public int getLabelRes() { - return labelRes; - } - - @Override - public CharSequence getNonLocalizedLabel() { - return nonLocalizedLabel; - } - - @Override - public int getIcon() { - return icon; - } - - @Override - public int getBanner() { - return banner; - } - - @Override - public int getLogo() { - return logo; - } - - @Override - public Bundle getMetaData() { - return appMetaData; - } - - private void addMimeGroupsFromComponent(ParsedComponent<?> component) { - for (int i = component.intents.size() - 1; i >= 0; i--) { - IntentFilter filter = component.intents.get(i); - for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) { - mimeGroups = ArrayUtils.add(mimeGroups, filter.getMimeGroup(groupIndex)); - } - } - } - - @Override - @Nullable - public Set<String> getMimeGroups() { - return mimeGroups; - } - - @Override - @Nullable - public List<Intent> getQueriesIntents() { - return queriesIntents; - } - - @Override - @Nullable - public List<String> getQueriesPackages() { - return queriesPackages; - } - - @Override - public Set<String> getQueriesProviders() { - return queriesProviders; - } - - @Override - public boolean hasPreserveLegacyExternalStorage() { - return preserveLegacyExternalStorage; - } - - private static void internStringArrayList(List<String> list) { - if (list != null) { - final int N = list.size(); - for (int i = 0; i < N; ++i) { - list.set(i, list.get(i).intern()); - } - } - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(this.supportsSmallScreens); - dest.writeInt(this.supportsNormalScreens); - dest.writeInt(this.supportsLargeScreens); - dest.writeInt(this.supportsXLargeScreens); - dest.writeInt(this.resizeable); - dest.writeInt(this.anyDensity); - dest.writeLongArray(this.lastPackageUsageTimeInMills); - dest.writeInt(this.versionCode); - dest.writeInt(this.versionCodeMajor); - dest.writeInt(this.baseRevisionCode); - dest.writeString(this.versionName); - dest.writeBoolean(this.coreApp); - dest.writeInt(this.compileSdkVersion); - dest.writeString(this.compileSdkVersionCodename); - dest.writeString(this.packageName); - dest.writeString(this.realPackage); - dest.writeString(this.manifestPackageName); - dest.writeString(this.baseCodePath); - dest.writeBoolean(this.requiredForAllUsers); - dest.writeString(this.restrictedAccountType); - dest.writeString(this.requiredAccountType); - dest.writeBoolean(this.baseHardwareAccelerated); - dest.writeString(this.overlayTarget); - dest.writeString(this.overlayTargetName); - dest.writeString(this.overlayCategory); - dest.writeInt(this.overlayPriority); - dest.writeBoolean(this.overlayIsStatic); - dest.writeMap(this.overlayables); - dest.writeString(this.staticSharedLibName); - dest.writeLong(this.staticSharedLibVersion); - dest.writeStringList(this.libraryNames); - dest.writeStringList(this.usesLibraries); - dest.writeStringList(this.usesOptionalLibraries); - dest.writeStringList(this.usesStaticLibraries); - dest.writeLongArray(this.usesStaticLibrariesVersions); - final int numProcesses = this.processes != null ? this.processes.size() : 0; - dest.writeInt(numProcesses); - for (int i = 0; i < numProcesses; i++) { - this.processes.valueAt(i).writeToParcel(dest, 0); - } - - if (this.usesStaticLibrariesCertDigests == null) { - dest.writeInt(-1); - } else { - dest.writeInt(this.usesStaticLibrariesCertDigests.length); - for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) { - dest.writeStringArray(this.usesStaticLibrariesCertDigests[index]); - } - } - - dest.writeString(this.sharedUserId); - dest.writeInt(this.sharedUserLabel); - dest.writeTypedList(this.configPreferences); - dest.writeTypedList(this.reqFeatures); - dest.writeTypedList(this.featureGroups); - dest.writeByteArray(this.restrictUpdateHash); - dest.writeStringList(this.originalPackages); - dest.writeStringList(this.adoptPermissions); - dest.writeStringList(this.requestedPermissions); - dest.writeStringList(this.implicitPermissions); - dest.writeArraySet(this.upgradeKeySets); - dest.writeMap(this.keySetMapping); - dest.writeStringList(this.protectedBroadcasts); - dest.writeTypedList(this.activities); - dest.writeTypedList(this.receivers); - dest.writeTypedList(this.services); - dest.writeTypedList(this.providers); - dest.writeTypedList(this.features); - dest.writeTypedList(this.permissions); - dest.writeTypedList(this.permissionGroups); - dest.writeTypedList(this.instrumentations); - ParsedIntentInfo.writeIntentsList(this.preferredActivityFilters, dest, flags); - dest.writeBundle(this.appMetaData); - dest.writeString(this.volumeUuid); - dest.writeString(this.applicationVolumeUuid); - dest.writeParcelable(this.signingDetails, flags); - dest.writeString(this.codePath); - dest.writeBoolean(this.use32BitAbi); - dest.writeBoolean(this.visibleToInstantApps); - dest.writeString(this.cpuAbiOverride); - dest.writeBoolean(this.isStub); - dest.writeInt(this.preferredOrder); - dest.writeBoolean(this.forceQueryable); - dest.writeParcelableList(this.queriesIntents, flags); - dest.writeStringList(this.queriesPackages); - dest.writeString(this.applicationInfoBaseResourcePath); - dest.writeString(this.applicationInfoCodePath); - dest.writeString(this.applicationInfoResourcePath); - dest.writeStringArray(this.applicationInfoSplitResourcePaths); - dest.writeString(this.appComponentFactory); - dest.writeString(this.backupAgentName); - dest.writeInt(this.banner); - dest.writeInt(this.category); - dest.writeString(this.classLoaderName); - dest.writeString(this.className); - dest.writeInt(this.compatibleWidthLimitDp); - dest.writeString(this.credentialProtectedDataDir); - dest.writeString(this.dataDir); - dest.writeInt(this.descriptionRes); - dest.writeString(this.deviceProtectedDataDir); - dest.writeBoolean(this.enabled); - dest.writeBoolean(this.crossProfile); - dest.writeInt(this.flags); - dest.writeInt(this.fullBackupContent); - dest.writeBoolean(this.hiddenUntilInstalled); - dest.writeInt(this.icon); - dest.writeInt(this.iconRes); - dest.writeInt(this.installLocation); - dest.writeInt(this.labelRes); - dest.writeInt(this.largestWidthLimitDp); - dest.writeInt(this.logo); - dest.writeString(this.manageSpaceActivityName); - dest.writeFloat(this.maxAspectRatio); - dest.writeFloat(this.minAspectRatio); - dest.writeInt(this.minSdkVersion); - dest.writeString(this.name); - dest.writeString(this.nativeLibraryDir); - dest.writeString(this.nativeLibraryRootDir); - dest.writeBoolean(this.nativeLibraryRootRequiresIsa); - dest.writeInt(this.networkSecurityConfigRes); - dest.writeCharSequence(this.nonLocalizedLabel); - dest.writeString(this.permission); - dest.writeString(this.primaryCpuAbi); - dest.writeInt(this.privateFlags); - dest.writeString(this.processName); - dest.writeInt(this.requiresSmallestWidthDp); - dest.writeInt(this.roundIconRes); - dest.writeString(this.secondaryCpuAbi); - dest.writeString(this.secondaryNativeLibraryDir); - dest.writeString(this.seInfo); - dest.writeString(this.seInfoUser); - dest.writeInt(this.targetSandboxVersion); - dest.writeInt(this.targetSdkVersion); - dest.writeString(this.taskAffinity); - dest.writeInt(this.theme); - dest.writeInt(this.uid); - dest.writeInt(this.uiOptions); - dest.writeStringArray(this.usesLibraryFiles); - dest.writeTypedList(this.usesLibraryInfos); - dest.writeString(this.zygotePreloadName); - dest.writeStringArray(this.splitClassLoaderNames); - dest.writeStringArray(this.splitCodePaths); - dest.writeSparseArray(this.splitDependencies); - dest.writeIntArray(this.splitFlags); - dest.writeStringArray(this.splitNames); - dest.writeIntArray(this.splitRevisionCodes); - dest.writeArraySet(this.mimeGroups); - } - - public PackageImpl(Parcel in) { - // We use the boot classloader for all classes that we load. - final ClassLoader boot = Object.class.getClassLoader(); - this.supportsSmallScreens = in.readInt(); - this.supportsNormalScreens = in.readInt(); - this.supportsLargeScreens = in.readInt(); - this.supportsXLargeScreens = in.readInt(); - this.resizeable = in.readInt(); - this.anyDensity = in.readInt(); - this.lastPackageUsageTimeInMills = in.createLongArray(); - this.versionCode = in.readInt(); - this.versionCodeMajor = in.readInt(); - this.baseRevisionCode = in.readInt(); - this.versionName = TextUtils.safeIntern(in.readString()); - this.coreApp = in.readBoolean(); - this.compileSdkVersion = in.readInt(); - this.compileSdkVersionCodename = TextUtils.safeIntern(in.readString()); - this.packageName = TextUtils.safeIntern(in.readString()); - this.realPackage = in.readString(); - this.manifestPackageName = in.readString(); - this.baseCodePath = in.readString(); - this.requiredForAllUsers = in.readBoolean(); - this.restrictedAccountType = in.readString(); - this.requiredAccountType = in.readString(); - this.baseHardwareAccelerated = in.readBoolean(); - this.overlayTarget = in.readString(); - this.overlayTargetName = in.readString(); - this.overlayCategory = in.readString(); - this.overlayPriority = in.readInt(); - this.overlayIsStatic = in.readBoolean(); - this.overlayables = new HashMap<>(); - in.readMap(overlayables, boot); - this.staticSharedLibName = TextUtils.safeIntern(in.readString()); - this.staticSharedLibVersion = in.readLong(); - this.libraryNames = in.createStringArrayList(); - internStringArrayList(this.libraryNames); - this.usesLibraries = in.createStringArrayList(); - internStringArrayList(this.usesLibraries); - this.usesOptionalLibraries = in.createStringArrayList(); - internStringArrayList(this.usesOptionalLibraries); - this.usesStaticLibraries = in.createStringArrayList(); - internStringArrayList(usesStaticLibraries); - this.usesStaticLibrariesVersions = in.createLongArray(); - final int numProcesses = in.readInt(); - if (numProcesses > 0) { - this.processes = new ArrayMap<>(numProcesses); - for (int i = 0; i < numProcesses; i++) { - ComponentParseUtils.ParsedProcess proc = new ComponentParseUtils.ParsedProcess(in); - this.processes.put(proc.name, proc); - } - } else { - this.processes = null; - } - - int digestsSize = in.readInt(); - if (digestsSize >= 0) { - this.usesStaticLibrariesCertDigests = new String[digestsSize][]; - for (int index = 0; index < digestsSize; index++) { - this.usesStaticLibrariesCertDigests[index] = in.readStringArray(); - } - } - - this.sharedUserId = TextUtils.safeIntern(in.readString()); - this.sharedUserLabel = in.readInt(); - this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR); - this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR); - this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR); - this.restrictUpdateHash = in.createByteArray(); - this.originalPackages = in.createStringArrayList(); - this.adoptPermissions = in.createStringArrayList(); - this.requestedPermissions = in.createStringArrayList(); - internStringArrayList(this.requestedPermissions); - this.implicitPermissions = in.createStringArrayList(); - internStringArrayList(this.implicitPermissions); - this.upgradeKeySets = (ArraySet<String>) in.readArraySet(boot); - this.keySetMapping = in.readHashMap(boot); - this.protectedBroadcasts = in.createStringArrayList(); - internStringArrayList(this.protectedBroadcasts); - this.activities = in.createTypedArrayList(ParsedActivity.CREATOR); - this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR); - this.services = in.createTypedArrayList(ParsedService.CREATOR); - this.providers = in.createTypedArrayList(ParsedProvider.CREATOR); - this.features = in.createTypedArrayList(ParsedFeature.CREATOR); - this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR); - this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR); - this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR); - this.preferredActivityFilters = ParsedIntentInfo.createIntentsList(in); - this.appMetaData = in.readBundle(boot); - this.volumeUuid = in.readString(); - this.applicationVolumeUuid = in.readString(); - this.signingDetails = in.readParcelable(boot); - this.codePath = in.readString(); - this.use32BitAbi = in.readBoolean(); - this.visibleToInstantApps = in.readBoolean(); - this.cpuAbiOverride = in.readString(); - this.isStub = in.readBoolean(); - this.preferredOrder = in.readInt(); - this.forceQueryable = in.readBoolean(); - this.queriesIntents = in.createTypedArrayList(Intent.CREATOR); - this.queriesPackages = in.createStringArrayList(); - internStringArrayList(this.queriesPackages); - this.applicationInfoBaseResourcePath = in.readString(); - this.applicationInfoCodePath = in.readString(); - this.applicationInfoResourcePath = in.readString(); - this.applicationInfoSplitResourcePaths = in.createStringArray(); - this.appComponentFactory = in.readString(); - this.backupAgentName = in.readString(); - this.banner = in.readInt(); - this.category = in.readInt(); - this.classLoaderName = in.readString(); - this.className = in.readString(); - this.compatibleWidthLimitDp = in.readInt(); - this.credentialProtectedDataDir = in.readString(); - this.dataDir = in.readString(); - this.descriptionRes = in.readInt(); - this.deviceProtectedDataDir = in.readString(); - this.enabled = in.readBoolean(); - this.crossProfile = in.readBoolean(); - this.flags = in.readInt(); - this.fullBackupContent = in.readInt(); - this.hiddenUntilInstalled = in.readBoolean(); - this.icon = in.readInt(); - this.iconRes = in.readInt(); - this.installLocation = in.readInt(); - this.labelRes = in.readInt(); - this.largestWidthLimitDp = in.readInt(); - this.logo = in.readInt(); - this.manageSpaceActivityName = in.readString(); - this.maxAspectRatio = in.readFloat(); - this.minAspectRatio = in.readFloat(); - this.minSdkVersion = in.readInt(); - this.name = in.readString(); - this.nativeLibraryDir = in.readString(); - this.nativeLibraryRootDir = in.readString(); - this.nativeLibraryRootRequiresIsa = in.readBoolean(); - this.networkSecurityConfigRes = in.readInt(); - this.nonLocalizedLabel = in.readCharSequence(); - this.permission = TextUtils.safeIntern(in.readString()); - this.primaryCpuAbi = in.readString(); - this.privateFlags = in.readInt(); - this.processName = in.readString(); - this.requiresSmallestWidthDp = in.readInt(); - this.roundIconRes = in.readInt(); - this.secondaryCpuAbi = in.readString(); - this.secondaryNativeLibraryDir = in.readString(); - this.seInfo = in.readString(); - this.seInfoUser = in.readString(); - this.targetSandboxVersion = in.readInt(); - this.targetSdkVersion = in.readInt(); - this.taskAffinity = in.readString(); - this.theme = in.readInt(); - this.uid = in.readInt(); - this.uiOptions = in.readInt(); - this.usesLibraryFiles = in.createStringArray(); - this.usesLibraryInfos = in.createTypedArrayList(SharedLibraryInfo.CREATOR); - this.zygotePreloadName = in.readString(); - this.splitClassLoaderNames = in.createStringArray(); - this.splitCodePaths = in.createStringArray(); - this.splitDependencies = in.readSparseArray(boot); - this.splitFlags = in.createIntArray(); - this.splitNames = in.createStringArray(); - this.splitRevisionCodes = in.createIntArray(); - this.mimeGroups = (ArraySet<String>) in.readArraySet(boot); - } - - public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() { - @Override - public PackageImpl createFromParcel(Parcel source) { - return new PackageImpl(source); - } - - @Override - public PackageImpl[] newArray(int size) { - return new PackageImpl[size]; - } - }; -} diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java deleted file mode 100644 index 72df18998470..000000000000 --- a/core/java/android/content/pm/parsing/PackageInfoUtils.java +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm.parsing; - -import android.annotation.Nullable; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.ComponentInfo; -import android.content.pm.ConfigurationInfo; -import android.content.pm.FallbackCategoryProvider; -import android.content.pm.FeatureGroupInfo; -import android.content.pm.FeatureInfo; -import android.content.pm.InstrumentationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageItemInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.content.pm.PackageUserState; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; -import android.content.pm.ProcessInfo; -import android.content.pm.ProviderInfo; -import android.content.pm.SELinuxUtil; -import android.content.pm.ServiceInfo; -import android.content.pm.Signature; -import android.content.pm.SigningInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; -import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; -import android.util.ArrayMap; -import android.util.ArraySet; - -import com.android.internal.util.ArrayUtils; - -import java.util.Set; - -/** @hide */ -public class PackageInfoUtils { - - private static final String TAG = ApkParseUtils.TAG; - - /** - * Returns true if the package is installed and not hidden, or if the caller - * explicitly wanted all uninstalled and hidden packages as well. - */ - private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, PackageUserState state, - @PackageManager.PackageInfoFlags int flags) { - // Returns false if the package is hidden system app until installed. - if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0 - && !state.installed - && pkg.isHiddenUntilInstalled()) { - return false; - } - - // If available for the target user, or trying to match uninstalled packages and it's - // a system app. - return state.isAvailable(flags) - || (pkg.isSystemApp() - && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0 - || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0)); - } - - public static PackageInfo generate(AndroidPackage pkg, int[] gids, - @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, - Set<String> grantedPermissions, PackageUserState state, int userId) { - if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) { - return null; - } - ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId); - - PackageInfo pi = new PackageInfo(); - pi.packageName = pkg.getPackageName(); - pi.splitNames = pkg.getSplitNames(); - pi.versionCode = pkg.getVersionCode(); - pi.versionCodeMajor = pkg.getVersionCodeMajor(); - pi.baseRevisionCode = pkg.getBaseRevisionCode(); - pi.splitRevisionCodes = pkg.getSplitRevisionCodes(); - pi.versionName = pkg.getVersionName(); - pi.sharedUserId = pkg.getSharedUserId(); - pi.sharedUserLabel = pkg.getSharedUserLabel(); - pi.applicationInfo = applicationInfo; - pi.installLocation = pkg.getInstallLocation(); - pi.isStub = pkg.isStub(); - pi.coreApp = pkg.isCoreApp(); - if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 - || (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { - pi.requiredForAllUsers = pkg.isRequiredForAllUsers(); - } - pi.restrictedAccountType = pkg.getRestrictedAccountType(); - pi.requiredAccountType = pkg.getRequiredAccountType(); - pi.overlayTarget = pkg.getOverlayTarget(); - pi.targetOverlayableName = pkg.getOverlayTargetName(); - pi.overlayCategory = pkg.getOverlayCategory(); - pi.overlayPriority = pkg.getOverlayPriority(); - pi.mOverlayIsStatic = pkg.isOverlayIsStatic(); - pi.compileSdkVersion = pkg.getCompileSdkVersion(); - pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName(); - pi.firstInstallTime = firstInstallTime; - pi.lastUpdateTime = lastUpdateTime; - if ((flags & PackageManager.GET_GIDS) != 0) { - pi.gids = gids; - } - if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) { - int size = pkg.getConfigPreferences() != null ? pkg.getConfigPreferences().size() : 0; - if (size > 0) { - pi.configPreferences = new ConfigurationInfo[size]; - pkg.getConfigPreferences().toArray(pi.configPreferences); - } - size = pkg.getReqFeatures() != null ? pkg.getReqFeatures().size() : 0; - if (size > 0) { - pi.reqFeatures = new FeatureInfo[size]; - pkg.getReqFeatures().toArray(pi.reqFeatures); - } - size = pkg.getFeatureGroups() != null ? pkg.getFeatureGroups().size() : 0; - if (size > 0) { - pi.featureGroups = new FeatureGroupInfo[size]; - pkg.getFeatureGroups().toArray(pi.featureGroups); - } - } - if ((flags & PackageManager.GET_ACTIVITIES) != 0) { - if (pkg.getActivities() != null) { - final int N = pkg.getActivities().size(); - if (N > 0) { - int num = 0; - final ActivityInfo[] res = new ActivityInfo[N]; - for (int i = 0; i < N; i++) { - final ParsedActivity a = pkg.getActivities().get(i); - if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) { - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals( - a.className)) { - continue; - } - res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo, - userId); - } - } - pi.activities = ArrayUtils.trimToSize(res, num); - } - } - } - if ((flags & PackageManager.GET_RECEIVERS) != 0) { - if (pkg.getReceivers() != null) { - final int size = pkg.getReceivers().size(); - if (size > 0) { - int num = 0; - final ActivityInfo[] res = new ActivityInfo[size]; - for (int i = 0; i < size; i++) { - final ParsedActivity a = pkg.getReceivers().get(i); - if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) { - res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo, - userId); - } - } - pi.receivers = ArrayUtils.trimToSize(res, num); - } - } - } - if ((flags & PackageManager.GET_SERVICES) != 0) { - if (pkg.getServices() != null) { - final int size = pkg.getServices().size(); - if (size > 0) { - int num = 0; - final ServiceInfo[] res = new ServiceInfo[size]; - for (int i = 0; i < size; i++) { - final ComponentParseUtils.ParsedService s = pkg.getServices().get(i); - if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) { - res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo, - userId); - } - } - pi.services = ArrayUtils.trimToSize(res, num); - } - } - } - if ((flags & PackageManager.GET_PROVIDERS) != 0) { - if (pkg.getProviders() != null) { - final int size = pkg.getProviders().size(); - if (size > 0) { - int num = 0; - final ProviderInfo[] res = new ProviderInfo[size]; - for (int i = 0; i < size; i++) { - final ComponentParseUtils.ParsedProvider pr = pkg.getProviders() - .get(i); - if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) { - res[num++] = generateProviderInfo(pkg, pr, flags, state, - applicationInfo, userId); - } - } - pi.providers = ArrayUtils.trimToSize(res, num); - } - } - } - if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) { - if (pkg.getInstrumentations() != null) { - int N = pkg.getInstrumentations().size(); - if (N > 0) { - pi.instrumentation = new InstrumentationInfo[N]; - for (int i = 0; i < N; i++) { - pi.instrumentation[i] = generateInstrumentationInfo( - pkg.getInstrumentations().get(i), pkg, flags); - } - } - } - } - if ((flags & PackageManager.GET_PERMISSIONS) != 0) { - if (pkg.getPermissions() != null) { - int N = ArrayUtils.size(pkg.getPermissions()); - if (N > 0) { - pi.permissions = new PermissionInfo[N]; - for (int i = 0; i < N; i++) { - pi.permissions[i] = generatePermissionInfo( - pkg.getPermissions().get(i), - flags - ); - } - } - } - if (pkg.getRequestedPermissions() != null) { - int N = pkg.getRequestedPermissions().size(); - if (N > 0) { - pi.requestedPermissions = new String[N]; - pi.requestedPermissionsFlags = new int[N]; - for (int i = 0; i < N; i++) { - final String perm = pkg.getRequestedPermissions().get(i); - pi.requestedPermissions[i] = perm; - // The notion of required permissions is deprecated but for compatibility. - pi.requestedPermissionsFlags[i] |= - PackageInfo.REQUESTED_PERMISSION_REQUIRED; - if (grantedPermissions != null && grantedPermissions.contains(perm)) { - pi.requestedPermissionsFlags[i] |= - PackageInfo.REQUESTED_PERMISSION_GRANTED; - } - } - } - } - } - - PackageParser.SigningDetails signingDetails = pkg.getSigningDetails(); - // deprecated method of getting signing certificates - if ((flags & PackageManager.GET_SIGNATURES) != 0) { - if (signingDetails.hasPastSigningCertificates()) { - // Package has included signing certificate rotation information. Return the oldest - // cert so that programmatic checks keep working even if unaware of key rotation. - pi.signatures = new Signature[1]; - pi.signatures[0] = signingDetails.pastSigningCertificates[0]; - } else if (signingDetails.hasSignatures()) { - // otherwise keep old behavior - int numberOfSigs = signingDetails.signatures.length; - pi.signatures = new Signature[numberOfSigs]; - System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0, - numberOfSigs); - } - } - - // replacement for GET_SIGNATURES - if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) { - if (signingDetails != PackageParser.SigningDetails.UNKNOWN) { - // only return a valid SigningInfo if there is signing information to report - pi.signingInfo = new SigningInfo(signingDetails); - } else { - pi.signingInfo = null; - } - } - - return pi; - } - - @Nullable - public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg, - @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) { - - if (pkg == null) return null; - if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) { - return null; - } - - // Make shallow copy so we can store the metadata/libraries safely - ApplicationInfo ai = pkg.toAppInfoWithoutState(); - ai.initForUser(userId); - if ((flags & PackageManager.GET_META_DATA) == 0) { - ai.metaData = null; - } - if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) { - ai.sharedLibraryFiles = null; - ai.sharedLibraryInfos = null; - } - if (state.stopped) { - ai.flags |= ApplicationInfo.FLAG_STOPPED; - } else { - ai.flags &= ~ApplicationInfo.FLAG_STOPPED; - } - updateApplicationInfo(ai, flags, state); - - return ai; - } - - private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, - @PackageManager.ComponentInfoFlags int flags, PackageUserState state, - @Nullable ApplicationInfo applicationInfo, int userId) { - if (a == null) return null; - if (!checkUseInstalledOrHidden(pkg, state, flags)) { - return null; - } - if (applicationInfo == null) { - applicationInfo = generateApplicationInfo(pkg, flags, state, userId); - } - // Make shallow copies so we can store the metadata safely - ActivityInfo ai = new ActivityInfo(); - assignSharedFieldsForComponentInfo(ai, a); - ai.targetActivity = a.targetActivity; - ai.processName = a.getProcessName(); - ai.exported = a.exported; - ai.theme = a.theme; - ai.uiOptions = a.uiOptions; - ai.parentActivityName = a.parentActivityName; - ai.permission = a.getPermission(); - ai.taskAffinity = a.taskAffinity; - ai.flags = a.flags; - ai.privateFlags = a.privateFlags; - ai.launchMode = a.launchMode; - ai.documentLaunchMode = a.documentLaunchMode; - ai.maxRecents = a.maxRecents; - ai.configChanges = a.configChanges; - ai.softInputMode = a.softInputMode; - ai.persistableMode = a.persistableMode; - ai.lockTaskLaunchMode = a.lockTaskLaunchMode; - ai.screenOrientation = a.screenOrientation; - ai.resizeMode = a.resizeMode; - ai.maxAspectRatio = a.maxAspectRatio; - ai.minAspectRatio = a.minAspectRatio; - ai.requestedVrComponent = a.requestedVrComponent; - ai.rotationAnimation = a.rotationAnimation; - ai.colorMode = a.colorMode; - ai.preferMinimalPostProcessing = a.preferMinimalPostProcessing; - ai.windowLayout = a.windowLayout; - ai.metaData = a.metaData; - ai.applicationInfo = applicationInfo; - return ai; - } - - public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, - @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) { - return generateActivityInfo(pkg, a, flags, state, null, userId); - } - - private static ServiceInfo generateServiceInfo(AndroidPackage pkg, - ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags, - PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) { - if (s == null) return null; - if (!checkUseInstalledOrHidden(pkg, state, flags)) { - return null; - } - if (applicationInfo == null) { - applicationInfo = generateApplicationInfo(pkg, flags, state, userId); - } - // Make shallow copies so we can store the metadata safely - ServiceInfo si = new ServiceInfo(); - assignSharedFieldsForComponentInfo(si, s); - si.exported = s.exported; - si.flags = s.flags; - si.metaData = s.metaData; - si.permission = s.getPermission(); - si.processName = s.getProcessName(); - si.mForegroundServiceType = s.foregroundServiceType; - si.metaData = s.metaData; - si.applicationInfo = applicationInfo; - return si; - } - - public static ServiceInfo generateServiceInfo(AndroidPackage pkg, - ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags, - PackageUserState state, int userId) { - return generateServiceInfo(pkg, s, flags, state, null, userId); - } - - private static ProviderInfo generateProviderInfo(AndroidPackage pkg, - ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags, - PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) { - if (p == null) return null; - if (!checkUseInstalledOrHidden(pkg, state, flags)) { - return null; - } - if (applicationInfo == null) { - applicationInfo = generateApplicationInfo(pkg, flags, state, userId); - } - // Make shallow copies so we can store the metadata safely - ProviderInfo pi = new ProviderInfo(); - assignSharedFieldsForComponentInfo(pi, p); - pi.exported = p.exported; - pi.flags = p.flags; - pi.processName = p.getProcessName(); - pi.authority = p.getAuthority(); - pi.isSyncable = p.isSyncable; - pi.readPermission = p.getReadPermission(); - pi.writePermission = p.getWritePermission(); - pi.grantUriPermissions = p.grantUriPermissions; - pi.forceUriPermissions = p.forceUriPermissions; - pi.multiprocess = p.multiProcess; - pi.initOrder = p.initOrder; - pi.uriPermissionPatterns = p.uriPermissionPatterns; - pi.pathPermissions = p.pathPermissions; - pi.metaData = p.metaData; - if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { - pi.uriPermissionPatterns = null; - } - pi.applicationInfo = applicationInfo; - return pi; - } - - public static ProviderInfo generateProviderInfo(AndroidPackage pkg, - ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags, - PackageUserState state, int userId) { - return generateProviderInfo(pkg, p, flags, state, null, userId); - } - - public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i, - AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags) { - if (i == null) return null; - - InstrumentationInfo ii = new InstrumentationInfo(); - assignSharedFieldsForPackageItemInfo(ii, i); - ii.targetPackage = i.getTargetPackage(); - ii.targetProcesses = i.getTargetProcesses(); - ii.handleProfiling = i.handleProfiling; - ii.functionalTest = i.functionalTest; - - ii.sourceDir = pkg.getBaseCodePath(); - ii.publicSourceDir = pkg.getBaseCodePath(); - ii.splitNames = pkg.getSplitNames(); - ii.splitSourceDirs = pkg.getSplitCodePaths(); - ii.splitPublicSourceDirs = pkg.getSplitCodePaths(); - ii.splitDependencies = pkg.getSplitDependencies(); - ii.dataDir = pkg.getDataDir(); - ii.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir(); - ii.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir(); - ii.primaryCpuAbi = pkg.getPrimaryCpuAbi(); - ii.secondaryCpuAbi = pkg.getSecondaryCpuAbi(); - ii.nativeLibraryDir = pkg.getNativeLibraryDir(); - ii.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir(); - - if ((flags & PackageManager.GET_META_DATA) == 0) { - return ii; - } - ii.metaData = i.metaData; - return ii; - } - - public static ArrayMap<String, ProcessInfo> generateProcessInfo( - ArrayMap<String, ComponentParseUtils.ParsedProcess> procs, - @PackageManager.ComponentInfoFlags int flags) { - if (procs == null) { - return null; - } - - final int numProcs = procs.size(); - ArrayMap<String, ProcessInfo> retProcs = new ArrayMap(numProcs); - for (int i = 0; i < numProcs; i++) { - ComponentParseUtils.ParsedProcess proc = procs.valueAt(i); - retProcs.put(proc.name, new ProcessInfo(proc.name, - proc.deniedPermissions != null - ? new ArraySet<>(proc.deniedPermissions) : null)); - } - return retProcs; - } - - public static PermissionInfo generatePermissionInfo(ParsedPermission p, - @PackageManager.ComponentInfoFlags int flags) { - if (p == null) return null; - - PermissionInfo pi = new PermissionInfo(p.backgroundPermission); - assignSharedFieldsForPackageItemInfo(pi, p); - pi.group = p.getGroup(); - pi.requestRes = p.requestRes; - pi.protectionLevel = p.protectionLevel; - pi.descriptionRes = p.descriptionRes; - pi.flags = p.flags; - - if ((flags & PackageManager.GET_META_DATA) == 0) { - return pi; - } - pi.metaData = p.metaData; - return pi; - } - - public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg, - @PackageManager.ComponentInfoFlags int flags) { - if (pg == null) return null; - - PermissionGroupInfo pgi = new PermissionGroupInfo( - pg.requestDetailResourceId, - pg.backgroundRequestResourceId, - pg.backgroundRequestDetailResourceId - ); - assignSharedFieldsForPackageItemInfo(pgi, pg); - pgi.descriptionRes = pg.descriptionRes; - pgi.priority = pg.priority; - pgi.requestRes = pg.requestRes; - pgi.flags = pg.flags; - - if ((flags & PackageManager.GET_META_DATA) == 0) { - return pgi; - } - pgi.metaData = pg.metaData; - return pgi; - } - - private static void updateApplicationInfo(ApplicationInfo ai, - @PackageManager.ApplicationInfoFlags int flags, - PackageUserState state) { - // CompatibilityMode is global state. - if (!PackageParser.sCompatibilityModeEnabled) { - ai.disableCompatibilityMode(); - } - if (state.installed) { - ai.flags |= ApplicationInfo.FLAG_INSTALLED; - } else { - ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; - } - if (state.suspended) { - ai.flags |= ApplicationInfo.FLAG_SUSPENDED; - } else { - ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED; - } - if (state.instantApp) { - ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT; - } else { - ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT; - } - if (state.virtualPreload) { - ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; - } else { - ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; - } - if (state.hidden) { - ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; - } else { - ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; - } - if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { - ai.enabled = true; - } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { - ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; - } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED - || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { - ai.enabled = false; - } - ai.enabledSetting = state.enabled; - if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { - ai.category = state.categoryHint; - } - if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { - ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName); - } - ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state); - ai.resourceDirs = state.getAllOverlayPaths(); - ai.icon = (PackageParser.sUseRoundIcon && ai.roundIconRes != 0) - ? ai.roundIconRes : ai.iconRes; - } - - private static void assignSharedFieldsForPackageItemInfo(PackageItemInfo packageItemInfo, - ComponentParseUtils.ParsedComponent parsedComponent) { - packageItemInfo.banner = parsedComponent.banner; - packageItemInfo.icon = parsedComponent.icon; - packageItemInfo.labelRes = parsedComponent.labelRes; - packageItemInfo.logo = parsedComponent.logo; - packageItemInfo.name = parsedComponent.className; - packageItemInfo.nonLocalizedLabel = parsedComponent.nonLocalizedLabel; - packageItemInfo.packageName = parsedComponent.getPackageName(); - } - - private static void assignSharedFieldsForComponentInfo(ComponentInfo componentInfo, - ComponentParseUtils.ParsedComponent parsedComponent) { - assignSharedFieldsForPackageItemInfo(componentInfo, parsedComponent); - componentInfo.descriptionRes = parsedComponent.descriptionRes; - componentInfo.directBootAware = parsedComponent.directBootAware; - componentInfo.enabled = parsedComponent.enabled; - componentInfo.splitName = parsedComponent.getSplitName(); - } - -} diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java new file mode 100644 index 000000000000..e7d91c205f34 --- /dev/null +++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java @@ -0,0 +1,697 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import android.annotation.CheckResult; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.apex.ApexInfo; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FallbackCategoryProvider; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageUserState; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; +import android.content.pm.ProviderInfo; +import android.content.pm.SELinuxUtil; +import android.content.pm.ServiceInfo; +import android.content.pm.Signature; +import android.content.pm.SigningInfo; +import android.content.pm.parsing.ParsingPackage; +import android.os.Environment; +import android.os.UserHandle; + +import com.android.internal.util.ArrayUtils; +import android.content.pm.parsing.component.ComponentParseUtils; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedComponent; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedMainComponent; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; + +import libcore.util.EmptyArray; + +import java.io.File; +import java.util.Collections; +import java.util.Set; + +/** @hide **/ +public class PackageInfoWithoutStateUtils { + + @Nullable + public static PackageInfo generate(ParsingPackageRead pkg, int[] gids, + @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, + Set<String> grantedPermissions, PackageUserState state, int userId) { + return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions, + state, userId, null); + } + + @Nullable + public static PackageInfo generate(ParsingPackageRead pkg, ApexInfo apexInfo, int flags) { + return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(), + new PackageUserState(), UserHandle.getCallingUserId(), apexInfo); + } + + @Nullable + private static PackageInfo generateWithComponents(ParsingPackageRead pkg, int[] gids, + @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, + Set<String> grantedPermissions, PackageUserState state, int userId, + @Nullable ApexInfo apexInfo) { + ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + if (applicationInfo == null) { + return null; + } + PackageInfo info = generateWithoutComponents(pkg, gids, flags, firstInstallTime, + lastUpdateTime, grantedPermissions, state, userId, apexInfo, applicationInfo); + + if (info == null) { + return null; + } + + if ((flags & PackageManager.GET_ACTIVITIES) != 0) { + final int N = pkg.getActivities().size(); + if (N > 0) { + int num = 0; + final ActivityInfo[] res = new ActivityInfo[N]; + for (int i = 0; i < N; i++) { + final ParsedActivity a = pkg.getActivities().get(i); + if (ComponentParseUtils.isMatch(state, false, pkg.isEnabled(), a, + flags)) { + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals( + a.getName())) { + continue; + } + res[num++] = generateActivityInfo(pkg, a, flags, state, + applicationInfo, userId); + } + } + info.activities = ArrayUtils.trimToSize(res, num); + } + } + if ((flags & PackageManager.GET_RECEIVERS) != 0) { + final int size = pkg.getReceivers().size(); + if (size > 0) { + int num = 0; + final ActivityInfo[] res = new ActivityInfo[size]; + for (int i = 0; i < size; i++) { + final ParsedActivity a = pkg.getReceivers().get(i); + if (ComponentParseUtils.isMatch(state, false, pkg.isEnabled(), a, + flags)) { + res[num++] = generateActivityInfo(pkg, a, flags, state, + applicationInfo, userId); + } + } + info.receivers = ArrayUtils.trimToSize(res, num); + } + } + if ((flags & PackageManager.GET_SERVICES) != 0) { + final int size = pkg.getServices().size(); + if (size > 0) { + int num = 0; + final ServiceInfo[] res = new ServiceInfo[size]; + for (int i = 0; i < size; i++) { + final ParsedService s = pkg.getServices().get(i); + if (ComponentParseUtils.isMatch(state, false, pkg.isEnabled(), s, + flags)) { + res[num++] = generateServiceInfo(pkg, s, flags, state, + applicationInfo, userId); + } + } + info.services = ArrayUtils.trimToSize(res, num); + } + } + if ((flags & PackageManager.GET_PROVIDERS) != 0) { + final int size = pkg.getProviders().size(); + if (size > 0) { + int num = 0; + final ProviderInfo[] res = new ProviderInfo[size]; + for (int i = 0; i < size; i++) { + final ParsedProvider pr = pkg.getProviders() + .get(i); + if (ComponentParseUtils.isMatch(state, false, pkg.isEnabled(), pr, + flags)) { + res[num++] = generateProviderInfo(pkg, pr, flags, state, + applicationInfo, userId); + } + } + info.providers = ArrayUtils.trimToSize(res, num); + } + } + if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) { + int N = pkg.getInstrumentations().size(); + if (N > 0) { + info.instrumentation = new InstrumentationInfo[N]; + for (int i = 0; i < N; i++) { + info.instrumentation[i] = generateInstrumentationInfo( + pkg.getInstrumentations().get(i), pkg, flags, userId); + } + } + } + + return info; + } + + @Nullable + public static PackageInfo generateWithoutComponents(ParsingPackageRead pkg, int[] gids, + @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, + Set<String> grantedPermissions, PackageUserState state, int userId, + @Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) { + if (!checkUseInstalled(pkg, state, flags)) { + return null; + } + + PackageInfo pi = new PackageInfo(); + pi.packageName = pkg.getPackageName(); + pi.splitNames = pkg.getSplitNames(); + pi.versionCode = pkg.getVersionCode(); + pi.versionCodeMajor = pkg.getVersionCodeMajor(); + pi.baseRevisionCode = pkg.getBaseRevisionCode(); + pi.splitRevisionCodes = pkg.getSplitRevisionCodes(); + pi.versionName = pkg.getVersionName(); + pi.sharedUserId = pkg.getSharedUserId(); + pi.sharedUserLabel = pkg.getSharedUserLabel(); + pi.applicationInfo = applicationInfo; + pi.installLocation = pkg.getInstallLocation(); + if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 + || (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + pi.requiredForAllUsers = pkg.isRequiredForAllUsers(); + } + pi.restrictedAccountType = pkg.getRestrictedAccountType(); + pi.requiredAccountType = pkg.getRequiredAccountType(); + pi.overlayTarget = pkg.getOverlayTarget(); + pi.targetOverlayableName = pkg.getOverlayTargetName(); + pi.overlayCategory = pkg.getOverlayCategory(); + pi.overlayPriority = pkg.getOverlayPriority(); + pi.mOverlayIsStatic = pkg.isOverlayIsStatic(); + pi.compileSdkVersion = pkg.getCompileSdkVersion(); + pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName(); + pi.firstInstallTime = firstInstallTime; + pi.lastUpdateTime = lastUpdateTime; + if ((flags & PackageManager.GET_GIDS) != 0) { + pi.gids = gids; + } + if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) { + int size = pkg.getConfigPreferences().size(); + if (size > 0) { + pi.configPreferences = new ConfigurationInfo[size]; + pkg.getConfigPreferences().toArray(pi.configPreferences); + } + size = pkg.getReqFeatures().size(); + if (size > 0) { + pi.reqFeatures = new FeatureInfo[size]; + pkg.getReqFeatures().toArray(pi.reqFeatures); + } + size = pkg.getFeatureGroups().size(); + if (size > 0) { + pi.featureGroups = new FeatureGroupInfo[size]; + pkg.getFeatureGroups().toArray(pi.featureGroups); + } + } + if ((flags & PackageManager.GET_PERMISSIONS) != 0) { + int size = ArrayUtils.size(pkg.getPermissions()); + if (size > 0) { + pi.permissions = new PermissionInfo[size]; + for (int i = 0; i < size; i++) { + pi.permissions[i] = generatePermissionInfo(pkg.getPermissions().get(i), + flags); + } + } + size = pkg.getRequestedPermissions().size(); + if (size > 0) { + pi.requestedPermissions = new String[size]; + pi.requestedPermissionsFlags = new int[size]; + for (int i = 0; i < size; i++) { + final String perm = pkg.getRequestedPermissions().get(i); + pi.requestedPermissions[i] = perm; + // The notion of required permissions is deprecated but for compatibility. + pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED; + if (grantedPermissions != null && grantedPermissions.contains(perm)) { + pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED; + } + } + } + } + + if (apexInfo != null) { + File apexFile = new File(apexInfo.modulePath); + + pi.applicationInfo.sourceDir = apexFile.getPath(); + pi.applicationInfo.publicSourceDir = apexFile.getPath(); + if (apexInfo.isFactory) { + pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; + } else { + pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; + } + if (apexInfo.isActive) { + pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; + } else { + pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; + } + pi.isApex = true; + } + + PackageParser.SigningDetails signingDetails = pkg.getSigningDetails(); + // deprecated method of getting signing certificates + if ((flags & PackageManager.GET_SIGNATURES) != 0) { + if (signingDetails.hasPastSigningCertificates()) { + // Package has included signing certificate rotation information. Return the oldest + // cert so that programmatic checks keep working even if unaware of key rotation. + pi.signatures = new Signature[1]; + pi.signatures[0] = signingDetails.pastSigningCertificates[0]; + } else if (signingDetails.hasSignatures()) { + // otherwise keep old behavior + int numberOfSigs = signingDetails.signatures.length; + pi.signatures = new Signature[numberOfSigs]; + System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0, + numberOfSigs); + } + } + + // replacement for GET_SIGNATURES + if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) { + if (signingDetails != PackageParser.SigningDetails.UNKNOWN) { + // only return a valid SigningInfo if there is signing information to report + pi.signingInfo = new SigningInfo(signingDetails); + } else { + pi.signingInfo = null; + } + } + + return pi; + } + + @Nullable + public static ApplicationInfo generateApplicationInfo(ParsingPackageRead pkg, + @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) { + if (pkg == null) { + return null; + } + + if (!checkUseInstalled(pkg, state, flags)) { + return null; + } + + // Make shallow copy so we can store the metadata/libraries safely + ApplicationInfo ai = pkg.toAppInfoWithoutState(); + // Init handles data directories + // TODO(b/135203078): Consolidate the data directory logic, remove initForUser + ai.initForUser(userId); + + ai.flags = appInfoFlags(pkg); + ai.privateFlags = appInfoPrivateFlags(pkg); + + if ((flags & PackageManager.GET_META_DATA) == 0) { + ai.metaData = null; + } + if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) { + ai.sharedLibraryFiles = null; + ai.sharedLibraryInfos = null; + } + + // CompatibilityMode is global state. + if (!PackageParser.sCompatibilityModeEnabled) { + ai.disableCompatibilityMode(); + } + + ai.flags |= flag(state.stopped, ApplicationInfo.FLAG_STOPPED) + | flag(state.installed, ApplicationInfo.FLAG_INSTALLED) + | flag(state.suspended, ApplicationInfo.FLAG_SUSPENDED); + ai.privateFlags |= flag(state.instantApp, ApplicationInfo.PRIVATE_FLAG_INSTANT) + | flag(state.virtualPreload, ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD) + | flag(state.hidden, ApplicationInfo.PRIVATE_FLAG_HIDDEN); + + if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + ai.enabled = true; + } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { + ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; + } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED + || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + ai.enabled = false; + } + ai.enabledSetting = state.enabled; + if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { + ai.category = state.categoryHint; + } + if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { + ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName); + } + ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state); + ai.resourceDirs = state.getOverlayPaths(); + + return ai; + } + + @Nullable + public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, + @Nullable ApplicationInfo applicationInfo, int userId) { + if (a == null) return null; + if (!checkUseInstalled(pkg, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + } + // Make shallow copies so we can store the metadata safely + ActivityInfo ai = new ActivityInfo(); + assignSharedFieldsForComponentInfo(ai, a); + ai.targetActivity = a.getTargetActivity(); + ai.processName = a.getProcessName(); + ai.exported = a.isExported(); + ai.theme = a.getTheme(); + ai.uiOptions = a.getUiOptions(); + ai.parentActivityName = a.getParentActivityName(); + ai.permission = a.getPermission(); + ai.taskAffinity = a.getTaskAffinity(); + ai.flags = a.getFlags(); + ai.privateFlags = a.getPrivateFlags(); + ai.launchMode = a.getLaunchMode(); + ai.documentLaunchMode = a.getDocumentLaunchMode(); + ai.maxRecents = a.getMaxRecents(); + ai.configChanges = a.getConfigChanges(); + ai.softInputMode = a.getSoftInputMode(); + ai.persistableMode = a.getPersistableMode(); + ai.lockTaskLaunchMode = a.getLockTaskLaunchMode(); + ai.screenOrientation = a.getScreenOrientation(); + ai.resizeMode = a.getResizeMode(); + Float maxAspectRatio = a.getMaxAspectRatio(); + ai.maxAspectRatio = maxAspectRatio != null ? maxAspectRatio : 0f; + Float minAspectRatio = a.getMinAspectRatio(); + ai.minAspectRatio = minAspectRatio != null ? minAspectRatio : 0f; + ai.requestedVrComponent = a.getRequestedVrComponent(); + ai.rotationAnimation = a.getRotationAnimation(); + ai.colorMode = a.getColorMode(); + ai.preferMinimalPostProcessing = a.isPreferMinimalPostProcessing(); + ai.windowLayout = a.getWindowLayout(); + ai.metaData = a.getMetaData(); + ai.applicationInfo = applicationInfo; + return ai; + } + + @Nullable + public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) { + return generateActivityInfo(pkg, a, flags, state, null, userId); + } + + @Nullable + public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, + @Nullable ApplicationInfo applicationInfo, int userId) { + if (s == null) return null; + if (!checkUseInstalled(pkg, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + } + // Make shallow copies so we can store the metadata safely + ServiceInfo si = new ServiceInfo(); + assignSharedFieldsForComponentInfo(si, s); + si.exported = s.isExported(); + si.flags = s.getFlags(); + si.metaData = s.getMetaData(); + si.permission = s.getPermission(); + si.processName = s.getProcessName(); + si.mForegroundServiceType = s.getForegroundServiceType(); + si.applicationInfo = applicationInfo; + return si; + } + + @Nullable + public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) { + return generateServiceInfo(pkg, s, flags, state, null, userId); + } + + @Nullable + public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, + @Nullable ApplicationInfo applicationInfo, int userId) { + if (p == null) return null; + if (!checkUseInstalled(pkg, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + } + // Make shallow copies so we can store the metadata safely + ProviderInfo pi = new ProviderInfo(); + assignSharedFieldsForComponentInfo(pi, p); + pi.exported = p.isExported(); + pi.flags = p.getFlags(); + pi.processName = p.getProcessName(); + pi.authority = p.getAuthority(); + pi.isSyncable = p.isSyncable(); + pi.readPermission = p.getReadPermission(); + pi.writePermission = p.getWritePermission(); + pi.grantUriPermissions = p.isGrantUriPermissions(); + pi.forceUriPermissions = p.isForceUriPermissions(); + pi.multiprocess = p.isMultiProcess(); + pi.initOrder = p.getInitOrder(); + pi.uriPermissionPatterns = p.getUriPermissionPatterns(); + pi.pathPermissions = p.getPathPermissions(); + pi.metaData = p.getMetaData(); + if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { + pi.uriPermissionPatterns = null; + } + pi.applicationInfo = applicationInfo; + return pi; + } + + @Nullable + public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) { + return generateProviderInfo(pkg, p, flags, state, null, userId); + } + + @Nullable + public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i, + ParsingPackageRead pkg, @PackageManager.ComponentInfoFlags int flags, int userId) { + if (i == null) return null; + + InstrumentationInfo ii = new InstrumentationInfo(); + assignSharedFieldsForPackageItemInfo(ii, i); + ii.targetPackage = i.getTargetPackage(); + ii.targetProcesses = i.getTargetProcesses(); + ii.handleProfiling = i.isHandleProfiling(); + ii.functionalTest = i.isFunctionalTest(); + + ii.sourceDir = pkg.getBaseCodePath(); + ii.publicSourceDir = pkg.getBaseCodePath(); + ii.splitNames = pkg.getSplitNames(); + ii.splitSourceDirs = pkg.getSplitCodePaths(); + ii.splitPublicSourceDirs = pkg.getSplitCodePaths(); + ii.splitDependencies = pkg.getSplitDependencies(); + ii.dataDir = getDataDir(pkg, userId).getAbsolutePath(); + ii.deviceProtectedDataDir = getDeviceProtectedDataDir(pkg, userId).getAbsolutePath(); + ii.credentialProtectedDataDir = getCredentialProtectedDataDir(pkg, + userId).getAbsolutePath(); + + if ((flags & PackageManager.GET_META_DATA) == 0) { + return ii; + } + ii.metaData = i.getMetaData(); + return ii; + } + + @Nullable + public static PermissionInfo generatePermissionInfo(ParsedPermission p, + @PackageManager.ComponentInfoFlags int flags) { + if (p == null) return null; + + PermissionInfo pi = new PermissionInfo(p.getBackgroundPermission()); + + assignSharedFieldsForPackageItemInfo(pi, p); + + pi.group = p.getGroup(); + pi.requestRes = p.getRequestRes(); + pi.protectionLevel = p.getProtectionLevel(); + pi.descriptionRes = p.getDescriptionRes(); + pi.flags = p.getFlags(); + + if ((flags & PackageManager.GET_META_DATA) == 0) { + return pi; + } + pi.metaData = p.getMetaData(); + return pi; + } + + @Nullable + public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg, + @PackageManager.ComponentInfoFlags int flags) { + if (pg == null) return null; + + PermissionGroupInfo pgi = new PermissionGroupInfo( + pg.getRequestDetailResourceId(), + pg.getBackgroundRequestResourceId(), + pg.getBackgroundRequestDetailResourceId() + ); + + assignSharedFieldsForPackageItemInfo(pgi, pg); + pgi.descriptionRes = pg.getDescriptionRes(); + pgi.priority = pg.getPriority(); + pgi.requestRes = pg.getRequestRes(); + pgi.flags = pg.getFlags(); + + if ((flags & PackageManager.GET_META_DATA) == 0) { + return pgi; + } + pgi.metaData = pg.getMetaData(); + return pgi; + } + + private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo, + @NonNull ParsedMainComponent mainComponent) { + assignSharedFieldsForPackageItemInfo(componentInfo, mainComponent); + componentInfo.descriptionRes = mainComponent.getDescriptionRes(); + componentInfo.directBootAware = mainComponent.isDirectBootAware(); + componentInfo.enabled = mainComponent.isEnabled(); + componentInfo.splitName = mainComponent.getSplitName(); + } + + private static void assignSharedFieldsForPackageItemInfo( + @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component) { + packageItemInfo.nonLocalizedLabel = ComponentParseUtils.getNonLocalizedLabel(component); + packageItemInfo.icon = ComponentParseUtils.getIcon(component); + + packageItemInfo.banner = component.getBanner(); + packageItemInfo.labelRes = component.getLabelRes(); + packageItemInfo.logo = component.getLogo(); + packageItemInfo.name = component.getName(); + packageItemInfo.packageName = component.getPackageName(); + } + + @CheckResult + private static int flag(boolean hasFlag, int flag) { + if (hasFlag) { + return flag; + } else { + return 0; + } + } + + /** @see ApplicationInfo#flags */ + public static int appInfoFlags(ParsingPackageRead pkg) { + // @formatter:off + return flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE) + | flag(pkg.isBaseHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED) + | flag(pkg.isAllowBackup(), ApplicationInfo.FLAG_ALLOW_BACKUP) + | flag(pkg.isKillAfterRestore(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE) + | flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION) + | flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY) + | flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT) + | flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE) + | flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE) + | flag(pkg.isHasCode(), ApplicationInfo.FLAG_HAS_CODE) + | flag(pkg.isAllowTaskReparenting(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) + | flag(pkg.isAllowClearUserData(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) + | flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP) + | flag(pkg.isUsesCleartextTraffic(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) + | flag(pkg.isSupportsRtl(), ApplicationInfo.FLAG_SUPPORTS_RTL) + | flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY) + | flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH) + | flag(pkg.isExtractNativeLibs(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) + | flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME) + | flag(pkg.isSupportsSmallScreens(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) + | flag(pkg.isSupportsNormalScreens(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) + | flag(pkg.isSupportsLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) + | flag(pkg.isSupportsExtraLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) + | flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) + | flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES); + // @formatter:on + } + + /** @see ApplicationInfo#privateFlags */ + public static int appInfoPrivateFlags(ParsingPackageRead pkg) { + // @formatter:off + int privateFlags = flag(pkg.isStaticSharedLibrary(), ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) + | flag(pkg.isOverlay(), ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY) + | flag(pkg.isIsolatedSplitLoading(), ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) + | flag(pkg.isHasDomainUrls(), ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) + | flag(pkg.isProfileableByShell(), ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) + | flag(pkg.isBackupInForeground(), ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND) + | flag(pkg.isUseEmbeddedDex(), ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX) + | flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) + | flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) + | flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) + | flag(pkg.isAllowClearUserDataOnFailedRestore(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE) + | flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE) + | flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) + | flag(pkg.isUsesNonSdkApi(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API) + | flag(pkg.isHasFragileUserData(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA) + | flag(pkg.isCantSaveState(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) + | flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) + | flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING); + // @formatter:on + + Boolean resizeableActivity = pkg.getResizeableActivity(); + if (resizeableActivity != null) { + if (resizeableActivity) { + privateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; + } else { + privateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; + } + } + + return privateFlags; + } + + private static boolean checkUseInstalled(ParsingPackageRead pkg, PackageUserState state, + @PackageManager.PackageInfoFlags int flags) { + // If available for the target user + return state.isAvailable(flags); + } + + @NonNull + public static File getDataDir(ParsingPackageRead pkg, int userId) { + if ("android".equals(pkg.getPackageName())) { + return Environment.getDataSystemDirectory(); + } + + if (pkg.isDefaultToDeviceProtectedStorage() + && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { + return getDeviceProtectedDataDir(pkg, userId); + } else { + return getCredentialProtectedDataDir(pkg, userId); + } + } + + @NonNull + public static File getDeviceProtectedDataDir(ParsingPackageRead pkg, int userId) { + return Environment.getDataUserDePackageDirectory(pkg.getVolumeUuid(), userId, + pkg.getPackageName()); + } + + @NonNull + public static File getCredentialProtectedDataDir(ParsingPackageRead pkg, int userId) { + return Environment.getDataUserCePackageDirectory(pkg.getVolumeUuid(), userId, + pkg.getPackageName()); + } +} diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java index 74a2640446f0..aa93d80fbfeb 100644 --- a/core/java/android/content/pm/parsing/ParsingPackage.java +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,35 +16,36 @@ package android.content.pm.parsing; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; import android.content.pm.ConfigurationInfo; import android.content.pm.FeatureGroupInfo; import android.content.pm.FeatureInfo; import android.content.pm.PackageParser; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedFeature; -import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; -import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; -import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedFeature; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.content.pm.parsing.component.ParsedProcess; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; import android.os.Bundle; -import android.util.ArrayMap; -import android.util.ArraySet; import android.util.SparseArray; import java.security.PublicKey; +import java.util.Map; +import java.util.Set; /** * Methods used for mutation during direct package parsing. * - * Java disallows defining this as an inner interface, so this must be a separate file. - * * @hide */ -public interface ParsingPackage extends AndroidPackage { +@SuppressWarnings("UnusedReturnValue") +public interface ParsingPackage extends ParsingPackageRead { ParsingPackage addActivity(ParsedActivity parsedActivity); @@ -66,18 +67,18 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage addOverlayable(String overlayableName, String actorName); - ParsingPackage addFeature(ParsedFeature permission); - ParsingPackage addPermission(ParsedPermission permission); ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup); - ParsingPackage addPreferredActivityFilter(ParsedActivityIntentInfo activityIntentInfo); + ParsingPackage addPreferredActivityFilter(String className, ParsedIntentInfo intentInfo); ParsingPackage addProtectedBroadcast(String protectedBroadcast); ParsingPackage addProvider(ParsedProvider parsedProvider); + ParsingPackage addFeature(ParsedFeature permission); + ParsingPackage addReceiver(ParsedActivity parsedReceiver); ParsingPackage addReqFeature(FeatureInfo reqFeature); @@ -102,7 +103,7 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage addQueriesProvider(String authority); - ParsingPackage setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes); + ParsingPackage setProcesses(@NonNull Map<String, ParsedProcess> processes); ParsingPackage asSplit( String[] splitNames, @@ -111,7 +112,7 @@ public interface ParsingPackage extends AndroidPackage { @Nullable SparseArray<int[]> splitDependencies ); - ParsingPackage setAppMetaData(Bundle appMetaData); + ParsingPackage setMetaData(Bundle metaData); ParsingPackage setForceQueryable(boolean forceQueryable); @@ -119,8 +120,6 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage setMinAspectRatio(float minAspectRatio); - ParsingPackage setName(String name); - ParsingPackage setPermission(String permission); ParsingPackage setProcessName(String processName); @@ -137,9 +136,9 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage setBaseHardwareAccelerated(boolean baseHardwareAccelerated); - ParsingPackage setActivitiesResizeModeResizeable(boolean resizeable); + ParsingPackage setResizeableActivity(Boolean resizeable); - ParsingPackage setActivitiesResizeModeResizeableViaSdkVersion(boolean resizeableViaSdkVersion); + ParsingPackage setResizeableActivityViaSdkVersion(boolean resizeableViaSdkVersion); ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture); @@ -151,7 +150,7 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting); - ParsingPackage setIsOverlay(boolean isOverlay); + ParsingPackage setOverlay(boolean isOverlay); ParsingPackage setBackupInForeground(boolean backupInForeground); @@ -173,7 +172,7 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage setHasFragileUserData(boolean hasFragileUserData); - ParsingPackage setIsGame(boolean isGame); + ParsingPackage setGame(boolean isGame); ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading); @@ -221,8 +220,6 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage setAppComponentFactory(String appComponentFactory); - ParsingPackage setApplicationVolumeUuid(String applicationVolumeUuid); - ParsingPackage setBackupAgentName(String backupAgentName); ParsingPackage setBanner(int banner); @@ -233,8 +230,6 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage setClassName(String className); - ParsingPackage setCodePath(String codePath); - ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp); ParsingPackage setDescriptionRes(int descriptionRes); @@ -247,8 +242,6 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage setHasDomainUrls(boolean hasDomainUrls); - ParsingPackage setIcon(int icon); - ParsingPackage setIconRes(int iconRes); ParsingPackage setInstallLocation(int installLocation); @@ -307,17 +300,17 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage setSupportsSmallScreens(int supportsSmallScreens); - ParsingPackage setSupportsXLargeScreens(int supportsXLargeScreens); + ParsingPackage setSupportsExtraLargeScreens(int supportsExtraLargeScreens); ParsingPackage setTargetSandboxVersion(int targetSandboxVersion); ParsingPackage setTheme(int theme); - ParsingPackage setUpgradeKeySets(ArraySet<String> upgradeKeySets); + ParsingPackage setUpgradeKeySets(@NonNull Set<String> upgradeKeySets); ParsingPackage setUse32BitAbi(boolean use32BitAbi); - ParsingPackage setVolumeUuid(String volumeUuid); + ParsingPackage setVolumeUuid(@Nullable String volumeUuid); ParsingPackage setZygotePreloadName(String zygotePreloadName); @@ -327,17 +320,16 @@ public interface ParsingPackage extends AndroidPackage { ParsingPackage sortServices(); - ParsedPackage hideAsParsed(); - ParsingPackage setBaseRevisionCode(int baseRevisionCode); - ParsingPackage setPreferredOrder(int preferredOrder); - ParsingPackage setVersionName(String versionName); ParsingPackage setCompileSdkVersion(int compileSdkVersion); ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename); - boolean usesCompatibilityMode(); + // TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement + // for moving to the next step + @Deprecated + Object hideAsParsed(); } diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java new file mode 100644 index 000000000000..c3eea2b2de86 --- /dev/null +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -0,0 +1,2584 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageParser; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedComponent; +import android.content.pm.parsing.component.ParsedFeature; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedMainComponent; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.content.pm.parsing.component.ParsedProcess; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; +import android.content.res.TypedArray; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.storage.StorageManager; +import android.text.TextUtils; +import android.util.ArraySet; +import android.util.Pair; +import android.util.SparseArray; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForBoolean; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArray; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringList; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringValueMap; + +import java.security.PublicKey; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The backing data for a package that was parsed from disk. + * + * The field nullability annotations here are for internal reference. For effective nullability, + * see the parent interfaces. + * + * TODO(b/135203078): Convert Lists used as sets into Sets, to better express intended use case + * + * @hide + */ +public class ParsingPackageImpl implements ParsingPackage, Parcelable { + + private static final String TAG = "PackageImpl"; + + public static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class); + public static ForInternedString sForString = Parcelling.Cache.getOrCreate( + ForInternedString.class); + public static ForInternedStringArray sForStringArray = Parcelling.Cache.getOrCreate( + ForInternedStringArray.class); + public static ForInternedStringList sForStringList = Parcelling.Cache.getOrCreate( + ForInternedStringList.class); + public static ForInternedStringValueMap sForStringValueMap = Parcelling.Cache.getOrCreate( + ForInternedStringValueMap.class); + public static ForInternedStringSet sForStringSet = Parcelling.Cache.getOrCreate( + ForInternedStringSet.class); + protected static ParsedIntentInfo.StringPairListParceler sForIntentInfoPairs = + Parcelling.Cache.getOrCreate(ParsedIntentInfo.StringPairListParceler.class); + + private static final Comparator<ParsedMainComponent> ORDER_COMPARATOR = + (first, second) -> Integer.compare(second.getOrder(), first.getOrder()); + + // These are objects because null represents not explicitly set + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + private Boolean supportsSmallScreens; + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + private Boolean supportsNormalScreens; + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + private Boolean supportsLargeScreens; + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + private Boolean supportsExtraLargeScreens; + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + private Boolean resizeable; + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + private Boolean anyDensity; + + protected int versionCode; + protected int versionCodeMajor; + private int baseRevisionCode; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String versionName; + + private int compileSdkVersion; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String compileSdkVersionCodeName; + + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + protected String packageName; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String realPackage; + + @NonNull + protected String baseCodePath; + + private boolean requiredForAllUsers; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String restrictedAccountType; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String requiredAccountType; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String overlayTarget; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String overlayTargetName; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String overlayCategory; + private int overlayPriority; + private boolean overlayIsStatic; + @NonNull + @DataClass.ParcelWith(ForInternedStringValueMap.class) + private Map<String, String> overlayables = emptyMap(); + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String staticSharedLibName; + private long staticSharedLibVersion; + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + private List<String> libraryNames = emptyList(); + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + protected List<String> usesLibraries = emptyList(); + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + protected List<String> usesOptionalLibraries = emptyList(); + + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + private List<String> usesStaticLibraries = emptyList(); + @Nullable + private long[] usesStaticLibrariesVersions; + + @Nullable + private String[][] usesStaticLibrariesCertDigests; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String sharedUserId; + + private int sharedUserLabel; + @NonNull + private List<ConfigurationInfo> configPreferences = emptyList(); + @NonNull + private List<FeatureInfo> reqFeatures = emptyList(); + @NonNull + private List<FeatureGroupInfo> featureGroups = emptyList(); + + @Nullable + private byte[] restrictUpdateHash; + + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + protected List<String> originalPackages = emptyList(); + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + protected List<String> adoptPermissions = emptyList(); + + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + private List<String> requestedPermissions = emptyList(); + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + private List<String> implicitPermissions = emptyList(); + + @NonNull + private Set<String> upgradeKeySets = emptySet(); + @NonNull + private Map<String, ArraySet<PublicKey>> keySetMapping = emptyMap(); + + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + protected List<String> protectedBroadcasts = emptyList(); + + @NonNull + protected List<ParsedActivity> activities = emptyList(); + + @NonNull + protected List<ParsedActivity> receivers = emptyList(); + + @NonNull + protected List<ParsedService> services = emptyList(); + + @NonNull + protected List<ParsedProvider> providers = emptyList(); + + @NonNull + private List<ParsedFeature> features = emptyList(); + + @NonNull + protected List<ParsedPermission> permissions = emptyList(); + + @NonNull + protected List<ParsedPermissionGroup> permissionGroups = emptyList(); + + @NonNull + protected List<ParsedInstrumentation> instrumentations = emptyList(); + + @NonNull + @DataClass.ParcelWith(ParsedIntentInfo.ListParceler.class) + private List<Pair<String, ParsedIntentInfo>> preferredActivityFilters = emptyList(); + + @NonNull + private Map<String, ParsedProcess> processes = emptyMap(); + + @Nullable + private Bundle metaData; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String volumeUuid; + @Nullable + private PackageParser.SigningDetails signingDetails; + + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + protected String codePath; + + private boolean use32BitAbi; + private boolean visibleToInstantApps; + + private boolean forceQueryable; + + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + private List<Intent> queriesIntents = emptyList(); + + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + private List<String> queriesPackages = emptyList(); + + @NonNull + @DataClass.ParcelWith(ForInternedStringSet.class) + private Set<String> queriesProviders = emptySet(); + + @Nullable + @DataClass.ParcelWith(ForInternedStringArray.class) + private String[] splitClassLoaderNames; + @Nullable + protected String[] splitCodePaths; + @Nullable + private SparseArray<int[]> splitDependencies; + @Nullable + private int[] splitFlags; + @Nullable + @DataClass.ParcelWith(ForInternedStringArray.class) + private String[] splitNames; + @Nullable + private int[] splitRevisionCodes; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String appComponentFactory; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String backupAgentName; + private int banner; + private int category; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String classLoaderName; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String className; + private int compatibleWidthLimitDp; + private int descriptionRes; + private boolean enabled; + private boolean crossProfile; + private int fullBackupContent; + private int iconRes; + private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION; + private int labelRes; + private int largestWidthLimitDp; + private int logo; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String manageSpaceActivityName; + private float maxAspectRatio; + private float minAspectRatio; + private int minSdkVersion; + private int networkSecurityConfigRes; + @Nullable + private CharSequence nonLocalizedLabel; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String permission; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String processName; + private int requiresSmallestWidthDp; + private int roundIconRes; + private int targetSandboxVersion; + private int targetSdkVersion; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String taskAffinity; + private int theme; + + private int uiOptions; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String zygotePreloadName; + + private boolean externalStorage; + private boolean baseHardwareAccelerated; + private boolean allowBackup; + private boolean killAfterRestore; + private boolean restoreAnyVersion; + private boolean fullBackupOnly; + private boolean persistent; + private boolean debuggable; + private boolean vmSafeMode; + private boolean hasCode; + private boolean allowTaskReparenting; + private boolean allowClearUserData; + private boolean largeHeap; + private boolean usesCleartextTraffic; + private boolean supportsRtl; + private boolean testOnly; + private boolean multiArch; + private boolean extractNativeLibs; + private boolean game; + + /** + * @see ParsingPackageRead#getResizeableActivity() + */ + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + private Boolean resizeableActivity; + + private boolean staticSharedLibrary; + private boolean overlay; + private boolean isolatedSplitLoading; + private boolean hasDomainUrls; + private boolean profileableByShell; + private boolean backupInForeground; + private boolean useEmbeddedDex; + private boolean defaultToDeviceProtectedStorage; + private boolean directBootAware; + private boolean partiallyDirectBootAware; + private boolean resizeableActivityViaSdkVersion; + private boolean allowClearUserDataOnFailedRestore; + private boolean allowAudioPlaybackCapture; + private boolean requestLegacyExternalStorage; + private boolean usesNonSdkApi; + private boolean hasFragileUserData; + private boolean cantSaveState; + private boolean allowNativeHeapPointerTagging; + private boolean preserveLegacyExternalStorage; + + // TODO(chiuwinson): Non-null + @Nullable + private ArraySet<String> mimeGroups; + + @VisibleForTesting + public ParsingPackageImpl(@NonNull String packageName, @NonNull String baseCodePath, + @NonNull String codePath, @Nullable TypedArray manifestArray) { + this.packageName = TextUtils.safeIntern(packageName); + this.baseCodePath = TextUtils.safeIntern(baseCodePath); + this.codePath = TextUtils.safeIntern(codePath); + + if (manifestArray != null) { + versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0); + versionCodeMajor = manifestArray.getInteger( + R.styleable.AndroidManifest_versionCodeMajor, 0); + setBaseRevisionCode( + manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode, 0)); + setVersionName(manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_versionName, 0)); + + setCompileSdkVersion(manifestArray.getInteger( + R.styleable.AndroidManifest_compileSdkVersion, 0)); + setCompileSdkVersionCodename(manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_compileSdkVersionCodename, 0)); + } + } + + public boolean isSupportsSmallScreens() { + if (supportsSmallScreens == null) { + return targetSdkVersion >= Build.VERSION_CODES.DONUT; + } + + return supportsSmallScreens; + } + + public boolean isSupportsNormalScreens() { + return supportsNormalScreens == null || supportsNormalScreens; + } + + public boolean isSupportsLargeScreens() { + if (supportsLargeScreens == null) { + return targetSdkVersion >= Build.VERSION_CODES.DONUT; + } + + return supportsLargeScreens; + } + + public boolean isSupportsExtraLargeScreens() { + if (supportsExtraLargeScreens == null) { + return targetSdkVersion >= Build.VERSION_CODES.GINGERBREAD; + } + + return supportsExtraLargeScreens; + } + + public boolean isResizeable() { + if (resizeable == null) { + return targetSdkVersion >= Build.VERSION_CODES.DONUT; + } + + return resizeable; + } + + public boolean isAnyDensity() { + if (anyDensity == null) { + return targetSdkVersion >= Build.VERSION_CODES.DONUT; + } + + return anyDensity; + } + + @Override + public ParsingPackageImpl sortActivities() { + Collections.sort(this.activities, ORDER_COMPARATOR); + return this; + } + + @Override + public ParsingPackageImpl sortReceivers() { + Collections.sort(this.receivers, ORDER_COMPARATOR); + return this; + } + + @Override + public ParsingPackageImpl sortServices() { + Collections.sort(this.services, ORDER_COMPARATOR); + return this; + } + + @Override + public ParsingPackageImpl setVersionName(String versionName) { + this.versionName = TextUtils.safeIntern(versionName); + return this; + } + + @Override + public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) { + this.compileSdkVersionCodeName = TextUtils.safeIntern(compileSdkVersionCodename); + return this; + } + + @Override + public Object hideAsParsed() { + // There is no equivalent for core-only parsing + throw new UnsupportedOperationException(); + } + + @Override + public ParsingPackageImpl addConfigPreference(ConfigurationInfo configPreference) { + this.configPreferences = CollectionUtils.add(this.configPreferences, configPreference); + return this; + } + + @Override + public ParsingPackageImpl addReqFeature(FeatureInfo reqFeature) { + this.reqFeatures = CollectionUtils.add(this.reqFeatures, reqFeature); + return this; + } + + @Override + public ParsingPackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) { + this.featureGroups = CollectionUtils.add(this.featureGroups, featureGroup); + return this; + } + + @Override + public ParsingPackageImpl addProtectedBroadcast(String protectedBroadcast) { + if (!this.protectedBroadcasts.contains(protectedBroadcast)) { + this.protectedBroadcasts = CollectionUtils.add(this.protectedBroadcasts, + TextUtils.safeIntern(protectedBroadcast)); + } + return this; + } + + @Override + public ParsingPackageImpl addInstrumentation(ParsedInstrumentation instrumentation) { + this.instrumentations = CollectionUtils.add(this.instrumentations, instrumentation); + return this; + } + + @Override + public ParsingPackageImpl addOriginalPackage(String originalPackage) { + this.originalPackages = CollectionUtils.add(this.originalPackages, + TextUtils.safeIntern(originalPackage)); + return this; + } + + @Override + public ParsingPackage addOverlayable(String overlayableName, String actorName) { + this.overlayables = CollectionUtils.add(this.overlayables, + TextUtils.safeIntern(overlayableName), TextUtils.safeIntern(actorName)); + return this; + } + + @Override + public ParsingPackageImpl addAdoptPermission(String adoptPermission) { + this.adoptPermissions = CollectionUtils.add(this.adoptPermissions, + TextUtils.safeIntern(adoptPermission)); + return this; + } + + @Override + public ParsingPackageImpl addPermission(ParsedPermission permission) { + this.permissions = CollectionUtils.add(this.permissions, permission); + return this; + } + + @Override + public ParsingPackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) { + this.permissionGroups = CollectionUtils.add(this.permissionGroups, permissionGroup); + return this; + } + + @Override + public ParsingPackageImpl addRequestedPermission(String permission) { + this.requestedPermissions = CollectionUtils.add(this.requestedPermissions, + TextUtils.safeIntern(permission)); + return this; + } + + @Override + public ParsingPackageImpl addImplicitPermission(String permission) { + this.implicitPermissions = CollectionUtils.add(this.implicitPermissions, + TextUtils.safeIntern(permission)); + return this; + } + + @Override + public ParsingPackageImpl addKeySet(String keySetName, PublicKey publicKey) { + ArraySet<PublicKey> publicKeys = keySetMapping.get(keySetName); + if (publicKeys == null) { + publicKeys = new ArraySet<>(); + } + publicKeys.add(publicKey); + keySetMapping = CollectionUtils.add(this.keySetMapping, keySetName, publicKeys); + return this; + } + + @Override + public ParsingPackageImpl addActivity(ParsedActivity parsedActivity) { + this.activities = CollectionUtils.add(this.activities, parsedActivity); + addMimeGroupsFromComponent(parsedActivity); + return this; + } + + @Override + public ParsingPackageImpl addReceiver(ParsedActivity parsedReceiver) { + this.receivers = CollectionUtils.add(this.receivers, parsedReceiver); + addMimeGroupsFromComponent(parsedReceiver); + return this; + } + + @Override + public ParsingPackageImpl addService(ParsedService parsedService) { + this.services = CollectionUtils.add(this.services, parsedService); + addMimeGroupsFromComponent(parsedService); + return this; + } + + @Override + public ParsingPackageImpl addProvider(ParsedProvider parsedProvider) { + this.providers = CollectionUtils.add(this.providers, parsedProvider); + addMimeGroupsFromComponent(parsedProvider); + return this; + } + + @Override + public ParsingPackageImpl addFeature(ParsedFeature feature) { + this.features = CollectionUtils.add(this.features, feature); + return this; + } + + @Override + public ParsingPackageImpl addLibraryName(String libraryName) { + this.libraryNames = CollectionUtils.add(this.libraryNames, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public ParsingPackageImpl addUsesOptionalLibrary(String libraryName) { + this.usesOptionalLibraries = CollectionUtils.add(this.usesOptionalLibraries, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public ParsingPackageImpl addUsesLibrary(String libraryName) { + this.usesLibraries = CollectionUtils.add(this.usesLibraries, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public ParsingPackageImpl removeUsesOptionalLibrary(String libraryName) { + this.usesOptionalLibraries = CollectionUtils.remove(this.usesOptionalLibraries, + libraryName); + return this; + } + + @Override + public ParsingPackageImpl addUsesStaticLibrary(String libraryName) { + this.usesStaticLibraries = CollectionUtils.add(this.usesStaticLibraries, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public ParsingPackageImpl addUsesStaticLibraryVersion(long version) { + this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions, + version, true); + return this; + } + + @Override + public ParsingPackageImpl addUsesStaticLibraryCertDigests(String[] certSha256Digests) { + this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class, + this.usesStaticLibrariesCertDigests, certSha256Digests, true); + return this; + } + + @Override + public ParsingPackageImpl addPreferredActivityFilter(String className, + ParsedIntentInfo intentInfo) { + this.preferredActivityFilters = CollectionUtils.add(this.preferredActivityFilters, + Pair.create(className, intentInfo)); + return this; + } + + @Override + public ParsingPackageImpl addQueriesIntent(Intent intent) { + this.queriesIntents = CollectionUtils.add(this.queriesIntents, intent); + return this; + } + + @Override + public ParsingPackageImpl addQueriesPackage(String packageName) { + this.queriesPackages = CollectionUtils.add(this.queriesPackages, + TextUtils.safeIntern(packageName)); + return this; + } + + @Override + public ParsingPackageImpl addQueriesProvider(String authority) { + this.queriesProviders = CollectionUtils.add(this.queriesProviders, + TextUtils.safeIntern(authority)); + return this; + } + + @Override + public ParsingPackageImpl setSupportsSmallScreens(int supportsSmallScreens) { + if (supportsSmallScreens == 1) { + return this; + } + + this.supportsSmallScreens = supportsSmallScreens < 0; + return this; + } + + @Override + public ParsingPackageImpl setSupportsNormalScreens(int supportsNormalScreens) { + if (supportsNormalScreens == 1) { + return this; + } + + this.supportsNormalScreens = supportsNormalScreens < 0; + return this; + } + + @Override + public ParsingPackageImpl setSupportsLargeScreens(int supportsLargeScreens) { + if (supportsLargeScreens == 1) { + return this; + } + + this.supportsLargeScreens = supportsLargeScreens < 0; + return this; + } + + @Override + public ParsingPackageImpl setSupportsExtraLargeScreens(int supportsExtraLargeScreens) { + if (supportsExtraLargeScreens == 1) { + return this; + } + + this.supportsExtraLargeScreens = supportsExtraLargeScreens < 0; + return this; + } + + @Override + public ParsingPackageImpl setResizeable(int resizeable) { + if (resizeable == 1) { + return this; + } + + this.resizeable = resizeable < 0; + return this; + } + + @Override + public ParsingPackageImpl setAnyDensity(int anyDensity) { + if (anyDensity == 1) { + return this; + } + + this.anyDensity = anyDensity < 0; + return this; + } + + @Override + public ParsingPackageImpl asSplit( + String[] splitNames, + String[] splitCodePaths, + int[] splitRevisionCodes, + SparseArray<int[]> splitDependencies + ) { + this.splitNames = splitNames; + + if (this.splitNames != null) { + for (int index = 0; index < this.splitNames.length; index++) { + splitNames[index] = TextUtils.safeIntern(splitNames[index]); + } + } + + this.splitCodePaths = splitCodePaths; + this.splitRevisionCodes = splitRevisionCodes; + this.splitDependencies = splitDependencies; + + int count = splitNames.length; + this.splitFlags = new int[count]; + this.splitClassLoaderNames = new String[count]; + return this; + } + + @Override + public ParsingPackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) { + this.splitFlags[splitIndex] = splitHasCode + ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE + : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE; + return this; + } + + @Override + public ParsingPackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) { + this.splitClassLoaderNames[splitIndex] = classLoaderName; + return this; + } + + @Override + public ParsingPackageImpl setProcessName(String processName) { + this.processName = TextUtils.safeIntern(processName); + return this; + } + + @Override + public ParsingPackageImpl setRealPackage(@Nullable String realPackage) { + this.realPackage = TextUtils.safeIntern(realPackage); + return this; + } + + @Override + public ParsingPackageImpl setRestrictedAccountType(@Nullable String restrictedAccountType) { + this.restrictedAccountType = TextUtils.safeIntern(restrictedAccountType); + return this; + } + + @Override + public ParsingPackageImpl setRequiredAccountType(@Nullable String requiredAccountType) { + this.requiredAccountType = TextUtils.nullIfEmpty(TextUtils.safeIntern(requiredAccountType)); + return this; + } + + @Override + public ParsingPackageImpl setOverlayTarget(@Nullable String overlayTarget) { + this.overlayTarget = TextUtils.safeIntern(overlayTarget); + return this; + } + + @Override + public ParsingPackageImpl setOverlayTargetName(@Nullable String overlayTargetName) { + this.overlayTargetName = TextUtils.safeIntern(overlayTargetName); + return this; + } + + @Override + public ParsingPackageImpl setOverlayCategory(@Nullable String overlayCategory) { + this.overlayCategory = TextUtils.safeIntern(overlayCategory); + return this; + } + + @Override + public ParsingPackageImpl setVolumeUuid(@Nullable String volumeUuid) { + this.volumeUuid = TextUtils.safeIntern(volumeUuid); + return this; + } + + @Override + public ParsingPackageImpl setAppComponentFactory(@Nullable String appComponentFactory) { + this.appComponentFactory = TextUtils.safeIntern(appComponentFactory); + return this; + } + + @Override + public ParsingPackageImpl setBackupAgentName(@Nullable String backupAgentName) { + this.backupAgentName = TextUtils.safeIntern(backupAgentName); + return this; + } + + @Override + public ParsingPackageImpl setClassLoaderName(@Nullable String classLoaderName) { + this.classLoaderName = TextUtils.safeIntern(classLoaderName); + return this; + } + + @Override + public ParsingPackageImpl setClassName(@Nullable String className) { + this.className = TextUtils.safeIntern(className); + return this; + } + + @Override + public ParsingPackageImpl setManageSpaceActivityName(@Nullable String manageSpaceActivityName) { + this.manageSpaceActivityName = TextUtils.safeIntern(manageSpaceActivityName); + return this; + } + + @Override + public ParsingPackageImpl setPermission(@Nullable String permission) { + this.permission = TextUtils.safeIntern(permission); + return this; + } + + @Override + public ParsingPackageImpl setTaskAffinity(@Nullable String taskAffinity) { + this.taskAffinity = TextUtils.safeIntern(taskAffinity); + return this; + } + + @Override + public ParsingPackageImpl setZygotePreloadName(@Nullable String zygotePreloadName) { + this.zygotePreloadName = TextUtils.safeIntern(zygotePreloadName); + return this; + } + + @Override + public ParsingPackageImpl setStaticSharedLibName(String staticSharedLibName) { + this.staticSharedLibName = TextUtils.safeIntern(staticSharedLibName); + return this; + } + + @Override + public ParsingPackageImpl setSharedUserId(String sharedUserId) { + this.sharedUserId = TextUtils.safeIntern(sharedUserId); + return this; + } + + @NonNull + @Override + public String getProcessName() { + return processName != null ? processName : packageName; + } + + @Override + public String toString() { + return "Package{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + packageName + "}"; + } + + @Deprecated + @Override + public ApplicationInfo toAppInfoWithoutState() { + ApplicationInfo appInfo = new ApplicationInfo(); + appInfo.flags = PackageInfoWithoutStateUtils.appInfoFlags(this); + appInfo.privateFlags = PackageInfoWithoutStateUtils.appInfoPrivateFlags(this); + + appInfo.appComponentFactory = appComponentFactory; + appInfo.backupAgentName = backupAgentName; + appInfo.banner = banner; + appInfo.category = category; + appInfo.classLoaderName = classLoaderName; + appInfo.className = className; + appInfo.compatibleWidthLimitDp = compatibleWidthLimitDp; + appInfo.compileSdkVersion = compileSdkVersion; + appInfo.compileSdkVersionCodename = compileSdkVersionCodeName; +// appInfo.credentialProtectedDataDir = credentialProtectedDataDir; +// appInfo.dataDir = dataDir; + appInfo.descriptionRes = descriptionRes; +// appInfo.deviceProtectedDataDir = deviceProtectedDataDir; + appInfo.enabled = enabled; + appInfo.fullBackupContent = fullBackupContent; +// appInfo.hiddenUntilInstalled = hiddenUntilInstalled; + appInfo.icon = (PackageParser.sUseRoundIcon && roundIconRes != 0) ? roundIconRes : iconRes; + appInfo.iconRes = iconRes; + appInfo.roundIconRes = roundIconRes; + appInfo.installLocation = installLocation; + appInfo.labelRes = labelRes; + appInfo.largestWidthLimitDp = largestWidthLimitDp; + appInfo.logo = logo; + appInfo.manageSpaceActivityName = manageSpaceActivityName; + appInfo.maxAspectRatio = maxAspectRatio; + appInfo.metaData = metaData; + appInfo.minAspectRatio = minAspectRatio; + appInfo.minSdkVersion = minSdkVersion; + appInfo.name = className; + if (appInfo.name != null) { + appInfo.name = appInfo.name.trim(); + } +// appInfo.nativeLibraryDir = nativeLibraryDir; +// appInfo.nativeLibraryRootDir = nativeLibraryRootDir; +// appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; + appInfo.networkSecurityConfigRes = networkSecurityConfigRes; + appInfo.nonLocalizedLabel = nonLocalizedLabel; + if (appInfo.nonLocalizedLabel != null) { + appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim(); + } + appInfo.packageName = packageName; + appInfo.permission = permission; +// appInfo.primaryCpuAbi = primaryCpuAbi; + appInfo.processName = getProcessName(); + appInfo.requiresSmallestWidthDp = requiresSmallestWidthDp; +// appInfo.secondaryCpuAbi = secondaryCpuAbi; +// appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir; +// appInfo.seInfo = seInfo; +// appInfo.seInfoUser = seInfoUser; +// appInfo.sharedLibraryFiles = usesLibraryFiles.isEmpty() +// ? null : usesLibraryFiles.toArray(new String[0]); +// appInfo.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos; + appInfo.splitClassLoaderNames = splitClassLoaderNames; + appInfo.splitDependencies = splitDependencies; + appInfo.splitNames = splitNames; + appInfo.storageUuid = StorageManager.convert(volumeUuid); + appInfo.targetSandboxVersion = targetSandboxVersion; + appInfo.targetSdkVersion = targetSdkVersion; + appInfo.taskAffinity = taskAffinity; + appInfo.theme = theme; +// appInfo.uid = uid; + appInfo.uiOptions = uiOptions; + appInfo.volumeUuid = volumeUuid; + appInfo.zygotePreloadName = zygotePreloadName; + appInfo.crossProfile = isCrossProfile(); + + appInfo.setBaseCodePath(baseCodePath); + appInfo.setBaseResourcePath(baseCodePath); + appInfo.setCodePath(codePath); + appInfo.setResourcePath(codePath); + appInfo.setSplitCodePaths(splitCodePaths); + appInfo.setSplitResourcePaths(splitCodePaths); + appInfo.setVersionCode(PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode)); + + // TODO(b/135203078): Can this be removed? Looks only used in ActivityInfo. +// appInfo.showUserIcon = pkg.getShowUserIcon(); + // TODO(b/135203078): Unused? +// appInfo.resourceDirs = pkg.getResourceDirs(); + // TODO(b/135203078): Unused? +// appInfo.enabledSetting = pkg.getEnabledSetting(); + // TODO(b/135203078): See ParsingPackageImpl#getHiddenApiEnforcementPolicy +// appInfo.mHiddenApiPolicy = pkg.getHiddenApiPolicy(); + + return appInfo; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + sForBoolean.parcel(this.supportsSmallScreens, dest, flags); + sForBoolean.parcel(this.supportsNormalScreens, dest, flags); + sForBoolean.parcel(this.supportsLargeScreens, dest, flags); + sForBoolean.parcel(this.supportsExtraLargeScreens, dest, flags); + sForBoolean.parcel(this.resizeable, dest, flags); + sForBoolean.parcel(this.anyDensity, dest, flags); + dest.writeInt(this.versionCode); + dest.writeInt(this.versionCodeMajor); + dest.writeInt(this.baseRevisionCode); + sForString.parcel(this.versionName, dest, flags); + dest.writeInt(this.compileSdkVersion); + sForString.parcel(this.compileSdkVersionCodeName, dest, flags); + sForString.parcel(this.packageName, dest, flags); + sForString.parcel(this.realPackage, dest, flags); + sForString.parcel(this.baseCodePath, dest, flags); + dest.writeBoolean(this.requiredForAllUsers); + sForString.parcel(this.restrictedAccountType, dest, flags); + sForString.parcel(this.requiredAccountType, dest, flags); + sForString.parcel(this.overlayTarget, dest, flags); + sForString.parcel(this.overlayTargetName, dest, flags); + sForString.parcel(this.overlayCategory, dest, flags); + dest.writeInt(this.overlayPriority); + dest.writeBoolean(this.overlayIsStatic); + sForStringValueMap.parcel(this.overlayables, dest, flags); + sForString.parcel(this.staticSharedLibName, dest, flags); + dest.writeLong(this.staticSharedLibVersion); + sForStringList.parcel(this.libraryNames, dest, flags); + sForStringList.parcel(this.usesLibraries, dest, flags); + sForStringList.parcel(this.usesOptionalLibraries, dest, flags); + sForStringList.parcel(this.usesStaticLibraries, dest, flags); + dest.writeLongArray(this.usesStaticLibrariesVersions); + + if (this.usesStaticLibrariesCertDigests == null) { + dest.writeInt(-1); + } else { + dest.writeInt(this.usesStaticLibrariesCertDigests.length); + for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) { + sForStringArray.parcel(this.usesStaticLibrariesCertDigests[index], dest, flags); + } + } + + sForString.parcel(this.sharedUserId, dest, flags); + dest.writeInt(this.sharedUserLabel); + dest.writeTypedList(this.configPreferences); + dest.writeTypedList(this.reqFeatures); + dest.writeTypedList(this.featureGroups); + dest.writeByteArray(this.restrictUpdateHash); + sForStringList.parcel(this.originalPackages, dest, flags); + sForStringList.parcel(this.adoptPermissions, dest, flags); + sForStringList.parcel(this.requestedPermissions, dest, flags); + sForStringList.parcel(this.implicitPermissions, dest, flags); + sForStringSet.parcel(this.upgradeKeySets, dest, flags); + dest.writeMap(this.keySetMapping); + sForStringList.parcel(this.protectedBroadcasts, dest, flags); + dest.writeTypedList(this.activities); + dest.writeTypedList(this.receivers); + dest.writeTypedList(this.services); + dest.writeTypedList(this.providers); + dest.writeTypedList(this.features); + dest.writeTypedList(this.permissions); + dest.writeTypedList(this.permissionGroups); + dest.writeTypedList(this.instrumentations); + sForIntentInfoPairs.parcel(this.preferredActivityFilters, dest, flags); + dest.writeMap(this.processes); + dest.writeBundle(this.metaData); + sForString.parcel(this.volumeUuid, dest, flags); + dest.writeParcelable(this.signingDetails, flags); + sForString.parcel(this.codePath, dest, flags); + dest.writeBoolean(this.use32BitAbi); + dest.writeBoolean(this.visibleToInstantApps); + dest.writeBoolean(this.forceQueryable); + dest.writeParcelableList(this.queriesIntents, flags); + sForStringList.parcel(this.queriesPackages, dest, flags); + sForString.parcel(this.appComponentFactory, dest, flags); + sForString.parcel(this.backupAgentName, dest, flags); + dest.writeInt(this.banner); + dest.writeInt(this.category); + sForString.parcel(this.classLoaderName, dest, flags); + sForString.parcel(this.className, dest, flags); + dest.writeInt(this.compatibleWidthLimitDp); + dest.writeInt(this.descriptionRes); + dest.writeBoolean(this.enabled); + dest.writeBoolean(this.crossProfile); + dest.writeInt(this.fullBackupContent); + dest.writeInt(this.iconRes); + dest.writeInt(this.installLocation); + dest.writeInt(this.labelRes); + dest.writeInt(this.largestWidthLimitDp); + dest.writeInt(this.logo); + sForString.parcel(this.manageSpaceActivityName, dest, flags); + dest.writeFloat(this.maxAspectRatio); + dest.writeFloat(this.minAspectRatio); + dest.writeInt(this.minSdkVersion); + dest.writeInt(this.networkSecurityConfigRes); + dest.writeCharSequence(this.nonLocalizedLabel); + sForString.parcel(this.permission, dest, flags); + sForString.parcel(this.processName, dest, flags); + dest.writeInt(this.requiresSmallestWidthDp); + dest.writeInt(this.roundIconRes); + dest.writeInt(this.targetSandboxVersion); + dest.writeInt(this.targetSdkVersion); + sForString.parcel(this.taskAffinity, dest, flags); + dest.writeInt(this.theme); + dest.writeInt(this.uiOptions); + sForString.parcel(this.zygotePreloadName, dest, flags); + sForStringArray.parcel(this.splitClassLoaderNames, dest, flags); + sForStringArray.parcel(this.splitCodePaths, dest, flags); + dest.writeSparseArray(this.splitDependencies); + dest.writeIntArray(this.splitFlags); + sForStringArray.parcel(this.splitNames, dest, flags); + dest.writeIntArray(this.splitRevisionCodes); + + dest.writeBoolean(this.externalStorage); + dest.writeBoolean(this.baseHardwareAccelerated); + dest.writeBoolean(this.allowBackup); + dest.writeBoolean(this.killAfterRestore); + dest.writeBoolean(this.restoreAnyVersion); + dest.writeBoolean(this.fullBackupOnly); + dest.writeBoolean(this.persistent); + dest.writeBoolean(this.debuggable); + dest.writeBoolean(this.vmSafeMode); + dest.writeBoolean(this.hasCode); + dest.writeBoolean(this.allowTaskReparenting); + dest.writeBoolean(this.allowClearUserData); + dest.writeBoolean(this.largeHeap); + dest.writeBoolean(this.usesCleartextTraffic); + dest.writeBoolean(this.supportsRtl); + dest.writeBoolean(this.testOnly); + dest.writeBoolean(this.multiArch); + dest.writeBoolean(this.extractNativeLibs); + dest.writeBoolean(this.game); + + sForBoolean.parcel(this.resizeableActivity, dest, flags); + + dest.writeBoolean(this.staticSharedLibrary); + dest.writeBoolean(this.overlay); + dest.writeBoolean(this.isolatedSplitLoading); + dest.writeBoolean(this.hasDomainUrls); + dest.writeBoolean(this.profileableByShell); + dest.writeBoolean(this.backupInForeground); + dest.writeBoolean(this.useEmbeddedDex); + dest.writeBoolean(this.defaultToDeviceProtectedStorage); + dest.writeBoolean(this.directBootAware); + dest.writeBoolean(this.partiallyDirectBootAware); + dest.writeBoolean(this.resizeableActivityViaSdkVersion); + dest.writeBoolean(this.allowClearUserDataOnFailedRestore); + dest.writeBoolean(this.allowAudioPlaybackCapture); + dest.writeBoolean(this.requestLegacyExternalStorage); + dest.writeBoolean(this.usesNonSdkApi); + dest.writeBoolean(this.hasFragileUserData); + dest.writeBoolean(this.cantSaveState); + dest.writeBoolean(this.allowNativeHeapPointerTagging); + dest.writeBoolean(this.preserveLegacyExternalStorage); + dest.writeArraySet(this.mimeGroups); + } + + public ParsingPackageImpl(Parcel in) { + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.supportsSmallScreens = sForBoolean.unparcel(in); + this.supportsNormalScreens = sForBoolean.unparcel(in); + this.supportsLargeScreens = sForBoolean.unparcel(in); + this.supportsExtraLargeScreens = sForBoolean.unparcel(in); + this.resizeable = sForBoolean.unparcel(in); + this.anyDensity = sForBoolean.unparcel(in); + this.versionCode = in.readInt(); + this.versionCodeMajor = in.readInt(); + this.baseRevisionCode = in.readInt(); + this.versionName = sForString.unparcel(in); + this.compileSdkVersion = in.readInt(); + this.compileSdkVersionCodeName = sForString.unparcel(in); + this.packageName = sForString.unparcel(in); + this.realPackage = sForString.unparcel(in); + this.baseCodePath = sForString.unparcel(in); + this.requiredForAllUsers = in.readBoolean(); + this.restrictedAccountType = sForString.unparcel(in); + this.requiredAccountType = sForString.unparcel(in); + this.overlayTarget = sForString.unparcel(in); + this.overlayTargetName = sForString.unparcel(in); + this.overlayCategory = sForString.unparcel(in); + this.overlayPriority = in.readInt(); + this.overlayIsStatic = in.readBoolean(); + this.overlayables = sForStringValueMap.unparcel(in); + this.staticSharedLibName = sForString.unparcel(in); + this.staticSharedLibVersion = in.readLong(); + this.libraryNames = sForStringList.unparcel(in); + this.usesLibraries = sForStringList.unparcel(in); + this.usesOptionalLibraries = sForStringList.unparcel(in); + this.usesStaticLibraries = sForStringList.unparcel(in); + this.usesStaticLibrariesVersions = in.createLongArray(); + + int digestsSize = in.readInt(); + if (digestsSize >= 0) { + this.usesStaticLibrariesCertDigests = new String[digestsSize][]; + for (int index = 0; index < digestsSize; index++) { + this.usesStaticLibrariesCertDigests[index] = sForStringArray.unparcel(in); + } + } + + this.sharedUserId = sForString.unparcel(in); + this.sharedUserLabel = in.readInt(); + this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR); + this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR); + this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR); + this.restrictUpdateHash = in.createByteArray(); + this.originalPackages = sForStringList.unparcel(in); + this.adoptPermissions = sForStringList.unparcel(in); + this.requestedPermissions = sForStringList.unparcel(in); + this.implicitPermissions = sForStringList.unparcel(in); + this.upgradeKeySets = sForStringSet.unparcel(in); + this.keySetMapping = in.readHashMap(boot); + this.protectedBroadcasts = sForStringList.unparcel(in); + this.activities = in.createTypedArrayList(ParsedActivity.CREATOR); + this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR); + this.services = in.createTypedArrayList(ParsedService.CREATOR); + this.providers = in.createTypedArrayList(ParsedProvider.CREATOR); + this.features = in.createTypedArrayList(ParsedFeature.CREATOR); + this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR); + this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR); + this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR); + this.preferredActivityFilters = sForIntentInfoPairs.unparcel(in); + this.processes = in.readHashMap(boot); + this.metaData = in.readBundle(boot); + this.volumeUuid = sForString.unparcel(in); + this.signingDetails = in.readParcelable(boot); + this.codePath = sForString.unparcel(in); + this.use32BitAbi = in.readBoolean(); + this.visibleToInstantApps = in.readBoolean(); + this.forceQueryable = in.readBoolean(); + this.queriesIntents = in.createTypedArrayList(Intent.CREATOR); + this.queriesPackages = sForStringList.unparcel(in); + this.appComponentFactory = sForString.unparcel(in); + this.backupAgentName = sForString.unparcel(in); + this.banner = in.readInt(); + this.category = in.readInt(); + this.classLoaderName = sForString.unparcel(in); + this.className = sForString.unparcel(in); + this.compatibleWidthLimitDp = in.readInt(); + this.descriptionRes = in.readInt(); + this.enabled = in.readBoolean(); + this.crossProfile = in.readBoolean(); + this.fullBackupContent = in.readInt(); + this.iconRes = in.readInt(); + this.installLocation = in.readInt(); + this.labelRes = in.readInt(); + this.largestWidthLimitDp = in.readInt(); + this.logo = in.readInt(); + this.manageSpaceActivityName = sForString.unparcel(in); + this.maxAspectRatio = in.readFloat(); + this.minAspectRatio = in.readFloat(); + this.minSdkVersion = in.readInt(); + this.networkSecurityConfigRes = in.readInt(); + this.nonLocalizedLabel = in.readCharSequence(); + this.permission = sForString.unparcel(in); + this.processName = sForString.unparcel(in); + this.requiresSmallestWidthDp = in.readInt(); + this.roundIconRes = in.readInt(); + this.targetSandboxVersion = in.readInt(); + this.targetSdkVersion = in.readInt(); + this.taskAffinity = sForString.unparcel(in); + this.theme = in.readInt(); + this.uiOptions = in.readInt(); + this.zygotePreloadName = sForString.unparcel(in); + this.splitClassLoaderNames = sForStringArray.unparcel(in); + this.splitCodePaths = sForStringArray.unparcel(in); + this.splitDependencies = in.readSparseArray(boot); + this.splitFlags = in.createIntArray(); + this.splitNames = sForStringArray.unparcel(in); + this.splitRevisionCodes = in.createIntArray(); + this.externalStorage = in.readBoolean(); + this.baseHardwareAccelerated = in.readBoolean(); + this.allowBackup = in.readBoolean(); + this.killAfterRestore = in.readBoolean(); + this.restoreAnyVersion = in.readBoolean(); + this.fullBackupOnly = in.readBoolean(); + this.persistent = in.readBoolean(); + this.debuggable = in.readBoolean(); + this.vmSafeMode = in.readBoolean(); + this.hasCode = in.readBoolean(); + this.allowTaskReparenting = in.readBoolean(); + this.allowClearUserData = in.readBoolean(); + this.largeHeap = in.readBoolean(); + this.usesCleartextTraffic = in.readBoolean(); + this.supportsRtl = in.readBoolean(); + this.testOnly = in.readBoolean(); + this.multiArch = in.readBoolean(); + this.extractNativeLibs = in.readBoolean(); + this.game = in.readBoolean(); + + this.resizeableActivity = sForBoolean.unparcel(in); + + this.staticSharedLibrary = in.readBoolean(); + this.overlay = in.readBoolean(); + this.isolatedSplitLoading = in.readBoolean(); + this.hasDomainUrls = in.readBoolean(); + this.profileableByShell = in.readBoolean(); + this.backupInForeground = in.readBoolean(); + this.useEmbeddedDex = in.readBoolean(); + this.defaultToDeviceProtectedStorage = in.readBoolean(); + this.directBootAware = in.readBoolean(); + this.partiallyDirectBootAware = in.readBoolean(); + this.resizeableActivityViaSdkVersion = in.readBoolean(); + this.allowClearUserDataOnFailedRestore = in.readBoolean(); + this.allowAudioPlaybackCapture = in.readBoolean(); + this.requestLegacyExternalStorage = in.readBoolean(); + this.usesNonSdkApi = in.readBoolean(); + this.hasFragileUserData = in.readBoolean(); + this.cantSaveState = in.readBoolean(); + this.allowNativeHeapPointerTagging = in.readBoolean(); + this.preserveLegacyExternalStorage = in.readBoolean(); + this.mimeGroups = (ArraySet<String>) in.readArraySet(boot); + } + + public static final Parcelable.Creator<ParsingPackageImpl> CREATOR = + new Parcelable.Creator<ParsingPackageImpl>() { + @Override + public ParsingPackageImpl createFromParcel(Parcel source) { + return new ParsingPackageImpl(source); + } + + @Override + public ParsingPackageImpl[] newArray(int size) { + return new ParsingPackageImpl[size]; + } + }; + + @Override + public int getVersionCode() { + return versionCode; + } + + @Override + public int getVersionCodeMajor() { + return versionCodeMajor; + } + + @Override + public int getBaseRevisionCode() { + return baseRevisionCode; + } + + @Nullable + @Override + public String getVersionName() { + return versionName; + } + + @Override + public int getCompileSdkVersion() { + return compileSdkVersion; + } + + @Nullable + @Override + public String getCompileSdkVersionCodeName() { + return compileSdkVersionCodeName; + } + + @NonNull + @Override + public String getPackageName() { + return packageName; + } + + @Nullable + @Override + public String getRealPackage() { + return realPackage; + } + + @NonNull + @Override + public String getBaseCodePath() { + return baseCodePath; + } + + @Override + public boolean isRequiredForAllUsers() { + return requiredForAllUsers; + } + + @Nullable + @Override + public String getRestrictedAccountType() { + return restrictedAccountType; + } + + @Nullable + @Override + public String getRequiredAccountType() { + return requiredAccountType; + } + + @Nullable + @Override + public String getOverlayTarget() { + return overlayTarget; + } + + @Nullable + @Override + public String getOverlayTargetName() { + return overlayTargetName; + } + + @Nullable + @Override + public String getOverlayCategory() { + return overlayCategory; + } + + @Override + public int getOverlayPriority() { + return overlayPriority; + } + + @Override + public boolean isOverlayIsStatic() { + return overlayIsStatic; + } + + @NonNull + @Override + public Map<String,String> getOverlayables() { + return overlayables; + } + + @Nullable + @Override + public String getStaticSharedLibName() { + return staticSharedLibName; + } + + @Override + public long getStaticSharedLibVersion() { + return staticSharedLibVersion; + } + + @NonNull + @Override + public List<String> getLibraryNames() { + return libraryNames; + } + + @NonNull + @Override + public List<String> getUsesLibraries() { + return usesLibraries; + } + + @NonNull + @Override + public List<String> getUsesOptionalLibraries() { + return usesOptionalLibraries; + } + + @NonNull + @Override + public List<String> getUsesStaticLibraries() { + return usesStaticLibraries; + } + + @Nullable + @Override + public long[] getUsesStaticLibrariesVersions() { + return usesStaticLibrariesVersions; + } + + @Nullable + @Override + public String[][] getUsesStaticLibrariesCertDigests() { + return usesStaticLibrariesCertDigests; + } + + @Nullable + @Override + public String getSharedUserId() { + return sharedUserId; + } + + @Override + public int getSharedUserLabel() { + return sharedUserLabel; + } + + @NonNull + @Override + public List<ConfigurationInfo> getConfigPreferences() { + return configPreferences; + } + + @NonNull + @Override + public List<FeatureInfo> getReqFeatures() { + return reqFeatures; + } + + @NonNull + @Override + public List<FeatureGroupInfo> getFeatureGroups() { + return featureGroups; + } + + @Nullable + @Override + public byte[] getRestrictUpdateHash() { + return restrictUpdateHash; + } + + @NonNull + @Override + public List<String> getOriginalPackages() { + return originalPackages; + } + + @NonNull + @Override + public List<String> getAdoptPermissions() { + return adoptPermissions; + } + + @NonNull + @Override + public List<String> getRequestedPermissions() { + return requestedPermissions; + } + + @NonNull + @Override + public List<String> getImplicitPermissions() { + return implicitPermissions; + } + + @NonNull + @Override + public Set<String> getUpgradeKeySets() { + return upgradeKeySets; + } + + @NonNull + @Override + public Map<String,ArraySet<PublicKey>> getKeySetMapping() { + return keySetMapping; + } + + @NonNull + @Override + public List<String> getProtectedBroadcasts() { + return protectedBroadcasts; + } + + @NonNull + @Override + public List<ParsedActivity> getActivities() { + return activities; + } + + @NonNull + @Override + public List<ParsedActivity> getReceivers() { + return receivers; + } + + @NonNull + @Override + public List<ParsedService> getServices() { + return services; + } + + @NonNull + @Override + public List<ParsedProvider> getProviders() { + return providers; + } + + @NonNull + @Override + public List<ParsedFeature> getFeatures() { + return features; + } + + @NonNull + @Override + public List<ParsedPermission> getPermissions() { + return permissions; + } + + @NonNull + @Override + public List<ParsedPermissionGroup> getPermissionGroups() { + return permissionGroups; + } + + @NonNull + @Override + public List<ParsedInstrumentation> getInstrumentations() { + return instrumentations; + } + + @NonNull + @Override + public List<Pair<String,ParsedIntentInfo>> getPreferredActivityFilters() { + return preferredActivityFilters; + } + + @NonNull + @Override + public Map<String,ParsedProcess> getProcesses() { + return processes; + } + + @Nullable + @Override + public Bundle getMetaData() { + return metaData; + } + + private void addMimeGroupsFromComponent(ParsedComponent component) { + for (int i = component.getIntents().size() - 1; i >= 0; i--) { + IntentFilter filter = component.getIntents().get(i); + for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) { + mimeGroups = ArrayUtils.add(mimeGroups, filter.getMimeGroup(groupIndex)); + } + } + } + + @Override + @Nullable + public Set<String> getMimeGroups() { + return mimeGroups; + } + + @Nullable + @Override + public String getVolumeUuid() { + return volumeUuid; + } + + @Nullable + @Override + public PackageParser.SigningDetails getSigningDetails() { + return signingDetails; + } + + @NonNull + @Override + public String getCodePath() { + return codePath; + } + + @Override + public boolean isUse32BitAbi() { + return use32BitAbi; + } + + @Override + public boolean isVisibleToInstantApps() { + return visibleToInstantApps; + } + + @Override + public boolean isForceQueryable() { + return forceQueryable; + } + + @NonNull + @Override + public List<Intent> getQueriesIntents() { + return queriesIntents; + } + + @NonNull + @Override + public List<String> getQueriesPackages() { + return queriesPackages; + } + + @NonNull + @Override + public Set<String> getQueriesProviders() { + return queriesProviders; + } + + @Nullable + @Override + public String[] getSplitClassLoaderNames() { + return splitClassLoaderNames; + } + + @Nullable + @Override + public String[] getSplitCodePaths() { + return splitCodePaths; + } + + @Nullable + @Override + public SparseArray<int[]> getSplitDependencies() { + return splitDependencies; + } + + @Nullable + @Override + public int[] getSplitFlags() { + return splitFlags; + } + + @Nullable + @Override + public String[] getSplitNames() { + return splitNames; + } + + @Nullable + @Override + public int[] getSplitRevisionCodes() { + return splitRevisionCodes; + } + + @Nullable + @Override + public String getAppComponentFactory() { + return appComponentFactory; + } + + @Nullable + @Override + public String getBackupAgentName() { + return backupAgentName; + } + + @Override + public int getBanner() { + return banner; + } + + @Override + public int getCategory() { + return category; + } + + @Nullable + @Override + public String getClassLoaderName() { + return classLoaderName; + } + + @Nullable + @Override + public String getClassName() { + return className; + } + + @Override + public int getCompatibleWidthLimitDp() { + return compatibleWidthLimitDp; + } + + @Override + public int getDescriptionRes() { + return descriptionRes; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public boolean isCrossProfile() { + return crossProfile; + } + + @Override + public int getFullBackupContent() { + return fullBackupContent; + } + + @Override + public int getIconRes() { + return iconRes; + } + + @Override + public int getInstallLocation() { + return installLocation; + } + + @Override + public int getLabelRes() { + return labelRes; + } + + @Override + public int getLargestWidthLimitDp() { + return largestWidthLimitDp; + } + + @Override + public int getLogo() { + return logo; + } + + @Nullable + @Override + public String getManageSpaceActivityName() { + return manageSpaceActivityName; + } + + @Override + public float getMaxAspectRatio() { + return maxAspectRatio; + } + + @Override + public float getMinAspectRatio() { + return minAspectRatio; + } + + @Override + public int getMinSdkVersion() { + return minSdkVersion; + } + + @Override + public int getNetworkSecurityConfigRes() { + return networkSecurityConfigRes; + } + + @Nullable + @Override + public CharSequence getNonLocalizedLabel() { + return nonLocalizedLabel; + } + + @Nullable + @Override + public String getPermission() { + return permission; + } + + @Override + public int getRequiresSmallestWidthDp() { + return requiresSmallestWidthDp; + } + + @Override + public int getRoundIconRes() { + return roundIconRes; + } + + @Override + public int getTargetSandboxVersion() { + return targetSandboxVersion; + } + + @Override + public int getTargetSdkVersion() { + return targetSdkVersion; + } + + @Nullable + @Override + public String getTaskAffinity() { + return taskAffinity; + } + + @Override + public int getTheme() { + return theme; + } + + @Override + public int getUiOptions() { + return uiOptions; + } + + @Nullable + @Override + public String getZygotePreloadName() { + return zygotePreloadName; + } + + @Override + public boolean isExternalStorage() { + return externalStorage; + } + + @Override + public boolean isBaseHardwareAccelerated() { + return baseHardwareAccelerated; + } + + @Override + public boolean isAllowBackup() { + return allowBackup; + } + + @Override + public boolean isKillAfterRestore() { + return killAfterRestore; + } + + @Override + public boolean isRestoreAnyVersion() { + return restoreAnyVersion; + } + + @Override + public boolean isFullBackupOnly() { + return fullBackupOnly; + } + + @Override + public boolean isPersistent() { + return persistent; + } + + @Override + public boolean isDebuggable() { + return debuggable; + } + + @Override + public boolean isVmSafeMode() { + return vmSafeMode; + } + + @Override + public boolean isHasCode() { + return hasCode; + } + + @Override + public boolean isAllowTaskReparenting() { + return allowTaskReparenting; + } + + @Override + public boolean isAllowClearUserData() { + return allowClearUserData; + } + + @Override + public boolean isLargeHeap() { + return largeHeap; + } + + @Override + public boolean isUsesCleartextTraffic() { + return usesCleartextTraffic; + } + + @Override + public boolean isSupportsRtl() { + return supportsRtl; + } + + @Override + public boolean isTestOnly() { + return testOnly; + } + + @Override + public boolean isMultiArch() { + return multiArch; + } + + @Override + public boolean isExtractNativeLibs() { + return extractNativeLibs; + } + + @Override + public boolean isGame() { + return game; + } + + /** + * @see ParsingPackageRead#getResizeableActivity() + */ + @Nullable + @Override + public Boolean getResizeableActivity() { + return resizeableActivity; + } + + @Override + public boolean isStaticSharedLibrary() { + return staticSharedLibrary; + } + + @Override + public boolean isOverlay() { + return overlay; + } + + @Override + public boolean isIsolatedSplitLoading() { + return isolatedSplitLoading; + } + + @Override + public boolean isHasDomainUrls() { + return hasDomainUrls; + } + + @Override + public boolean isProfileableByShell() { + return profileableByShell; + } + + @Override + public boolean isBackupInForeground() { + return backupInForeground; + } + + @Override + public boolean isUseEmbeddedDex() { + return useEmbeddedDex; + } + + @Override + public boolean isDefaultToDeviceProtectedStorage() { + return defaultToDeviceProtectedStorage; + } + + @Override + public boolean isDirectBootAware() { + return directBootAware; + } + + @Override + public boolean isPartiallyDirectBootAware() { + return partiallyDirectBootAware; + } + + @Override + public boolean isResizeableActivityViaSdkVersion() { + return resizeableActivityViaSdkVersion; + } + + @Override + public boolean isAllowClearUserDataOnFailedRestore() { + return allowClearUserDataOnFailedRestore; + } + + @Override + public boolean isAllowAudioPlaybackCapture() { + return allowAudioPlaybackCapture; + } + + @Override + public boolean isRequestLegacyExternalStorage() { + return requestLegacyExternalStorage; + } + + @Override + public boolean isUsesNonSdkApi() { + return usesNonSdkApi; + } + + @Override + public boolean isHasFragileUserData() { + return hasFragileUserData; + } + + @Override + public boolean isCantSaveState() { + return cantSaveState; + } + + @Override + public boolean isAllowNativeHeapPointerTagging() { + return allowNativeHeapPointerTagging; + } + + @Override + public boolean hasPreserveLegacyExternalStorage() { + return preserveLegacyExternalStorage; + } + + @Override + public ParsingPackageImpl setBaseRevisionCode(int value) { + baseRevisionCode = value; + return this; + } + + @Override + public ParsingPackageImpl setCompileSdkVersion(int value) { + compileSdkVersion = value; + return this; + } + + @Override + public ParsingPackageImpl setRequiredForAllUsers(boolean value) { + requiredForAllUsers = value; + return this; + } + + @Override + public ParsingPackageImpl setOverlayPriority(int value) { + overlayPriority = value; + return this; + } + + @Override + public ParsingPackageImpl setOverlayIsStatic(boolean value) { + overlayIsStatic = value; + return this; + } + + @Override + public ParsingPackageImpl setStaticSharedLibVersion(long value) { + staticSharedLibVersion = value; + return this; + } + + @Override + public ParsingPackageImpl setSharedUserLabel(int value) { + sharedUserLabel = value; + return this; + } + + @Override + public ParsingPackageImpl setRestrictUpdateHash(@Nullable byte... value) { + restrictUpdateHash = value; + return this; + } + + @Override + public ParsingPackageImpl setUpgradeKeySets(@NonNull Set<String> value) { + upgradeKeySets = value; + return this; + } + + @Override + public ParsingPackageImpl setProcesses(@NonNull Map<String,ParsedProcess> value) { + processes = value; + return this; + } + + @Override + public ParsingPackageImpl setMetaData(@Nullable Bundle value) { + metaData = value; + return this; + } + + @Override + public ParsingPackageImpl setSigningDetails(@Nullable PackageParser.SigningDetails value) { + signingDetails = value; + return this; + } + + @Override + public ParsingPackageImpl setUse32BitAbi(boolean value) { + use32BitAbi = value; + return this; + } + + @Override + public ParsingPackageImpl setVisibleToInstantApps(boolean value) { + visibleToInstantApps = value; + return this; + } + + @Override + public ParsingPackageImpl setForceQueryable(boolean value) { + forceQueryable = value; + return this; + } + + @Override + public ParsingPackageImpl setBanner(int value) { + banner = value; + return this; + } + + @Override + public ParsingPackageImpl setCategory(int value) { + category = value; + return this; + } + + @Override + public ParsingPackageImpl setCompatibleWidthLimitDp(int value) { + compatibleWidthLimitDp = value; + return this; + } + + @Override + public ParsingPackageImpl setDescriptionRes(int value) { + descriptionRes = value; + return this; + } + + @Override + public ParsingPackageImpl setEnabled(boolean value) { + enabled = value; + return this; + } + + @Override + public ParsingPackageImpl setCrossProfile(boolean value) { + crossProfile = value; + return this; + } + + @Override + public ParsingPackageImpl setFullBackupContent(int value) { + fullBackupContent = value; + return this; + } + + @Override + public ParsingPackageImpl setIconRes(int value) { + iconRes = value; + return this; + } + + @Override + public ParsingPackageImpl setInstallLocation(int value) { + installLocation = value; + return this; + } + + @Override + public ParsingPackageImpl setLabelRes(int value) { + labelRes = value; + return this; + } + + @Override + public ParsingPackageImpl setLargestWidthLimitDp(int value) { + largestWidthLimitDp = value; + return this; + } + + @Override + public ParsingPackageImpl setLogo(int value) { + logo = value; + return this; + } + + @Override + public ParsingPackageImpl setMaxAspectRatio(float value) { + maxAspectRatio = value; + return this; + } + + @Override + public ParsingPackageImpl setMinAspectRatio(float value) { + minAspectRatio = value; + return this; + } + + @Override + public ParsingPackageImpl setMinSdkVersion(int value) { + minSdkVersion = value; + return this; + } + + @Override + public ParsingPackageImpl setNetworkSecurityConfigRes(int value) { + networkSecurityConfigRes = value; + return this; + } + + @Override + public ParsingPackageImpl setNonLocalizedLabel(@Nullable CharSequence value) { + nonLocalizedLabel = value; + return this; + } + + @Override + public ParsingPackageImpl setRequiresSmallestWidthDp(int value) { + requiresSmallestWidthDp = value; + return this; + } + + @Override + public ParsingPackageImpl setRoundIconRes(int value) { + roundIconRes = value; + return this; + } + + @Override + public ParsingPackageImpl setTargetSandboxVersion(int value) { + targetSandboxVersion = value; + return this; + } + + @Override + public ParsingPackageImpl setTargetSdkVersion(int value) { + targetSdkVersion = value; + return this; + } + + @Override + public ParsingPackageImpl setTheme(int value) { + theme = value; + return this; + } + + @Override + public ParsingPackageImpl setUiOptions(int value) { + uiOptions = value; + return this; + } + + @Override + public ParsingPackageImpl setExternalStorage(boolean value) { + externalStorage = value; + return this; + } + + @Override + public ParsingPackageImpl setBaseHardwareAccelerated(boolean value) { + baseHardwareAccelerated = value; + return this; + } + + @Override + public ParsingPackageImpl setAllowBackup(boolean value) { + allowBackup = value; + return this; + } + + @Override + public ParsingPackageImpl setKillAfterRestore(boolean value) { + killAfterRestore = value; + return this; + } + + @Override + public ParsingPackageImpl setRestoreAnyVersion(boolean value) { + restoreAnyVersion = value; + return this; + } + + @Override + public ParsingPackageImpl setFullBackupOnly(boolean value) { + fullBackupOnly = value; + return this; + } + + @Override + public ParsingPackageImpl setPersistent(boolean value) { + persistent = value; + return this; + } + + @Override + public ParsingPackageImpl setDebuggable(boolean value) { + debuggable = value; + return this; + } + + @Override + public ParsingPackageImpl setVmSafeMode(boolean value) { + vmSafeMode = value; + return this; + } + + @Override + public ParsingPackageImpl setHasCode(boolean value) { + hasCode = value; + return this; + } + + @Override + public ParsingPackageImpl setAllowTaskReparenting(boolean value) { + allowTaskReparenting = value; + return this; + } + + @Override + public ParsingPackageImpl setAllowClearUserData(boolean value) { + allowClearUserData = value; + return this; + } + + @Override + public ParsingPackageImpl setLargeHeap(boolean value) { + largeHeap = value; + return this; + } + + @Override + public ParsingPackageImpl setUsesCleartextTraffic(boolean value) { + usesCleartextTraffic = value; + return this; + } + + @Override + public ParsingPackageImpl setSupportsRtl(boolean value) { + supportsRtl = value; + return this; + } + + @Override + public ParsingPackageImpl setTestOnly(boolean value) { + testOnly = value; + return this; + } + + @Override + public ParsingPackageImpl setMultiArch(boolean value) { + multiArch = value; + return this; + } + + @Override + public ParsingPackageImpl setExtractNativeLibs(boolean value) { + extractNativeLibs = value; + return this; + } + + @Override + public ParsingPackageImpl setGame(boolean value) { + game = value; + return this; + } + + /** + * @see ParsingPackageRead#getResizeableActivity() + */ + @Override + public ParsingPackageImpl setResizeableActivity(@Nullable Boolean value) { + resizeableActivity = value; + return this; + } + + @Override + public ParsingPackageImpl setStaticSharedLibrary(boolean value) { + staticSharedLibrary = value; + return this; + } + + @Override + public ParsingPackageImpl setOverlay(boolean value) { + overlay = value; + return this; + } + + @Override + public ParsingPackageImpl setIsolatedSplitLoading(boolean value) { + isolatedSplitLoading = value; + return this; + } + + @Override + public ParsingPackageImpl setHasDomainUrls(boolean value) { + hasDomainUrls = value; + return this; + } + + @Override + public ParsingPackageImpl setProfileableByShell(boolean value) { + profileableByShell = value; + return this; + } + + @Override + public ParsingPackageImpl setBackupInForeground(boolean value) { + backupInForeground = value; + return this; + } + + @Override + public ParsingPackageImpl setUseEmbeddedDex(boolean value) { + useEmbeddedDex = value; + return this; + } + + @Override + public ParsingPackageImpl setDefaultToDeviceProtectedStorage(boolean value) { + defaultToDeviceProtectedStorage = value; + return this; + } + + @Override + public ParsingPackageImpl setDirectBootAware(boolean value) { + directBootAware = value; + return this; + } + + @Override + public ParsingPackageImpl setPartiallyDirectBootAware(boolean value) { + partiallyDirectBootAware = value; + return this; + } + + @Override + public ParsingPackageImpl setResizeableActivityViaSdkVersion(boolean value) { + resizeableActivityViaSdkVersion = value; + return this; + } + + @Override + public ParsingPackageImpl setAllowClearUserDataOnFailedRestore(boolean value) { + allowClearUserDataOnFailedRestore = value; + return this; + } + + @Override + public ParsingPackageImpl setAllowAudioPlaybackCapture(boolean value) { + allowAudioPlaybackCapture = value; + return this; + } + + @Override + public ParsingPackageImpl setRequestLegacyExternalStorage(boolean value) { + requestLegacyExternalStorage = value; + return this; + } + + @Override + public ParsingPackageImpl setUsesNonSdkApi(boolean value) { + usesNonSdkApi = value; + return this; + } + + @Override + public ParsingPackageImpl setHasFragileUserData(boolean value) { + hasFragileUserData = value; + return this; + } + + @Override + public ParsingPackageImpl setCantSaveState(boolean value) { + cantSaveState = value; + return this; + } + + @Override + public ParsingPackageImpl setAllowNativeHeapPointerTagging(boolean value) { + allowNativeHeapPointerTagging = value; + return this; + } + + @Override + public ParsingPackageImpl setPreserveLegacyExternalStorage(boolean value) { + preserveLegacyExternalStorage = value; + return this; + } +} diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java new file mode 100644 index 000000000000..048b924e10cc --- /dev/null +++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java @@ -0,0 +1,845 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageParser; +import android.content.pm.ServiceInfo; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedFeature; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.content.pm.parsing.component.ParsedProcess; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.ArraySet; +import android.util.Pair; +import android.util.SparseArray; + +import com.android.internal.R; + +import java.security.PublicKey; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Everything written by {@link ParsingPackage} and readable back. + * + * @hide + */ +@SuppressWarnings("UnusedReturnValue") +public interface ParsingPackageRead extends Parcelable { + + /** + * @see ActivityInfo + * @see PackageInfo#activities + */ + @NonNull + List<ParsedActivity> getActivities(); + + /** + * The names of packages to adopt ownership of permissions from, parsed under + * {@link PackageParser#TAG_ADOPT_PERMISSIONS}. + * @see R.styleable#AndroidManifestOriginalPackage_name + */ + @NonNull + List<String> getAdoptPermissions(); + + /** + * @see PackageInfo#configPreferences + * @see R.styleable#AndroidManifestUsesConfiguration + */ + @NonNull + List<ConfigurationInfo> getConfigPreferences(); + + @NonNull + List<ParsedFeature> getFeatures(); + + /** + * @see PackageInfo#featureGroups + * @see R.styleable#AndroidManifestUsesFeature + */ + @NonNull + List<FeatureGroupInfo> getFeatureGroups(); + + /** + * Permissions requested but not in the manifest. These may have been split or migrated from + * previous versions/definitions. + */ + @NonNull + List<String> getImplicitPermissions(); + + /** + * @see android.content.pm.InstrumentationInfo + * @see PackageInfo#instrumentation + */ + @NonNull + List<ParsedInstrumentation> getInstrumentations(); + + /** + * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in + * {@link PackageParser#TAG_KEY_SETS}. + * @see R.styleable#AndroidManifestKeySet + * @see R.styleable#AndroidManifestPublicKey + */ + @NonNull + Map<String, ArraySet<PublicKey>> getKeySetMapping(); + + /** + * Library names this package is declared as, for use by other packages with "uses-library". + * @see R.styleable#AndroidManifestLibrary + */ + @NonNull + List<String> getLibraryNames(); + + /** + * For system use to migrate from an old package name to a new one, moving over data + * if available. + * @see R.styleable#AndroidManifestOriginalPackage} + */ + @NonNull + List<String> getOriginalPackages(); + + /** + * Map of overlayable name to actor name. + */ + @NonNull + Map<String, String> getOverlayables(); + + /** + * @see android.content.pm.PermissionInfo + * @see PackageInfo#permissions + */ + @NonNull + List<ParsedPermission> getPermissions(); + + /** + * @see android.content.pm.PermissionGroupInfo + */ + @NonNull + List<ParsedPermissionGroup> getPermissionGroups(); + + /** + * Used to determine the default preferred handler of an {@link Intent}. + * + * Map of component className to intent info inside that component. + * TODO(b/135203078): Is this actually used/working? + */ + @NonNull + List<Pair<String, ParsedIntentInfo>> getPreferredActivityFilters(); + + /** + * System protected broadcasts. + * @see R.styleable#AndroidManifestProtectedBroadcast + */ + @NonNull + List<String> getProtectedBroadcasts(); + + /** + * @see android.content.pm.ProviderInfo + * @see PackageInfo#providers + */ + @NonNull + List<ParsedProvider> getProviders(); + + /** + * @see android.content.pm.ProcessInfo + */ + @NonNull + Map<String, ParsedProcess> getProcesses(); + + /** + * Since they share several attributes, receivers are parsed as {@link ParsedActivity}, even + * though they represent different functionality. + * TODO(b/135203078): Reconsider this and maybe make ParsedReceiver so it's not so confusing + * @see ActivityInfo + * @see PackageInfo#receivers + */ + @NonNull + List<ParsedActivity> getReceivers(); + + /** + * @see PackageInfo#reqFeatures + * @see R.styleable#AndroidManifestUsesFeature + */ + @NonNull + List<FeatureInfo> getReqFeatures(); + + /** + * All the permissions declared. This is an effective set, and may include permissions + * transformed from split/migrated permissions from previous versions, so may not be exactly + * what the package declares in its manifest. + * @see PackageInfo#requestedPermissions + * @see R.styleable#AndroidManifestUsesPermission + */ + @NonNull + List<String> getRequestedPermissions(); + + /** + * Whether or not the app requested explicitly resizeable Activities. + * A null value means nothing was explicitly requested. + */ + @Nullable + Boolean getResizeableActivity(); + + /** + * @see ServiceInfo + * @see PackageInfo#services + */ + @NonNull + List<ParsedService> getServices(); + + /** @see R.styleable#AndroidManifestUsesLibrary */ + @NonNull + List<String> getUsesLibraries(); + + /** + * Like {@link #getUsesLibraries()}, but marked optional by setting + * {@link R.styleable#AndroidManifestUsesLibrary_required} to false . Application is expected + * to handle absence manually. + * @see R.styleable#AndroidManifestUsesLibrary + */ + @NonNull + List<String> getUsesOptionalLibraries(); + + /** + * TODO(b/135203078): Move static library stuff to an inner data class + * @see R.styleable#AndroidManifestUsesStaticLibrary + */ + @NonNull + List<String> getUsesStaticLibraries(); + + /** @see R.styleable#AndroidManifestUsesStaticLibrary_certDigest */ + @Nullable + String[][] getUsesStaticLibrariesCertDigests(); + + /** @see R.styleable#AndroidManifestUsesStaticLibrary_version */ + @Nullable + long[] getUsesStaticLibrariesVersions(); + + /** + * Intents that this package may query or require and thus requires visibility into. + * @see R.styleable#AndroidManifestQueriesIntent + */ + @NonNull + List<Intent> getQueriesIntents(); + + /** + * Other packages that this package may query or require and thus requires visibility into. + * @see R.styleable#AndroidManifestQueriesPackage + */ + @NonNull + List<String> getQueriesPackages(); + + /** + * Authorities that this package may query or require and thus requires visibility into. + * @see R.styleable#AndroidManifestQueriesProvider + */ + @NonNull + Set<String> getQueriesProviders(); + + /** + * We store the application meta-data independently to avoid multiple unwanted references + * TODO(b/135203078): What does this comment mean? + * TODO(b/135203078): Make all the Bundles immutable (and non-null by shared empty reference?) + */ + @Nullable + Bundle getMetaData(); + + /** @see R.styleable#AndroidManifestApplication_forceQueryable */ + boolean isForceQueryable(); + + /** + * @see ApplicationInfo#maxAspectRatio + * @see R.styleable#AndroidManifestApplication_maxAspectRatio + */ + float getMaxAspectRatio(); + + /** + * @see ApplicationInfo#minAspectRatio + * @see R.styleable#AndroidManifestApplication_minAspectRatio + */ + float getMinAspectRatio(); + + /** + * @see ApplicationInfo#permission + * @see R.styleable#AndroidManifestApplication_permission + */ + @Nullable + String getPermission(); + + /** + * @see ApplicationInfo#processName + * @see R.styleable#AndroidManifestApplication_process + */ + @NonNull + String getProcessName(); + + /** + * @see PackageInfo#sharedUserId + * @see R.styleable#AndroidManifest_sharedUserId + */ + @Deprecated + @Nullable + String getSharedUserId(); + + /** @see R.styleable#AndroidManifestStaticLibrary_name */ + @Nullable + String getStaticSharedLibName(); + + /** + * @see ApplicationInfo#taskAffinity + * @see R.styleable#AndroidManifestApplication_taskAffinity + */ + @Nullable + String getTaskAffinity(); + + /** + * @see ApplicationInfo#targetSdkVersion + * @see R.styleable#AndroidManifestUsesSdk_targetSdkVersion + */ + int getTargetSdkVersion(); + + /** + * @see ApplicationInfo#uiOptions + * @see R.styleable#AndroidManifestApplication_uiOptions + */ + int getUiOptions(); + + boolean isCrossProfile(); + + boolean isResizeableActivityViaSdkVersion(); + + /** @see ApplicationInfo#FLAG_HARDWARE_ACCELERATED */ + boolean isBaseHardwareAccelerated(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#DONUT}. + * @see R.styleable#AndroidManifestSupportsScreens_resizeable + * @see ApplicationInfo#FLAG_RESIZEABLE_FOR_SCREENS + */ + boolean isResizeable(); + + /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE */ + boolean isAllowAudioPlaybackCapture(); + + /** @see ApplicationInfo#FLAG_ALLOW_BACKUP */ + boolean isAllowBackup(); + + /** @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA */ + boolean isAllowClearUserData(); + + /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE */ + boolean isAllowClearUserDataOnFailedRestore(); + + /** @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING */ + boolean isAllowTaskReparenting(); + + /** + * @see ApplicationInfo#PRIVATE_FLAG_IS_RESOURCE_OVERLAY + * @see ApplicationInfo#isResourceOverlay() + */ + boolean isOverlay(); + + /** @see ApplicationInfo#PRIVATE_FLAG_BACKUP_IN_FOREGROUND */ + boolean isBackupInForeground(); + + /** @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE */ + boolean isCantSaveState(); + + /** @see ApplicationInfo#FLAG_DEBUGGABLE */ + boolean isDebuggable(); + + /** @see ApplicationInfo#PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE */ + boolean isDefaultToDeviceProtectedStorage(); + + /** @see ApplicationInfo#PRIVATE_FLAG_DIRECT_BOOT_AWARE */ + boolean isDirectBootAware(); + + /** @see ApplicationInfo#FLAG_EXTERNAL_STORAGE */ + boolean isExternalStorage(); + + /** @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS */ + boolean isExtractNativeLibs(); + + /** @see ApplicationInfo#FLAG_FULL_BACKUP_ONLY */ + boolean isFullBackupOnly(); + + /** @see ApplicationInfo#FLAG_HAS_CODE */ + boolean isHasCode(); + + /** @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA */ + boolean isHasFragileUserData(); + + /** @see ApplicationInfo#FLAG_IS_GAME */ + @Deprecated + boolean isGame(); + + /** @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING */ + boolean isIsolatedSplitLoading(); + + /** @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE */ + boolean isKillAfterRestore(); + + /** @see ApplicationInfo#FLAG_LARGE_HEAP */ + boolean isLargeHeap(); + + /** @see ApplicationInfo#FLAG_MULTIARCH */ + boolean isMultiArch(); + + /** @see ApplicationInfo#PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE */ + boolean isPartiallyDirectBootAware(); + + /** @see ApplicationInfo#FLAG_PERSISTENT */ + boolean isPersistent(); + + /** @see ApplicationInfo#PRIVATE_FLAG_PROFILEABLE_BY_SHELL */ + boolean isProfileableByShell(); + + /** @see ApplicationInfo#PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE */ + boolean isRequestLegacyExternalStorage(); + + /** @see ApplicationInfo#FLAG_RESTORE_ANY_VERSION */ + boolean isRestoreAnyVersion(); + + // ParsingPackageRead setSplitHasCode(int splitIndex, boolean splitHasCode); + + /** Flags of any split APKs; ordered by parsed splitName */ + @Nullable + int[] getSplitFlags(); + + /** @see ApplicationInfo#splitSourceDirs */ + @Nullable + String[] getSplitCodePaths(); + + /** @see ApplicationInfo#splitDependencies */ + @Nullable + SparseArray<int[]> getSplitDependencies(); + + /** + * @see ApplicationInfo#splitNames + * @see PackageInfo#splitNames + */ + @Nullable + String[] getSplitNames(); + + /** @see PackageInfo#splitRevisionCodes */ + int[] getSplitRevisionCodes(); + + /** @see ApplicationInfo#PRIVATE_FLAG_STATIC_SHARED_LIBRARY */ + boolean isStaticSharedLibrary(); + + /** @see ApplicationInfo#FLAG_SUPPORTS_RTL */ + boolean isSupportsRtl(); + + /** @see ApplicationInfo#FLAG_TEST_ONLY */ + boolean isTestOnly(); + + /** @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX */ + boolean isUseEmbeddedDex(); + + /** @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC */ + boolean isUsesCleartextTraffic(); + + /** @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API */ + boolean isUsesNonSdkApi(); + + /** + * Set if the any of components are visible to instant applications. + * @see R.styleable#AndroidManifestActivity_visibleToInstantApps + * @see R.styleable#AndroidManifestProvider_visibleToInstantApps + * @see R.styleable#AndroidManifestService_visibleToInstantApps + */ + boolean isVisibleToInstantApps(); + + /** @see ApplicationInfo#FLAG_VM_SAFE_MODE */ + boolean isVmSafeMode(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#DONUT}. + * @see R.styleable#AndroidManifestSupportsScreens_anyDensity + * @see ApplicationInfo#FLAG_SUPPORTS_SCREEN_DENSITIES + */ + boolean isAnyDensity(); + + /** + * @see ApplicationInfo#appComponentFactory + * @see R.styleable#AndroidManifestApplication_appComponentFactory + */ + @Nullable + String getAppComponentFactory(); + + /** + * @see ApplicationInfo#backupAgentName + * @see R.styleable#AndroidManifestApplication_backupAgent + */ + @Nullable + String getBackupAgentName(); + + /** + * @see ApplicationInfo#banner + * @see R.styleable#AndroidManifestApplication_banner + */ + int getBanner(); + + /** + * @see ApplicationInfo#category + * @see R.styleable#AndroidManifestApplication_appCategory + */ + int getCategory(); + + /** + * @see ApplicationInfo#classLoaderName + * @see R.styleable#AndroidManifestApplication_classLoader + */ + @Nullable + String getClassLoaderName(); + + /** + * @see ApplicationInfo#className + * @see R.styleable#AndroidManifestApplication_name + */ + @Nullable + String getClassName(); + + String getPackageName(); + + /** Path of base APK */ + String getBaseCodePath(); + + /** + * Path where this package was found on disk. For monolithic packages + * this is path to single base APK file; for cluster packages this is + * path to the cluster directory. + */ + @NonNull + String getCodePath(); + + /** + * @see ApplicationInfo#compatibleWidthLimitDp + * @see R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp + */ + int getCompatibleWidthLimitDp(); + + /** + * @see ApplicationInfo#descriptionRes + * @see R.styleable#AndroidManifestApplication_description + */ + int getDescriptionRes(); + + /** + * @see ApplicationInfo#enabled + * @see R.styleable#AndroidManifestApplication_enabled + */ + boolean isEnabled(); + + /** + * @see ApplicationInfo#fullBackupContent + * @see R.styleable#AndroidManifestApplication_fullBackupContent + */ + int getFullBackupContent(); + + /** @see ApplicationInfo#PRIVATE_FLAG_HAS_DOMAIN_URLS */ + boolean isHasDomainUrls(); + + /** + * @see ApplicationInfo#iconRes + * @see R.styleable#AndroidManifestApplication_icon + */ + int getIconRes(); + + /** + * @see ApplicationInfo#installLocation + * @see R.styleable#AndroidManifest_installLocation + */ + int getInstallLocation(); + + /** + * @see ApplicationInfo#labelRes + * @see R.styleable#AndroidManifestApplication_label + */ + int getLabelRes(); + + /** + * @see ApplicationInfo#largestWidthLimitDp + * @see R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp + */ + int getLargestWidthLimitDp(); + + /** + * @see ApplicationInfo#logo + * @see R.styleable#AndroidManifestApplication_logo + */ + int getLogo(); + + /** + * @see ApplicationInfo#manageSpaceActivityName + * @see R.styleable#AndroidManifestApplication_manageSpaceActivity + */ + @Nullable + String getManageSpaceActivityName(); + + /** + * @see ApplicationInfo#minSdkVersion + * @see R.styleable#AndroidManifestUsesSdk_minSdkVersion + */ + int getMinSdkVersion(); + + /** + * @see ApplicationInfo#networkSecurityConfigRes + * @see R.styleable#AndroidManifestApplication_networkSecurityConfig + */ + int getNetworkSecurityConfigRes(); + + /** + * If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it. + * Otherwise, it's stored as {@link #getLabelRes()}. + * @see ApplicationInfo#nonLocalizedLabel + * @see R.styleable#AndroidManifestApplication_label + */ + @Nullable + CharSequence getNonLocalizedLabel(); + + /** + * @see PackageInfo#overlayCategory + * @see R.styleable#AndroidManifestResourceOverlay_category + */ + @Nullable + String getOverlayCategory(); + + /** @see PackageInfo#mOverlayIsStatic */ + boolean isOverlayIsStatic(); + + /** + * @see PackageInfo#overlayPriority + * @see R.styleable#AndroidManifestResourceOverlay_priority + */ + int getOverlayPriority(); + + /** + * @see PackageInfo#overlayTarget + * @see R.styleable#AndroidManifestResourceOverlay_targetPackage + */ + @Nullable + String getOverlayTarget(); + + /** + * @see PackageInfo#targetOverlayableName + * @see R.styleable#AndroidManifestResourceOverlay_targetName + */ + @Nullable + String getOverlayTargetName(); + + /** + * If a system app declares {@link #getOriginalPackages()}, and the app was previously installed + * under one of those original package names, the {@link #getPackageName()} system identifier + * will be changed to that previously installed name. This will then be non-null, set to the + * manifest package name, for tracking the package under its true name. + * + * TODO(b/135203078): Remove this in favor of checking originalPackages.isEmpty and + * getManifestPackageName + */ + @Nullable + String getRealPackage(); + + /** + * The required account type without which this application will not function. + * + * @see PackageInfo#requiredAccountType + * @see R.styleable#AndroidManifestApplication_requiredAccountType + */ + @Nullable + String getRequiredAccountType(); + + /** + * @see PackageInfo#requiredForAllUsers + * @see R.styleable#AndroidManifestApplication_requiredForAllUsers + */ + boolean isRequiredForAllUsers(); + + /** + * @see ApplicationInfo#requiresSmallestWidthDp + * @see R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp + */ + int getRequiresSmallestWidthDp(); + + /** + * SHA-512 hash of the only APK that can be used to update a system package. + * @see R.styleable#AndroidManifestRestrictUpdate + */ + @Nullable + byte[] getRestrictUpdateHash(); + + /** + * The restricted account authenticator type that is used by this application + * + * @see PackageInfo#restrictedAccountType + * @see R.styleable#AndroidManifestApplication_restrictedAccountType + */ + @Nullable + String getRestrictedAccountType(); + + /** + * @see ApplicationInfo#roundIconRes + * @see R.styleable#AndroidManifestApplication_roundIcon + */ + int getRoundIconRes(); + + /** + * @see PackageInfo#sharedUserLabel + * @see R.styleable#AndroidManifest_sharedUserLabel + */ + @Deprecated + int getSharedUserLabel(); + + /** + * The signature data of all APKs in this package, which must be exactly the same across the + * base and splits. + */ + PackageParser.SigningDetails getSigningDetails(); + + /** + * @see ApplicationInfo#splitClassLoaderNames + * @see R.styleable#AndroidManifestApplication_classLoader + */ + @Nullable + String[] getSplitClassLoaderNames(); + + /** @see R.styleable#AndroidManifestStaticLibrary_version */ + long getStaticSharedLibVersion(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#DONUT}. + * @see R.styleable#AndroidManifestSupportsScreens_largeScreens + * @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS + */ + boolean isSupportsLargeScreens(); + + /** + * If omitted from manifest, returns true. + * @see R.styleable#AndroidManifestSupportsScreens_normalScreens + * @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS + */ + boolean isSupportsNormalScreens(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#DONUT}. + * @see R.styleable#AndroidManifestSupportsScreens_smallScreens + * @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS + */ + boolean isSupportsSmallScreens(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#GINGERBREAD}. + * @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens + * @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS + */ + boolean isSupportsExtraLargeScreens(); + + /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING */ + boolean isAllowNativeHeapPointerTagging(); + + boolean hasPreserveLegacyExternalStorage(); + + /** + * @see ApplicationInfo#targetSandboxVersion + * @see R.styleable#AndroidManifest_targetSandboxVersion + */ + @Deprecated + int getTargetSandboxVersion(); + + /** + * @see ApplicationInfo#theme + * @see R.styleable#AndroidManifestApplication_theme + */ + int getTheme(); + + /** + * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in + * {@link PackageParser#TAG_KEY_SETS}. + * @see R.styleable#AndroidManifestUpgradeKeySet + */ + @NonNull + Set<String> getUpgradeKeySets(); + + /** + * The install time abi override to choose 32bit abi's when multiple abi's + * are present. This is only meaningfull for multiarch applications. + * The use32bitAbi attribute is ignored if cpuAbiOverride is also set. + */ + boolean isUse32BitAbi(); + + /** @see ApplicationInfo#volumeUuid */ + @Nullable + String getVolumeUuid(); + + /** @see ApplicationInfo#zygotePreloadName */ + @Nullable + String getZygotePreloadName(); + + /** Revision code of base APK */ + int getBaseRevisionCode(); + + /** @see PackageInfo#versionName */ + @Nullable + String getVersionName(); + + /** @see PackageInfo#versionCodeMajor */ + @Nullable + int getVersionCode(); + + /** @see PackageInfo#versionCodeMajor */ + @Nullable + int getVersionCodeMajor(); + + /** + * @see ApplicationInfo#compileSdkVersion + * @see R.styleable#AndroidManifest_compileSdkVersion + */ + int getCompileSdkVersion(); + + /** + * @see ApplicationInfo#compileSdkVersionCodename + * @see R.styleable#AndroidManifest_compileSdkVersionCodename + */ + @Nullable + String getCompileSdkVersionCodeName(); + + @Nullable + Set<String> getMimeGroups(); + + // TODO(b/135203078): Hide and enforce going through PackageInfoUtils + ApplicationInfo toAppInfoWithoutState(); +} diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java new file mode 100644 index 000000000000..40754dff5ea0 --- /dev/null +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -0,0 +1,2673 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.PackageManager.FEATURE_WATCH; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; +import static android.os.Build.VERSION_CODES.DONUT; +import static android.os.Build.VERSION_CODES.O; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; + +import android.annotation.AnyRes; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.StyleableRes; +import android.app.ActivityThread; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.PackageParser.SigningDetails; +import android.content.pm.Signature; +import android.content.pm.parsing.component.ComponentParseUtils; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedActivityUtils; +import android.content.pm.parsing.component.ParsedFeature; +import android.content.pm.parsing.component.ParsedFeatureUtils; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedInstrumentationUtils; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedIntentInfoUtils; +import android.content.pm.parsing.component.ParsedMainComponent; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.content.pm.parsing.component.ParsedPermissionUtils; +import android.content.pm.parsing.component.ParsedProcess; +import android.content.pm.parsing.component.ParsedProcessUtils; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedProviderUtils; +import android.content.pm.parsing.component.ParsedService; +import android.content.pm.parsing.component.ParsedServiceUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.pm.permission.SplitPermissionInfoParcelable; +import android.content.pm.split.DefaultSplitAssetLoader; +import android.content.pm.split.SplitAssetDependencyLoader; +import android.content.pm.split.SplitAssetLoader; +import android.content.res.ApkAssets; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.FileUtils; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.os.Trace; +import android.os.ext.SdkExtensions; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Pair; +import android.util.Slog; +import android.util.SparseArray; +import android.util.TypedValue; +import android.util.apk.ApkSignatureVerifier; + +import com.android.internal.R; +import com.android.internal.os.ClassLoaderFactory; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.XmlUtils; + +import libcore.io.IoUtils; +import libcore.util.EmptyArray; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * TODO(b/135203078): Differentiate between parse_ methods and some add_ method for whether it + * mutates the passed-in component or not. Or consolidate so all parse_ methods mutate. + * + * @hide + */ +public class ParsingPackageUtils { + + public static final String TAG = ParsingUtils.TAG; + + private boolean mOnlyCoreApps; + private String[] mSeparateProcesses; + private DisplayMetrics mDisplayMetrics; + private Callback mCallback; + + public ParsingPackageUtils(boolean onlyCoreApps, String[] separateProcesses, + DisplayMetrics displayMetrics, @NonNull Callback callback) { + mOnlyCoreApps = onlyCoreApps; + mSeparateProcesses = separateProcesses; + mDisplayMetrics = displayMetrics; + mCallback = callback; + } + + /** + * Parse the package at the given location. Automatically detects if the + * package is a monolithic style (single APK file) or cluster style + * (directory of APKs). + * <p> + * This performs sanity checking on cluster style packages, such as + * requiring identical package name and version codes, a single base APK, + * and unique split names. + * <p> + * Note that this <em>does not</em> perform signature verification; that + * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}. + * + * If {@code useCaches} is true, the package parser might return a cached + * result from a previous parse of the same {@code packageFile} with the same + * {@code flags}. Note that this method does not check whether {@code packageFile} + * has changed since the last parse, it's up to callers to do so. + * + * @see PackageParser#parsePackageLite(File, int) + */ + public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, + int flags) + throws PackageParserException { + if (packageFile.isDirectory()) { + return parseClusterPackage(input, packageFile, flags); + } else { + return parseMonolithicPackage(input, packageFile, flags); + } + } + + /** + * Parse all APKs contained in the given directory, treating them as a + * single package. This also performs sanity checking, such as requiring + * identical package name and version codes, a single base APK, and unique + * split names. + * <p> + * Note that this <em>does not</em> perform signature verification; that + * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}. + */ + private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir, + int flags) throws PackageParserException { + final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir, + 0); + if (mOnlyCoreApps && !lite.coreApp) { + return input.error("Not a coreApp: " + packageDir); + } + + // Build the split dependency tree. + SparseArray<int[]> splitDependencies = null; + final SplitAssetLoader assetLoader; + if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) { + try { + splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite); + assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags); + } catch (SplitAssetDependencyLoader.IllegalDependencyException e) { + return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage()); + } + } else { + assetLoader = new DefaultSplitAssetLoader(lite, flags); + } + + try { + final AssetManager assets = assetLoader.getBaseAssetManager(); + final File baseApk = new File(lite.baseCodePath); + ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk, + lite.codePath, assets, flags); + // TODO(b/135203078): Pass original error up? + if (result.isError()) { + return input.error(INSTALL_PARSE_FAILED_NOT_APK, + "Failed to parse base APK: " + baseApk); + } + + ParsingPackage pkg = result.getResult(); + if (!ArrayUtils.isEmpty(lite.splitNames)) { + pkg.asSplit( + lite.splitNames, + lite.splitCodePaths, + lite.splitRevisionCodes, + splitDependencies + ); + final int num = lite.splitNames.length; + + for (int i = 0; i < num; i++) { + final AssetManager splitAssets = assetLoader.getSplitAssetManager(i); + parseSplitApk(input, pkg, i, splitAssets, flags); + } + } + + pkg.setUse32BitAbi(lite.use32bitAbi); + return input.success(pkg); + } finally { + IoUtils.closeQuietly(assetLoader); + } + } + + /** + * Parse the given APK file, treating it as as a single monolithic package. + * <p> + * Note that this <em>does not</em> perform signature verification; that + * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}. + */ + private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile, + int flags) throws PackageParserException { + final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile, + flags); + if (mOnlyCoreApps && !lite.coreApp) { + return input.error("Not a coreApp: " + apkFile); + } + + final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); + try { + ParseResult<ParsingPackage> result = parseBaseApk(input, + apkFile, + apkFile.getCanonicalPath(), + assetLoader.getBaseAssetManager(), flags); + if (result.isError()) { + return input.error(result); + } + + return input.success(result.getResult() + .setUse32BitAbi(lite.use32bitAbi)); + } catch (IOException e) { + return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to get path: " + apkFile, e); + } finally { + IoUtils.closeQuietly(assetLoader); + } + } + + private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile, + String codePath, AssetManager assets, int flags) { + final String apkPath = apkFile.getAbsolutePath(); + + String volumeUuid = null; + if (apkPath.startsWith(PackageParser.MNT_EXPAND)) { + final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length()); + volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end); + } + + if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); + + final int cookie = assets.findCookieForPath(apkPath); + if (cookie == 0) { + return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Failed adding asset path: " + apkPath); + } + + try (XmlResourceParser parser = assets.openXmlResourceParser(cookie, + PackageParser.ANDROID_MANIFEST_FILENAME)) { + final Resources res = new Resources(assets, mDisplayMetrics, null); + + ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res, + parser, flags); + if (result.isError()) { + return input.error(result.getErrorCode(), + apkPath + " (at " + parser.getPositionDescription() + "): " + + result.getErrorMessage()); + } + + ParsingPackage pkg = result.getResult(); + ApkAssets apkAssets = assets.getApkAssets()[0]; + if (apkAssets.definesOverlayable()) { + SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers(); + int size = packageNames.size(); + for (int index = 0; index < size; index++) { + String packageName = packageNames.get(index); + Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName); + if (overlayableToActor != null && !overlayableToActor.isEmpty()) { + for (String overlayable : overlayableToActor.keySet()) { + pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable)); + } + } + } + } + + pkg.setVolumeUuid(volumeUuid) + .setSigningDetails(SigningDetails.UNKNOWN); + + return input.success(pkg); + } catch (Exception e) { + return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to read manifest from " + apkPath, e); + } + } + + private ParseResult<ParsingPackage> parseSplitApk(ParseInput input, + ParsingPackage pkg, int splitIndex, AssetManager assets, int flags) { + final String apkPath = pkg.getSplitCodePaths()[splitIndex]; + + if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); + + // This must always succeed, as the path has been added to the AssetManager before. + final int cookie = assets.findCookieForPath(apkPath); + if (cookie == 0) { + return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Failed adding asset path: " + apkPath); + } + try (XmlResourceParser parser = assets.openXmlResourceParser(cookie, + PackageParser.ANDROID_MANIFEST_FILENAME)) { + Resources res = new Resources(assets, mDisplayMetrics, null); + ParseResult<ParsingPackage> parseResult = parseSplitApk(input, pkg, res, + parser, flags, splitIndex); + if (parseResult.isError()) { + return input.error(parseResult.getErrorCode(), + apkPath + " (at " + parser.getPositionDescription() + "): " + + parseResult.getErrorMessage()); + } + + return parseResult; + } catch (Exception e) { + return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to read manifest from " + apkPath, e); + } + } + + /** + * Parse the manifest of a <em>base APK</em>. When adding new features you + * need to consider whether they should be supported by split APKs and child + * packages. + * + * @param apkPath The package apk file path + * @param res The resources from which to resolve values + * @param parser The manifest parser + * @param flags Flags how to parse + * @return Parsed package or null on error. + */ + private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath, + String codePath, Resources res, XmlResourceParser parser, int flags) + throws XmlPullParserException, IOException { + final String splitName; + final String pkgName; + + try { + Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser, + parser); + pkgName = packageSplit.first; + splitName = packageSplit.second; + + if (!TextUtils.isEmpty(splitName)) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, + "Expected base APK, but found split " + splitName + ); + } + } catch (PackageParserException e) { + return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME); + } + + TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest); + try { + boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false); + + ParsingPackage pkg = mCallback.startParsingPackage(pkgName, apkPath, codePath, + manifestArray, isCoreApp); + + ParseResult<ParsingPackage> result = parseBaseApkTags(input, pkg, manifestArray, + res, parser, flags); + if (result.isError()) { + return result; + } + + return input.success(pkg); + } finally { + manifestArray.recycle(); + } + } + + /** + * Parse the manifest of a <em>split APK</em>. + * <p> + * Note that split APKs have many more restrictions on what they're capable + * of doing, so many valid features of a base APK have been carefully + * omitted here. + * + * @param pkg builder to fill + * @return false on failure + */ + private ParseResult<ParsingPackage> parseSplitApk(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser, int flags, int splitIndex) + throws XmlPullParserException, IOException, PackageParserException { + AttributeSet attrs = parser; + + // We parsed manifest tag earlier; just skip past it + PackageParser.parsePackageSplitNames(parser, attrs); + + int type; + + boolean foundApp = false; + + int outerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (outerDepth + 1 < parser.getDepth() || type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + String tagName = parser.getName(); + if (PackageParser.TAG_APPLICATION.equals(tagName)) { + if (foundApp) { + if (PackageParser.RIGID_PARSER) { + result = input.error("<manifest> has more than one <application>"); + } else { + Slog.w(TAG, "<manifest> has more than one <application>"); + result = input.success(null); + } + } else { + foundApp = true; + result = parseSplitApplication(input, pkg, res, parser, flags, splitIndex); + } + } else { + result = ParsingUtils.unknownTag("<manifest>", pkg, parser, input); + } + + if (result.isError()) { + return input.error(result); + } + } + + if (!foundApp) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY, + "<manifest> does not contain an <application>" + ); + } + + return input.success(pkg); + } + + /** + * Parse the {@code application} XML tree at the current parse location in a + * <em>split APK</em> manifest. + * <p> + * Note that split APKs have many more restrictions on what they're capable + * of doing, so many valid features of a base APK have been carefully + * omitted here. + */ + private ParseResult<ParsingPackage> parseSplitApplication(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, int splitIndex) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); + try { + pkg.setSplitHasCode(splitIndex, sa.getBoolean( + R.styleable.AndroidManifestApplication_hasCode, true)); + + final String classLoaderName = sa.getString( + R.styleable.AndroidManifestApplication_classLoader); + if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName( + classLoaderName)) { + pkg.setSplitClassLoaderName(splitIndex, classLoaderName); + } else { + return input.error("Invalid class loader name: " + classLoaderName); + } + } finally { + sa.recycle(); + } + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + ParsedMainComponent mainComponent = null; + + final ParseResult result; + String tagName = parser.getName(); + boolean isActivity = false; + switch (tagName) { + case "activity": + isActivity = true; + // fall-through + case "receiver": + ParseResult<ParsedActivity> activityResult = + ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg, + res, + parser, flags, PackageParser.sUseRoundIcon, input); + if (activityResult.isSuccess()) { + ParsedActivity activity = activityResult.getResult(); + if (isActivity) { + pkg.addActivity(activity); + } else { + pkg.addReceiver(activity); + } + mainComponent = activity; + } + result = activityResult; + break; + case "service": + ParseResult<ParsedService> serviceResult = ParsedServiceUtils.parseService( + mSeparateProcesses, pkg, res, parser, flags, + PackageParser.sUseRoundIcon, input); + if (serviceResult.isSuccess()) { + ParsedService service = serviceResult.getResult(); + pkg.addService(service); + mainComponent = service; + } + result = serviceResult; + break; + case "provider": + ParseResult<ParsedProvider> providerResult = + ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser, + flags, PackageParser.sUseRoundIcon, input); + if (providerResult.isSuccess()) { + ParsedProvider provider = providerResult.getResult(); + pkg.addProvider(provider); + mainComponent = provider; + } + result = providerResult; + break; + case "activity-alias": + activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, parser, + PackageParser.sUseRoundIcon, input); + if (activityResult.isSuccess()) { + ParsedActivity activity = activityResult.getResult(); + pkg.addActivity(activity); + mainComponent = activity; + } + + result = activityResult; + break; + default: + result = parseSplitBaseAppChildTags(input, tagName, pkg, res, parser); + break; + } + + if (result.isError()) { + return input.error(result); + } + + if (mainComponent != null && mainComponent.getSplitName() == null) { + // If the loaded component did not specify a split, inherit the split name + // based on the split it is defined in. + // This is used to later load the correct split when starting this + // component. + mainComponent.setSplitName(pkg.getSplitNames()[splitIndex]); + } + } + + return input.success(pkg); + } + + /** + * For parsing non-MainComponents. Main ones have an order and some special handling which is + * done directly in {@link #parseSplitApplication(ParseInput, ParsingPackage, Resources, + * XmlResourceParser, int, int)}. + */ + private ParseResult parseSplitBaseAppChildTags(ParseInput input, String tag, ParsingPackage pkg, + Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException { + switch (tag) { + case "meta-data": + // note: application meta-data is stored off to the side, so it can + // remain null in the primary copy (we like to avoid extra copies because + // it can be large) + ParseResult<Bundle> metaDataResult = parseMetaData(pkg, res, parser, + pkg.getMetaData(), input); + if (metaDataResult.isSuccess()) { + pkg.setMetaData(metaDataResult.getResult()); + } + return metaDataResult; + case "uses-static-library": + return parseUsesStaticLibrary(input, pkg, res, parser); + case "uses-library": + return parseUsesLibrary(input, pkg, res, parser); + case "uses-package": + // Dependencies for app installers; we don't currently try to + // enforce this. + return input.success(null); + default: + return ParsingUtils.unknownTag("<application>", pkg, parser, input); + } + } + + private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg, + TypedArray sa, Resources res, XmlResourceParser parser, int flags) + throws XmlPullParserException, IOException { + ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa); + if (sharedUserResult.isError()) { + return sharedUserResult; + } + + pkg.setInstallLocation(anInt(PackageParser.PARSE_DEFAULT_INSTALL_LOCATION, + R.styleable.AndroidManifest_installLocation, sa)) + .setTargetSandboxVersion(anInt(PackageParser.PARSE_DEFAULT_TARGET_SANDBOX, + R.styleable.AndroidManifest_targetSandboxVersion, sa)) + /* Set the global "on SD card" flag */ + .setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0) + .setIsolatedSplitLoading( + bool(false, R.styleable.AndroidManifest_isolatedSplits, sa)); + + boolean foundApp = false; + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + String tagName = parser.getName(); + final ParseResult result; + + // TODO(b/135203078): Convert to instance methods to share variables + // <application> has special logic, so it's handled outside the general method + if (PackageParser.TAG_APPLICATION.equals(tagName)) { + if (foundApp) { + if (PackageParser.RIGID_PARSER) { + result = input.error("<manifest> has more than one <application>"); + } else { + Slog.w(TAG, "<manifest> has more than one <application>"); + result = input.success(null); + } + } else { + foundApp = true; + result = parseBaseApplication(input, pkg, res, parser, flags); + } + } else { + result = parseBaseApkTag(tagName, input, pkg, res, parser, flags); + } + + if (result.isError()) { + return input.error(result); + } + } + + if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY, + "<manifest> does not contain an <application> or <instrumentation>" + ); + } + + if (!ParsedFeature.isCombinationValid(pkg.getFeatures())) { + return input.error( + INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Combination <feature> tags are not valid" + ); + } + + convertNewPermissions(pkg); + + convertSplitPermissions(pkg); + + // At this point we can check if an application is not supporting densities and hence + // cannot be windowed / resized. Note that an SDK version of 0 is common for + // pre-Doughnut applications. + if (pkg.getTargetSdkVersion() < DONUT + || (!pkg.isSupportsSmallScreens() + && !pkg.isSupportsNormalScreens() + && !pkg.isSupportsLargeScreens() + && !pkg.isSupportsExtraLargeScreens() + && !pkg.isResizeable() + && !pkg.isAnyDensity())) { + adjustPackageToBeUnresizeableAndUnpipable(pkg); + } + + return input.success(pkg); + } + + private ParseResult parseBaseApkTag(String tag, ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags) + throws IOException, XmlPullParserException { + switch (tag) { + case PackageParser.TAG_OVERLAY: + return parseOverlay(input, pkg, res, parser); + case PackageParser.TAG_KEY_SETS: + return parseKeySets(input, pkg, res, parser); + case PackageParser.TAG_FEATURE: + return parseFeature(input, pkg, res, parser); + case PackageParser.TAG_PERMISSION_GROUP: + return parsePermissionGroup(input, pkg, res, parser); + case PackageParser.TAG_PERMISSION: + return parsePermission(input, pkg, res, parser); + case PackageParser.TAG_PERMISSION_TREE: + return parsePermissionTree(input, pkg, res, parser); + case PackageParser.TAG_USES_PERMISSION: + case PackageParser.TAG_USES_PERMISSION_SDK_M: + case PackageParser.TAG_USES_PERMISSION_SDK_23: + return parseUsesPermission(input, pkg, res, parser); + case PackageParser.TAG_USES_CONFIGURATION: + return parseUsesConfiguration(input, pkg, res, parser); + case PackageParser.TAG_USES_FEATURE: + return parseUsesFeature(input, pkg, res, parser); + case PackageParser.TAG_FEATURE_GROUP: + return parseFeatureGroup(input, pkg, res, parser); + case PackageParser.TAG_USES_SDK: + return parseUsesSdk(input, pkg, res, parser); + case PackageParser.TAG_SUPPORT_SCREENS: + return parseSupportScreens(input, pkg, res, parser); + case PackageParser.TAG_PROTECTED_BROADCAST: + return parseProtectedBroadcast(input, pkg, res, parser); + case PackageParser.TAG_INSTRUMENTATION: + return parseInstrumentation(input, pkg, res, parser); + case PackageParser.TAG_ORIGINAL_PACKAGE: + return parseOriginalPackage(input, pkg, res, parser); + case PackageParser.TAG_ADOPT_PERMISSIONS: + return parseAdoptPermissions(input, pkg, res, parser); + case PackageParser.TAG_USES_GL_TEXTURE: + case PackageParser.TAG_COMPATIBLE_SCREENS: + case PackageParser.TAG_SUPPORTS_INPUT: + case PackageParser.TAG_EAT_COMMENT: + // Just skip this tag + XmlUtils.skipCurrentTag(parser); + return input.success(pkg); + case PackageParser.TAG_RESTRICT_UPDATE: + return parseRestrictUpdateHash(flags, input, pkg, res, parser); + case PackageParser.TAG_QUERIES: + return parseQueries(input, pkg, res, parser); + default: + return ParsingUtils.unknownTag("<manifest>", pkg, parser, input); + } + } + + private static ParseResult<ParsingPackage> parseSharedUser(ParseInput input, + ParsingPackage pkg, TypedArray sa) { + String str = nonConfigString(0, R.styleable.AndroidManifest_sharedUserId, sa); + if (TextUtils.isEmpty(str)) { + return input.success(pkg); + } + + ParseResult nameResult = validateName(input, str, true, true); + if (nameResult.isError()) { + if ("android".equals(pkg.getPackageName())) { + nameResult.ignoreError(); + } else { + return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, + "<manifest> specifies bad sharedUserId name \"" + str + "\": " + + nameResult.getErrorMessage()); + } + } + + return input.success(pkg + .setSharedUserId(str.intern()) + .setSharedUserLabel(resId(R.styleable.AndroidManifest_sharedUserLabel, sa))); + } + + private static ParseResult<ParsingPackage> parseKeySets(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + // we've encountered the 'key-sets' tag + // all the keys and keysets that we want must be defined here + // so we're going to iterate over the parser and pull out the things we want + int outerDepth = parser.getDepth(); + int currentKeySetDepth = -1; + int type; + String currentKeySet = null; + ArrayMap<String, PublicKey> publicKeys = new ArrayMap<>(); + ArraySet<String> upgradeKeySets = new ArraySet<>(); + ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<>(); + ArraySet<String> improperKeySets = new ArraySet<>(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG) { + if (parser.getDepth() == currentKeySetDepth) { + currentKeySet = null; + currentKeySetDepth = -1; + } + continue; + } + String tagName = parser.getName(); + switch (tagName) { + case "key-set": { + if (currentKeySet != null) { + return input.error("Improperly nested 'key-set' tag at " + + parser.getPositionDescription()); + } + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestKeySet); + try { + final String keysetName = sa.getNonResourceString( + R.styleable.AndroidManifestKeySet_name); + definedKeySets.put(keysetName, new ArraySet<>()); + currentKeySet = keysetName; + currentKeySetDepth = parser.getDepth(); + } finally { + sa.recycle(); + } + } break; + case "public-key": { + if (currentKeySet == null) { + return input.error("Improperly nested 'key-set' tag at " + + parser.getPositionDescription()); + } + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestPublicKey); + try { + final String publicKeyName = nonResString( + R.styleable.AndroidManifestPublicKey_name, sa); + final String encodedKey = nonResString( + R.styleable.AndroidManifestPublicKey_value, sa); + if (encodedKey == null && publicKeys.get(publicKeyName) == null) { + return input.error("'public-key' " + publicKeyName + + " must define a public-key value on first use at " + + parser.getPositionDescription()); + } else if (encodedKey != null) { + PublicKey currentKey = PackageParser.parsePublicKey(encodedKey); + if (currentKey == null) { + Slog.w(TAG, "No recognized valid key in 'public-key' tag at " + + parser.getPositionDescription() + " key-set " + + currentKeySet + + " will not be added to the package's defined key-sets."); + improperKeySets.add(currentKeySet); + XmlUtils.skipCurrentTag(parser); + continue; + } + if (publicKeys.get(publicKeyName) == null + || publicKeys.get(publicKeyName).equals(currentKey)) { + + /* public-key first definition, or matches old definition */ + publicKeys.put(publicKeyName, currentKey); + } else { + return input.error("Value of 'public-key' " + publicKeyName + + " conflicts with previously defined value at " + + parser.getPositionDescription()); + } + } + definedKeySets.get(currentKeySet).add(publicKeyName); + XmlUtils.skipCurrentTag(parser); + } finally { + sa.recycle(); + } + } break; + case "upgrade-key-set": { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUpgradeKeySet); + try { + String name = sa.getNonResourceString( + R.styleable.AndroidManifestUpgradeKeySet_name); + upgradeKeySets.add(name); + XmlUtils.skipCurrentTag(parser); + } finally { + sa.recycle(); + } + } break; + default: + ParseResult result = ParsingUtils.unknownTag("<key-sets>", pkg, parser, + input); + if (result.isError()) { + return input.error(result); + } + break; + } + } + String packageName = pkg.getPackageName(); + Set<String> publicKeyNames = publicKeys.keySet(); + if (publicKeyNames.removeAll(definedKeySets.keySet())) { + return input.error("Package" + packageName + + " AndroidManifest.xml 'key-set' and 'public-key' names must be distinct."); + } + + for (ArrayMap.Entry<String, ArraySet<String>> e : definedKeySets.entrySet()) { + final String keySetName = e.getKey(); + if (e.getValue().size() == 0) { + Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " + + "'key-set' " + keySetName + " has no valid associated 'public-key'." + + " Not including in package's defined key-sets."); + continue; + } else if (improperKeySets.contains(keySetName)) { + Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " + + "'key-set' " + keySetName + " contained improper 'public-key'" + + " tags. Not including in package's defined key-sets."); + continue; + } + + for (String s : e.getValue()) { + pkg.addKeySet(keySetName, publicKeys.get(s)); + } + } + if (pkg.getKeySetMapping().keySet().containsAll(upgradeKeySets)) { + pkg.setUpgradeKeySets(upgradeKeySets); + } else { + return input.error("Package" + packageName + + " AndroidManifest.xml does not define all 'upgrade-key-set's ."); + } + + return input.success(pkg); + } + + private static ParseResult<ParsingPackage> parseFeature(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException { + ParseResult<ParsedFeature> result = ParsedFeatureUtils.parseFeature(res, parser, input); + if (result.isError()) { + return input.error(result); + } + return input.success(pkg.addFeature(result.getResult())); + } + + private static ParseResult<ParsingPackage> parsePermissionGroup(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + ParseResult<ParsedPermissionGroup> result = ParsedPermissionUtils.parsePermissionGroup( + pkg, res, parser, PackageParser.sUseRoundIcon, input); + if (result.isError()) { + return input.error(result); + } + return input.success(pkg.addPermissionGroup(result.getResult())); + } + + private static ParseResult<ParsingPackage> parsePermission(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + ParseResult<ParsedPermission> result = ParsedPermissionUtils.parsePermission( + pkg, res, parser, PackageParser.sUseRoundIcon, input); + if (result.isError()) { + return input.error(result); + } + return input.success(pkg.addPermission(result.getResult())); + } + + private static ParseResult<ParsingPackage> parsePermissionTree(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + ParseResult<ParsedPermission> result = ParsedPermissionUtils.parsePermissionTree( + pkg, res, parser, PackageParser.sUseRoundIcon, input); + if (result.isError()) { + return input.error(result); + } + return input.success(pkg.addPermission(result.getResult())); + } + + private ParseResult<ParsingPackage> parseUsesPermission(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesPermission); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String name = sa.getNonResourceString( + R.styleable.AndroidManifestUsesPermission_name); + + int maxSdkVersion = 0; + TypedValue val = sa.peekValue( + R.styleable.AndroidManifestUsesPermission_maxSdkVersion); + if (val != null) { + if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) { + maxSdkVersion = val.data; + } + } + + final String requiredFeature = sa.getNonConfigurationString( + R.styleable.AndroidManifestUsesPermission_requiredFeature, 0); + + final String requiredNotfeature = sa.getNonConfigurationString( + R.styleable.AndroidManifestUsesPermission_requiredNotFeature, + 0); + + XmlUtils.skipCurrentTag(parser); + + // Can only succeed from here on out + ParseResult<ParsingPackage> success = input.success(pkg); + + if (name == null) { + return success; + } + + if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) { + return success; + } + + // Only allow requesting this permission if the platform supports the given feature. + if (requiredFeature != null && mCallback != null && !mCallback.hasFeature( + requiredFeature)) { + return success; + } + + // Only allow requesting this permission if the platform doesn't support the given + // feature. + if (requiredNotfeature != null && mCallback != null + && mCallback.hasFeature(requiredNotfeature)) { + return success; + } + + if (!pkg.getRequestedPermissions().contains(name)) { + pkg.addRequestedPermission(name.intern()); + } else { + Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: " + + name + " in package: " + pkg.getPackageName() + " at: " + + parser.getPositionDescription()); + } + + return success; + } finally { + sa.recycle(); + } + } + + private static ParseResult<ParsingPackage> parseUsesConfiguration(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + ConfigurationInfo cPref = new ConfigurationInfo(); + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesConfiguration); + try { + cPref.reqTouchScreen = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, + Configuration.TOUCHSCREEN_UNDEFINED); + cPref.reqKeyboardType = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, + Configuration.KEYBOARD_UNDEFINED); + if (sa.getBoolean( + R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; + } + cPref.reqNavigation = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqNavigation, + Configuration.NAVIGATION_UNDEFINED); + if (sa.getBoolean( + R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; + } + pkg.addConfigPreference(cPref); + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + private static ParseResult<ParsingPackage> parseUsesFeature(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + FeatureInfo fi = parseFeatureInfo(res, parser); + pkg.addReqFeature(fi); + + if (fi.name == null) { + ConfigurationInfo cPref = new ConfigurationInfo(); + cPref.reqGlEsVersion = fi.reqGlEsVersion; + pkg.addConfigPreference(cPref); + } + + return input.success(pkg); + } + + private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) { + FeatureInfo fi = new FeatureInfo(); + TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestUsesFeature); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name); + fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0); + if (fi.name == null) { + fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion, + FeatureInfo.GL_ES_VERSION_UNDEFINED); + } + if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) { + fi.flags |= FeatureInfo.FLAG_REQUIRED; + } + return fi; + } finally { + sa.recycle(); + } + } + + private static ParseResult<ParsingPackage> parseFeatureGroup(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws IOException, XmlPullParserException { + FeatureGroupInfo group = new FeatureGroupInfo(); + ArrayList<FeatureInfo> features = null; + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final String innerTagName = parser.getName(); + if (innerTagName.equals("uses-feature")) { + FeatureInfo featureInfo = parseFeatureInfo(res, parser); + // FeatureGroups are stricter and mandate that + // any <uses-feature> declared are mandatory. + featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; + features = ArrayUtils.add(features, featureInfo); + } else { + Slog.w(TAG, + "Unknown element under <feature-group>: " + innerTagName + + " at " + pkg.getBaseCodePath() + " " + + parser.getPositionDescription()); + } + } + + if (features != null) { + group.features = new FeatureInfo[features.size()]; + group.features = features.toArray(group.features); + } + + pkg.addFeatureGroup(group); + return input.success(pkg); + } + + private static ParseResult<ParsingPackage> parseUsesSdk(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws IOException, XmlPullParserException { + if (PackageParser.SDK_VERSION > 0) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk); + try { + int minVers = 1; + String minCode = null; + int targetVers = 0; + String targetCode = null; + + TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + minCode = val.string.toString(); + } else { + // If it's not a string, it's an integer. + minVers = val.data; + } + } + + val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + targetCode = val.string.toString(); + if (minCode == null) { + minCode = targetCode; + } + } else { + // If it's not a string, it's an integer. + targetVers = val.data; + } + } else { + targetVers = minVers; + targetCode = minCode; + } + + ParseResult<Integer> minSdkVersionResult = computeMinSdkVersion(minVers, minCode, + PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, input); + if (minSdkVersionResult.isError()) { + return input.error(minSdkVersionResult); + } + + int minSdkVersion = minSdkVersionResult.getResult(); + + ParseResult<Integer> targetSdkVersionResult = computeTargetSdkVersion( + targetVers, targetCode, PackageParser.SDK_CODENAMES, input); + if (targetSdkVersionResult.isError()) { + return input.error(targetSdkVersionResult); + } + + int targetSdkVersion = minSdkVersionResult.getResult(); + + pkg.setMinSdkVersion(minSdkVersion) + .setTargetSdkVersion(targetSdkVersion); + + int type; + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + final ParseResult result; + if (parser.getName().equals("extension-sdk")) { + result = parseExtensionSdk(input, pkg, res, parser); + XmlUtils.skipCurrentTag(parser); + } else { + result = ParsingUtils.unknownTag("<uses-sdk>", pkg, parser, input); + } + + if (result.isError()) { + return input.error(result); + } + } + } finally { + sa.recycle(); + } + } + return input.success(pkg); + } + + private static ParseResult parseExtensionSdk(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser) { + int sdkVersion; + int minVersion; + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestExtensionSdk); + try { + sdkVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_sdkVersion, -1); + minVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_minExtensionVersion, -1); + } finally { + sa.recycle(); + } + + if (sdkVersion < 0) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<extension-sdk> must specify an sdkVersion >= 0"); + } + if (minVersion < 0) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<extension-sdk> must specify minExtensionVersion >= 0"); + } + + try { + int version = SdkExtensions.getExtensionVersion(sdkVersion); + if (version < minVersion) { + return input.error( + PackageManager.INSTALL_FAILED_OLDER_SDK, + "Package requires " + sdkVersion + " extension version " + minVersion + + " which exceeds device version " + version); + } + } catch (RuntimeException e) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Specified sdkVersion " + sdkVersion + " is not valid"); + } + return input.success(pkg); + } + + /** + * {@link ParseResult} version of + * {@link PackageParser#computeMinSdkVersion(int, String, int, String[], String[])} + */ + public static ParseResult<Integer> computeMinSdkVersion(@IntRange(from = 1) int minVers, + @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion, + @NonNull String[] platformSdkCodenames, @NonNull ParseInput input) { + // If it's a release SDK, make sure we meet the minimum SDK requirement. + if (minCode == null) { + if (minVers <= platformSdkVersion) { + return input.success(minVers); + } + + // We don't meet the minimum SDK requirement. + return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, + "Requires newer sdk version #" + minVers + + " (current version is #" + platformSdkVersion + ")"); + } + + // If it's a pre-release SDK and the codename matches this platform, we + // definitely meet the minimum SDK requirement. + if (matchTargetCode(platformSdkCodenames, minCode)) { + return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); + } + + // Otherwise, we're looking at an incompatible pre-release SDK. + if (platformSdkCodenames.length > 0) { + return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, + "Requires development platform " + minCode + + " (current platform is any of " + + Arrays.toString(platformSdkCodenames) + ")"); + } else { + return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, + "Requires development platform " + minCode + + " but this is a release platform."); + } + } + + /** + * {@link ParseResult} version of + * {@link PackageParser#computeTargetSdkVersion(int, String, String[], String[])} + */ + public static ParseResult<Integer> computeTargetSdkVersion(@IntRange(from = 0) int targetVers, + @Nullable String targetCode, @NonNull String[] platformSdkCodenames, + @NonNull ParseInput input) { + // If it's a release SDK, return the version number unmodified. + if (targetCode == null) { + return input.success(targetVers); + } + + // If it's a pre-release SDK and the codename matches this platform, it + // definitely targets this SDK. + if (matchTargetCode(platformSdkCodenames, targetCode)) { + return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); + } + + // Otherwise, we're looking at an incompatible pre-release SDK. + if (platformSdkCodenames.length > 0) { + return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, + "Requires development platform " + targetCode + + " (current platform is any of " + + Arrays.toString(platformSdkCodenames) + ")"); + } else { + return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, + "Requires development platform " + targetCode + + " but this is a release platform."); + } + } + + /** + * Matches a given {@code targetCode} against a set of release codeNames. Target codes can + * either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form + * {@code [codename].[fingerprint]} (e.g {@code "Q.cafebc561"}). + */ + private static boolean matchTargetCode(@NonNull String[] codeNames, + @NonNull String targetCode) { + final String targetCodeName; + final int targetCodeIdx = targetCode.indexOf('.'); + if (targetCodeIdx == -1) { + targetCodeName = targetCode; + } else { + targetCodeName = targetCode.substring(0, targetCodeIdx); + } + return ArrayUtils.contains(codeNames, targetCodeName); + } + + private static ParseResult<ParsingPackage> parseRestrictUpdateHash(int flags, ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestRestrictUpdate); + try { + final String hash = sa.getNonConfigurationString( + R.styleable.AndroidManifestRestrictUpdate_hash, + 0); + + if (hash != null) { + final int hashLength = hash.length(); + final byte[] hashBytes = new byte[hashLength / 2]; + for (int i = 0; i < hashLength; i += 2) { + hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16) + << 4) + + Character.digit(hash.charAt(i + 1), 16)); + } + pkg.setRestrictUpdateHash(hashBytes); + } else { + pkg.setRestrictUpdateHash(null); + } + } finally { + sa.recycle(); + } + } + return input.success(pkg); + } + + private static ParseResult<ParsingPackage> parseQueries(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException { + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + if (parser.getName().equals("intent")) { + ParseResult<ParsedIntentInfo> result = ParsedIntentInfoUtils.parseIntentInfo(null, + pkg, res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/, input); + if (result.isError()) { + return input.error(result); + } + + ParsedIntentInfo intentInfo = result.getResult(); + + Uri data = null; + String dataType = null; + String host = ""; + final int numActions = intentInfo.countActions(); + final int numSchemes = intentInfo.countDataSchemes(); + final int numTypes = intentInfo.countDataTypes(); + final int numHosts = intentInfo.getHosts().length; + if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) { + return input.error("intent tags must contain either an action or data."); + } + if (numActions > 1) { + return input.error("intent tag may have at most one action."); + } + if (numTypes > 1) { + return input.error("intent tag may have at most one data type."); + } + if (numSchemes > 1) { + return input.error("intent tag may have at most one data scheme."); + } + if (numHosts > 1) { + return input.error("intent tag may have at most one data host."); + } + Intent intent = new Intent(); + for (int i = 0, max = intentInfo.countCategories(); i < max; i++) { + intent.addCategory(intentInfo.getCategory(i)); + } + if (numHosts == 1) { + host = intentInfo.getHosts()[0]; + } + if (numSchemes == 1) { + data = new Uri.Builder() + .scheme(intentInfo.getDataScheme(0)) + .authority(host) + .build(); + } + if (numTypes == 1) { + dataType = intentInfo.getDataType(0); + } + intent.setDataAndType(data, dataType); + if (numActions == 1) { + intent.setAction(intentInfo.getAction(0)); + } + pkg.addQueriesIntent(intent); + } else if (parser.getName().equals("package")) { + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestQueriesPackage); + final String packageName = sa.getString( + R.styleable.AndroidManifestQueriesPackage_name); + if (TextUtils.isEmpty(packageName)) { + return input.error("Package name is missing from package tag."); + } + pkg.addQueriesPackage(packageName.intern()); + } else if (parser.getName().equals("provider")) { + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestQueriesProvider); + try { + final String authorities = + sa.getString(R.styleable.AndroidManifestQueriesProvider_authorities); + if (TextUtils.isEmpty(authorities)) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Authority missing from provider tag." + ); + } + StringTokenizer authoritiesTokenizer = new StringTokenizer(authorities, ";"); + while (authoritiesTokenizer.hasMoreElements()) { + pkg.addQueriesProvider(authoritiesTokenizer.nextToken()); + } + } finally { + sa.recycle(); + } + } + } + return input.success(pkg); + } + + /** + * Parse the {@code application} XML tree at the current parse location in a + * <em>base APK</em> manifest. + * <p> + * When adding new features, carefully consider if they should also be + * supported by split APKs. + * + * This method should avoid using a getter for fields set by this method. Prefer assigning + * a local variable and using it. Otherwise there's an ordering problem which can be broken + * if any code moves around. + */ + private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags) + throws XmlPullParserException, IOException { + final String pkgName = pkg.getPackageName(); + int targetSdk = pkg.getTargetSdkVersion(); + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); + try { + // TODO(b/135203078): Remove this and force unit tests to mock an empty manifest + // This case can only happen in unit tests where we sometimes need to create fakes + // of various package parser data structures. + if (sa == null) { + return input.error("<application> does not contain any attributes"); + } + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestApplication_name, + 0); + if (name != null) { + String packageName = pkg.getPackageName(); + String outInfoName = ParsingUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) { + return input.error("<application> invalid android:name"); + } else if (outInfoName == null) { + return input.error("Empty class name in package " + packageName); + } + + pkg.setClassName(outInfoName); + } + + TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label); + if (labelValue != null) { + pkg.setLabelRes(labelValue.resourceId); + if (labelValue.resourceId == 0) { + pkg.setNonLocalizedLabel(labelValue.coerceToString()); + } + } + + parseBaseAppBasicFlags(pkg, sa); + + String manageSpaceActivity = nonConfigString(Configuration.NATIVE_CONFIG_VERSION, + R.styleable.AndroidManifestApplication_manageSpaceActivity, sa); + if (manageSpaceActivity != null) { + String manageSpaceActivityName = ParsingUtils.buildClassName(pkgName, + manageSpaceActivity); + + if (manageSpaceActivityName == null) { + return input.error("Empty class name in package " + pkgName); + } + + pkg.setManageSpaceActivityName(manageSpaceActivityName); + } + + if (pkg.isAllowBackup()) { + // backupAgent, killAfterRestore, fullBackupContent, backupInForeground, + // and restoreAnyVersion are only relevant if backup is possible for the + // given application. + String backupAgent = nonConfigString(Configuration.NATIVE_CONFIG_VERSION, + R.styleable.AndroidManifestApplication_backupAgent, sa); + if (backupAgent != null) { + String backupAgentName = ParsingUtils.buildClassName(pkgName, backupAgent); + if (backupAgentName == null) { + return input.error("Empty class name in package " + pkgName); + } + + if (PackageParser.DEBUG_BACKUP) { + Slog.v(TAG, "android:backupAgent = " + backupAgentName + + " from " + pkgName + "+" + backupAgent); + } + + pkg.setBackupAgentName(backupAgentName) + .setKillAfterRestore(bool(true, + R.styleable.AndroidManifestApplication_killAfterRestore, sa)) + .setRestoreAnyVersion(bool(false, + R.styleable.AndroidManifestApplication_restoreAnyVersion, sa)) + .setFullBackupOnly(bool(false, + R.styleable.AndroidManifestApplication_fullBackupOnly, sa)) + .setBackupInForeground(bool(false, + R.styleable.AndroidManifestApplication_backupInForeground, sa)); + } + + TypedValue v = sa.peekValue( + R.styleable.AndroidManifestApplication_fullBackupContent); + int fullBackupContent = 0; + + if (v != null) { + fullBackupContent = v.resourceId; + + if (v.resourceId == 0) { + if (PackageParser.DEBUG_BACKUP) { + Slog.v(TAG, "fullBackupContent specified as boolean=" + + (v.data == 0 ? "false" : "true")); + } + // "false" => -1, "true" => 0 + fullBackupContent = v.data == 0 ? -1 : 0; + } + + pkg.setFullBackupContent(fullBackupContent); + } + if (PackageParser.DEBUG_BACKUP) { + Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName); + } + } + + if (sa.getBoolean(R.styleable.AndroidManifestApplication_persistent, false)) { + // Check if persistence is based on a feature being present + final String requiredFeature = sa.getNonResourceString(R.styleable + .AndroidManifestApplication_persistentWhenFeatureAvailable); + pkg.setPersistent(requiredFeature == null || mCallback.hasFeature(requiredFeature)); + } + + // TODO(b/135203078): Should parsing code be responsible for this? Maybe move to a + // util or just have PackageImpl return true if either flag is set + // Debuggable implies profileable + pkg.setProfileableByShell(pkg.isProfileableByShell() || pkg.isDebuggable()); + + if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) { + pkg.setResizeableActivity(sa.getBoolean( + R.styleable.AndroidManifestApplication_resizeableActivity, true)); + } else { + pkg.setResizeableActivityViaSdkVersion( + targetSdk >= Build.VERSION_CODES.N); + } + + String taskAffinity; + if (targetSdk >= Build.VERSION_CODES.FROYO) { + taskAffinity = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_taskAffinity, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + taskAffinity = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_taskAffinity); + } + + ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName( + pkgName, pkgName, taskAffinity, input); + if (taskAffinityResult.isError()) { + return input.error(taskAffinityResult); + } + + pkg.setTaskAffinity(taskAffinityResult.getResult()); + String factory = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_appComponentFactory); + if (factory != null) { + String appComponentFactory = ParsingUtils.buildClassName(pkgName, factory); + if (appComponentFactory == null) { + return input.error("Empty class name in package " + pkgName); + } + + pkg.setAppComponentFactory(appComponentFactory); + } + + CharSequence pname; + if (targetSdk >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_process); + } + ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName( + pkgName, null, pname, flags, mSeparateProcesses, input); + if (processNameResult.isError()) { + return input.error(processNameResult); + } + + String processName = processNameResult.getResult(); + pkg.setProcessName(processName); + + if (pkg.isCantSaveState()) { + // A heavy-weight application can not be in a custom process. + // We can do direct compare because we intern all strings. + if (processName != null && !processName.equals(pkgName)) { + return input.error( + "cantSaveState applications can not use custom processes"); + } + } + + String classLoaderName = pkg.getClassLoaderName(); + if (classLoaderName != null + && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { + return input.error("Invalid class loader name: " + classLoaderName); + } + } finally { + sa.recycle(); + } + + boolean hasActivityOrder = false; + boolean hasReceiverOrder = false; + boolean hasServiceOrder = false; + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + String tagName = parser.getName(); + boolean isActivity = false; + switch (tagName) { + case "activity": + isActivity = true; + // fall-through + case "receiver": + ParseResult<ParsedActivity> activityResult = + ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg, + res, parser, flags, PackageParser.sUseRoundIcon, input); + + if (activityResult.isSuccess()) { + ParsedActivity activity = activityResult.getResult(); + if (isActivity) { + hasActivityOrder |= (activity.getOrder() != 0); + pkg.addActivity(activity); + } else { + hasReceiverOrder |= (activity.getOrder() != 0); + pkg.addReceiver(activity); + } + } + + result = activityResult; + break; + case "service": + ParseResult<ParsedService> serviceResult = + ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser, + flags, PackageParser.sUseRoundIcon, input); + if (serviceResult.isSuccess()) { + ParsedService service = serviceResult.getResult(); + hasServiceOrder |= (service.getOrder() != 0); + pkg.addService(service); + } + + result = serviceResult; + break; + case "provider": + ParseResult<ParsedProvider> providerResult = + ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser, + flags, PackageParser.sUseRoundIcon, input); + if (providerResult.isSuccess()) { + pkg.addProvider(providerResult.getResult()); + } + + result = providerResult; + break; + case "activity-alias": + activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, + parser, PackageParser.sUseRoundIcon, input); + if (activityResult.isSuccess()) { + ParsedActivity activity = activityResult.getResult(); + hasActivityOrder |= (activity.getOrder() != 0); + pkg.addActivity(activity); + } + + result = activityResult; + break; + default: + result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags); + break; + } + + if (result.isError()) { + return input.error(result); + } + } + + if (TextUtils.isEmpty(pkg.getStaticSharedLibName())) { + // Add a hidden app detail activity to normal apps which forwards user to App Details + // page. + ParseResult<ParsedActivity> a = generateAppDetailsHiddenActivity(input, pkg); + // Backwards-compat, assume success + pkg.addActivity(a.getResult()); + a.ignoreError(); + } + + if (hasActivityOrder) { + pkg.sortActivities(); + } + if (hasReceiverOrder) { + pkg.sortReceivers(); + } + if (hasServiceOrder) { + pkg.sortServices(); + } + + // Must be run after the entire {@link ApplicationInfo} has been fully processed and after + // every activity info has had a chance to set it from its attributes. + setMaxAspectRatio(pkg); + setMinAspectRatio(pkg); + + pkg.setHasDomainUrls(hasDomainURLs(pkg)); + + return input.success(pkg); + } + + /** + * Collection of single-line, no (or little) logic assignments. Separated for readability. + * + * Flags are separated by type and by default value. They are sorted alphabetically within each + * section. + */ + private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) { + int targetSdk = pkg.getTargetSdkVersion(); + //@formatter:off + // CHECKSTYLE:off + pkg + // Default true + .setAllowBackup(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa)) + .setAllowClearUserData(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa)) + .setAllowClearUserDataOnFailedRestore(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa)) + .setAllowNativeHeapPointerTagging(bool(true, R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, sa)) + .setEnabled(bool(true, R.styleable.AndroidManifestApplication_enabled, sa)) + .setExtractNativeLibs(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa)) + .setHasCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa)) + // Default false + .setAllowTaskReparenting(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa)) + .setCantSaveState(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa)) + .setDebuggable(bool(false, R.styleable.AndroidManifestApplication_debuggable, sa)) + .setDefaultToDeviceProtectedStorage(bool(false, R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, sa)) + .setDirectBootAware(bool(false, R.styleable.AndroidManifestApplication_directBootAware, sa)) + .setForceQueryable(bool(false, R.styleable.AndroidManifestApplication_forceQueryable, sa)) + .setGame(bool(false, R.styleable.AndroidManifestApplication_isGame, sa)) + .setHasFragileUserData(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa)) + .setLargeHeap(bool(false, R.styleable.AndroidManifestApplication_largeHeap, sa)) + .setMultiArch(bool(false, R.styleable.AndroidManifestApplication_multiArch, sa)) + .setPreserveLegacyExternalStorage(bool(false, R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage, sa)) + .setRequiredForAllUsers(bool(false, R.styleable.AndroidManifestApplication_requiredForAllUsers, sa)) + .setSupportsRtl(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa)) + .setTestOnly(bool(false, R.styleable.AndroidManifestApplication_testOnly, sa)) + .setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa)) + .setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa)) + .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa)) + // targetSdkVersion gated + .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa)) + .setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa)) + .setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa)) + .setUsesCleartextTraffic(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa)) + // Ints Default 0 + .setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa)) + // Ints + .setCategory(anInt(ApplicationInfo.CATEGORY_UNDEFINED, R.styleable.AndroidManifestApplication_appCategory, sa)) + // Floats Default 0f + .setMaxAspectRatio(aFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, sa)) + .setMinAspectRatio(aFloat(R.styleable.AndroidManifestApplication_minAspectRatio, sa)) + // Resource ID + .setBanner(resId(R.styleable.AndroidManifestApplication_banner, sa)) + .setDescriptionRes(resId(R.styleable.AndroidManifestApplication_description, sa)) + .setIconRes(resId(R.styleable.AndroidManifestApplication_icon, sa)) + .setLogo(resId(R.styleable.AndroidManifestApplication_logo, sa)) + .setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa)) + .setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa)) + .setTheme(resId(R.styleable.AndroidManifestApplication_theme, sa)) + // Strings + .setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa)) + .setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa)) + .setRestrictedAccountType(string(R.styleable.AndroidManifestApplication_restrictedAccountType, sa)) + .setZygotePreloadName(string(R.styleable.AndroidManifestApplication_zygotePreloadName, sa)) + // Non-Config String + .setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa)); + // CHECKSTYLE:on + //@formatter:on + } + + /** + * For parsing non-MainComponents. Main ones have an order and some special handling which is + * done directly in {@link #parseBaseApplication(ParseInput, ParsingPackage, Resources, + * XmlResourceParser, int)}. + */ + private ParseResult parseBaseAppChildTag(ParseInput input, String tag, ParsingPackage pkg, + Resources res, XmlResourceParser parser, int flags) + throws IOException, XmlPullParserException { + switch (tag) { + case "meta-data": + // TODO(b/135203078): I have no idea what this comment means + // note: application meta-data is stored off to the side, so it can + // remain null in the primary copy (we like to avoid extra copies because + // it can be large) + ParseResult<Bundle> metaDataResult = parseMetaData(pkg, res, parser, + pkg.getMetaData(), input); + if (metaDataResult.isSuccess()) { + pkg.setMetaData(metaDataResult.getResult()); + } + + return metaDataResult; + case "static-library": + return parseStaticLibrary(pkg, res, parser, input); + case "library": + return parseLibrary(pkg, res, parser, input); + case "uses-static-library": + return parseUsesStaticLibrary(input, pkg, res, parser); + case "uses-library": + return parseUsesLibrary(input, pkg, res, parser); + case "processes": + return parseProcesses(input, pkg, res, parser, mSeparateProcesses, flags); + case "uses-package": + // Dependencies for app installers; we don't currently try to + // enforce this. + return input.success(null); + case "profileable": + return parseProfileable(input, pkg, res, parser); + default: + return ParsingUtils.unknownTag("<application>", pkg, parser, input); + } + } + + @NonNull + private static ParseResult<ParsingPackage> parseStaticLibrary( + ParsingPackage pkg, Resources res, + XmlResourceParser parser, ParseInput input) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestStaticLibrary); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestStaticLibrary_name); + final int version = sa.getInt( + R.styleable.AndroidManifestStaticLibrary_version, -1); + final int versionMajor = sa.getInt( + R.styleable.AndroidManifestStaticLibrary_versionMajor, + 0); + + // Since the app canot run without a static lib - fail if malformed + if (lname == null || version < 0) { + return input.error("Bad static-library declaration name: " + lname + + " version: " + version); + } else if (pkg.getSharedUserId() != null) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, + "sharedUserId not allowed in static shared library" + ); + } else if (pkg.getStaticSharedLibName() != null) { + return input.error("Multiple static-shared libs for package " + + pkg.getPackageName()); + } + + return input.success(pkg.setStaticSharedLibName(lname.intern()) + .setStaticSharedLibVersion( + PackageInfo.composeLongVersionCode(versionMajor, version)) + .setStaticSharedLibrary(true)); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult<ParsingPackage> parseLibrary( + ParsingPackage pkg, Resources res, + XmlResourceParser parser, ParseInput input) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestLibrary); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString(R.styleable.AndroidManifestLibrary_name); + + if (lname != null) { + lname = lname.intern(); + if (!ArrayUtils.contains(pkg.getLibraryNames(), lname)) { + pkg.addLibraryName(lname); + } + } + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult<ParsingPackage> parseUsesStaticLibrary(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesStaticLibrary); + try { + // Note: don't allow this value to be a reference to a resource that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesLibrary_name); + final int version = sa.getInt( + R.styleable.AndroidManifestUsesStaticLibrary_version, -1); + String certSha256Digest = sa.getNonResourceString(R.styleable + .AndroidManifestUsesStaticLibrary_certDigest); + + // Since an APK providing a static shared lib can only provide the lib - fail if + // malformed + if (lname == null || version < 0 || certSha256Digest == null) { + return input.error("Bad uses-static-library declaration name: " + lname + + " version: " + version + " certDigest" + certSha256Digest); + } + + // Can depend only on one version of the same library + List<String> usesStaticLibraries = pkg.getUsesStaticLibraries(); + if (usesStaticLibraries.contains(lname)) { + return input.error( + "Depending on multiple versions of static library " + lname); + } + + lname = lname.intern(); + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); + + // Fot apps targeting O-MR1 we require explicit enumeration of all certs. + String[] additionalCertSha256Digests = EmptyArray.STRING; + if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) { + ParseResult<String[]> certResult = parseAdditionalCertificates(input, res, parser); + if (certResult.isError()) { + return input.error(certResult); + } + additionalCertSha256Digests = certResult.getResult(); + } + + final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; + certSha256Digests[0] = certSha256Digest; + System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, + 1, additionalCertSha256Digests.length); + + return input.success(pkg.addUsesStaticLibrary(lname) + .addUsesStaticLibraryVersion(version) + .addUsesStaticLibraryCertDigests(certSha256Digests)); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult<ParsingPackage> parseUsesLibrary(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString(R.styleable.AndroidManifestUsesLibrary_name); + boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesLibrary_required, true); + + if (lname != null) { + lname = lname.intern(); + if (req) { + // Upgrade to treat as stronger constraint + pkg.addUsesLibrary(lname) + .removeUsesOptionalLibrary(lname); + } else { + // Ignore if someone already defined as required + if (!ArrayUtils.contains(pkg.getUsesLibraries(), lname)) { + pkg.addUsesOptionalLibrary(lname); + } + } + } + + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult<ParsingPackage> parseProcesses(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser, String[] separateProcesses, int flags) + throws IOException, XmlPullParserException { + ParseResult<ArrayMap<String, ParsedProcess>> result = + ParsedProcessUtils.parseProcesses(separateProcesses, pkg, res, parser, flags, + input); + if (result.isError()) { + return input.error(result); + } + + return input.success(pkg.setProcesses(result.getResult())); + } + + @NonNull + private static ParseResult<ParsingPackage> parseProfileable(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProfileable); + try { + return input.success(pkg.setProfileableByShell(pkg.isProfileableByShell() + || bool(false, R.styleable.AndroidManifestProfileable_shell, sa))); + } finally { + sa.recycle(); + } + } + + private static ParseResult<String[]> parseAdditionalCertificates(ParseInput input, + Resources resources, XmlResourceParser parser) + throws XmlPullParserException, IOException { + String[] certSha256Digests = EmptyArray.STRING; + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final String nodeName = parser.getName(); + if (nodeName.equals("additional-certificate")) { + TypedArray sa = resources.obtainAttributes(parser, + R.styleable.AndroidManifestAdditionalCertificate); + try { + String certSha256Digest = sa.getNonResourceString( + R.styleable.AndroidManifestAdditionalCertificate_certDigest); + + if (TextUtils.isEmpty(certSha256Digest)) { + return input.error("Bad additional-certificate declaration with empty" + + " certDigest:" + certSha256Digest); + } + + + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); + certSha256Digests = ArrayUtils.appendElement(String.class, + certSha256Digests, certSha256Digest); + } finally { + sa.recycle(); + } + } + } + + return input.success(certSha256Digests); + } + + /** + * Generate activity object that forwards user to App Details page automatically. + * This activity should be invisible to user and user should not know or see it. + */ + @NonNull + private static ParseResult<ParsedActivity> generateAppDetailsHiddenActivity(ParseInput input, + ParsingPackage pkg) { + String packageName = pkg.getPackageName(); + ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName( + packageName, packageName, ":app_details", input); + + String taskAffinity; + if (taskAffinityResult.isSuccess()) { + taskAffinity = taskAffinityResult.getResult(); + } else { + // Backwards-compat, do not fail + taskAffinity = null; + taskAffinityResult.ignoreError(); + } + + // Build custom App Details activity info instead of parsing it from xml + return input.success(ParsedActivity.makeAppDetailsActivity(packageName, + pkg.getProcessName(), pkg.getUiOptions(), taskAffinity, + pkg.isBaseHardwareAccelerated())); + } + + /** + * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI + */ + private static boolean hasDomainURLs(ParsingPackage pkg) { + final List<ParsedActivity> activities = pkg.getActivities(); + final int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ParsedActivity activity = activities.get(index); + List<ParsedIntentInfo> filters = activity.getIntents(); + final int filtersSize = filters.size(); + for (int filtersIndex = 0; filtersIndex < filtersSize; filtersIndex++) { + ParsedIntentInfo aii = filters.get(filtersIndex); + if (!aii.hasAction(Intent.ACTION_VIEW)) continue; + if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue; + if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || + aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { + return true; + } + } + } + return false; + } + + /** + * Sets the max aspect ratio of every child activity that doesn't already have an aspect + * ratio set. + */ + private static void setMaxAspectRatio(ParsingPackage pkg) { + // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. + // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. + float maxAspectRatio = pkg.getTargetSdkVersion() < O + ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; + + float packageMaxAspectRatio = pkg.getMaxAspectRatio(); + if (packageMaxAspectRatio != 0) { + // Use the application max aspect ration as default if set. + maxAspectRatio = packageMaxAspectRatio; + } else { + Bundle appMetaData = pkg.getMetaData(); + if (appMetaData != null && appMetaData.containsKey( + PackageParser.METADATA_MAX_ASPECT_RATIO)) { + maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, + maxAspectRatio); + } + } + + List<ParsedActivity> activities = pkg.getActivities(); + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ParsedActivity activity = activities.get(index); + // If the max aspect ratio for the activity has already been set, skip. + if (activity.getMaxAspectRatio() != null) { + continue; + } + + // By default we prefer to use a values defined on the activity directly than values + // defined on the application. We do not check the styled attributes on the activity + // as it would have already been set when we processed the activity. We wait to + // process the meta data here since this method is called at the end of processing + // the application and all meta data is guaranteed. + final float activityAspectRatio = activity.getMetaData() != null + ? activity.getMetaData().getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, + maxAspectRatio) + : maxAspectRatio; + + activity.setMaxAspectRatio(activity.getResizeMode(), activityAspectRatio); + } + } + + /** + * Sets the min aspect ratio of every child activity that doesn't already have an aspect + * ratio set. + */ + private void setMinAspectRatio(ParsingPackage pkg) { + final float minAspectRatio; + float packageMinAspectRatio = pkg.getMinAspectRatio(); + if (packageMinAspectRatio != 0) { + // Use the application max aspect ration as default if set. + minAspectRatio = packageMinAspectRatio; + } else { + // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater. + // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD, + // except for watches which always supported 1:1. + minAspectRatio = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.Q + ? 0 + : (mCallback != null && mCallback.hasFeature(FEATURE_WATCH)) + ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH + : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO; + } + + List<ParsedActivity> activities = pkg.getActivities(); + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ParsedActivity activity = activities.get(index); + if (activity.getMinAspectRatio() == null) { + activity.setMinAspectRatio(activity.getResizeMode(), minAspectRatio); + } + } + } + + private static ParseResult<ParsingPackage> parseOverlay(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay); + try { + String target = sa.getString(R.styleable.AndroidManifestResourceOverlay_targetPackage); + int priority = anInt(0, R.styleable.AndroidManifestResourceOverlay_priority, sa); + + if (target == null) { + return input.error("<overlay> does not specify a target package"); + } else if (priority < 0 || priority > 9999) { + return input.error("<overlay> priority must be between 0 and 9999"); + } + + // check to see if overlay should be excluded based on system property condition + String propName = sa.getString( + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName); + String propValue = sa.getString( + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue); + if (!checkOverlayRequiredSystemProperty(propName, propValue)) { + Slog.i(TAG, "Skipping target and overlay pair " + target + " and " + + pkg.getBaseCodePath() + + ": overlay ignored due to required system property: " + + propName + " with value: " + propValue); + return input.error("Skipping target and overlay pair " + target + " and " + + pkg.getBaseCodePath() + + ": overlay ignored due to required system property: " + + propName + " with value: " + propValue); + } + + return input.success(pkg.setOverlay(true) + .setOverlayTarget(target) + .setOverlayPriority(priority) + .setOverlayTargetName( + sa.getString(R.styleable.AndroidManifestResourceOverlay_targetName)) + .setOverlayCategory( + sa.getString(R.styleable.AndroidManifestResourceOverlay_category)) + .setOverlayIsStatic( + bool(false, R.styleable.AndroidManifestResourceOverlay_isStatic, sa))); + } finally { + sa.recycle(); + } + } + + private static ParseResult<ParsingPackage> parseProtectedBroadcast(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProtectedBroadcast); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String name = nonResString(R.styleable.AndroidManifestProtectedBroadcast_name, sa); + if (name != null) { + pkg.addProtectedBroadcast(name); + } + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + private static ParseResult<ParsingPackage> parseSupportScreens(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestSupportsScreens); + try { + int requiresSmallestWidthDp = anInt(0, + R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, sa); + int compatibleWidthLimitDp = anInt(0, + R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, sa); + int largestWidthLimitDp = anInt(0, + R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, sa); + + // This is a trick to get a boolean and still able to detect + // if a value was actually set. + return input.success(pkg + .setSupportsSmallScreens( + anInt(1, R.styleable.AndroidManifestSupportsScreens_smallScreens, sa)) + .setSupportsNormalScreens( + anInt(1, R.styleable.AndroidManifestSupportsScreens_normalScreens, sa)) + .setSupportsLargeScreens( + anInt(1, R.styleable.AndroidManifestSupportsScreens_largeScreens, sa)) + .setSupportsExtraLargeScreens( + anInt(1, R.styleable.AndroidManifestSupportsScreens_xlargeScreens, sa)) + .setResizeable( + anInt(1, R.styleable.AndroidManifestSupportsScreens_resizeable, sa)) + .setAnyDensity( + anInt(1, R.styleable.AndroidManifestSupportsScreens_anyDensity, sa)) + .setRequiresSmallestWidthDp(requiresSmallestWidthDp) + .setCompatibleWidthLimitDp(compatibleWidthLimitDp) + .setLargestWidthLimitDp(largestWidthLimitDp)); + } finally { + sa.recycle(); + } + } + + private static ParseResult<ParsingPackage> parseInstrumentation(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + ParseResult<ParsedInstrumentation> result = ParsedInstrumentationUtils.parseInstrumentation( + pkg, res, parser, PackageParser.sUseRoundIcon, input); + if (result.isError()) { + return input.error(result); + } + return input.success(pkg.addInstrumentation(result.getResult())); + } + + private static ParseResult<ParsingPackage> parseOriginalPackage(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage); + try { + String orig = sa.getNonConfigurationString( + R.styleable.AndroidManifestOriginalPackage_name, + 0); + if (!pkg.getPackageName().equals(orig)) { + if (pkg.getOriginalPackages().isEmpty()) { + pkg.setRealPackage(pkg.getPackageName()); + } + pkg.addOriginalPackage(orig); + } + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + private static ParseResult<ParsingPackage> parseAdoptPermissions(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage); + try { + String name = nonConfigString(0, R.styleable.AndroidManifestOriginalPackage_name, sa); + if (name != null) { + pkg.addAdoptPermission(name); + } + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + private static void convertNewPermissions(ParsingPackage pkg) { + final int NP = PackageParser.NEW_PERMISSIONS.length; + StringBuilder newPermsMsg = null; + for (int ip = 0; ip < NP; ip++) { + final PackageParser.NewPermissionInfo npi + = PackageParser.NEW_PERMISSIONS[ip]; + if (pkg.getTargetSdkVersion() >= npi.sdkVersion) { + break; + } + if (!pkg.getRequestedPermissions().contains(npi.name)) { + if (newPermsMsg == null) { + newPermsMsg = new StringBuilder(128); + newPermsMsg.append(pkg.getPackageName()); + newPermsMsg.append(": compat added "); + } else { + newPermsMsg.append(' '); + } + newPermsMsg.append(npi.name); + pkg.addRequestedPermission(npi.name) + .addImplicitPermission(npi.name); + } + } + if (newPermsMsg != null) { + Slog.i(TAG, newPermsMsg.toString()); + } + } + + private static void convertSplitPermissions(ParsingPackage pkg) { + List<SplitPermissionInfoParcelable> splitPermissions; + + try { + splitPermissions = ActivityThread.getPermissionManager().getSplitPermissions(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + final int listSize = splitPermissions.size(); + for (int is = 0; is < listSize; is++) { + final SplitPermissionInfoParcelable spi = splitPermissions.get(is); + List<String> requestedPermissions = pkg.getRequestedPermissions(); + if (pkg.getTargetSdkVersion() >= spi.getTargetSdk() + || !requestedPermissions.contains(spi.getSplitPermission())) { + continue; + } + final List<String> newPerms = spi.getNewPermissions(); + for (int in = 0; in < newPerms.size(); in++) { + final String perm = newPerms.get(in); + if (!requestedPermissions.contains(perm)) { + pkg.addRequestedPermission(perm) + .addImplicitPermission(perm); + } + } + } + } + + private static boolean checkOverlayRequiredSystemProperty(String propName, String propValue) { + if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) { + if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) { + // malformed condition - incomplete + Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName + + "=" + propValue + "' - require both requiredSystemPropertyName" + + " AND requiredSystemPropertyValue to be specified."); + return false; + } + // no valid condition set - so no exclusion criteria, overlay will be included. + return true; + } + + // check property value - make sure it is both set and equal to expected value + final String currValue = SystemProperties.get(propName); + return (currValue != null && currValue.equals(propValue)); + } + + /** + * This is a pre-density application which will get scaled - instead of being pixel perfect. + * This type of application is not resizable. + * + * @param pkg The package which needs to be marked as unresizable. + */ + private static void adjustPackageToBeUnresizeableAndUnpipable(ParsingPackage pkg) { + List<ParsedActivity> activities = pkg.getActivities(); + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ParsedActivity activity = activities.get(index); + activity.setResizeMode(RESIZE_MODE_UNRESIZEABLE) + .setFlags(activity.getFlags() & ~FLAG_SUPPORTS_PICTURE_IN_PICTURE); + } + } + + private static ParseResult validateName(ParseInput input, String name, boolean requireSeparator, + boolean requireFilename) { + final int N = name.length(); + boolean hasSep = false; + boolean front = true; + for (int i = 0; i < N; i++) { + final char c = name.charAt(i); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + front = false; + continue; + } + if (!front) { + if ((c >= '0' && c <= '9') || c == '_') { + continue; + } + } + if (c == '.') { + hasSep = true; + front = true; + continue; + } + return input.error("bad character '" + c + "'"); + } + if (requireFilename && !FileUtils.isValidExtFilename(name)) { + return input.error("Invalid filename"); + } + return hasSep || !requireSeparator + ? input.success(null) + : input.error("must have at least one '.' separator"); + } + + public static ParseResult<Bundle> parseMetaData(ParsingPackage pkg, Resources res, + XmlResourceParser parser, Bundle data, ParseInput input) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestMetaData); + try { + if (data == null) { + data = new Bundle(); + } + + String name = TextUtils.safeIntern( + nonConfigString(0, R.styleable.AndroidManifestMetaData_name, sa)); + if (name == null) { + return input.error("<meta-data> requires an android:name attribute"); + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestMetaData_resource); + if (v != null && v.resourceId != 0) { + //Slog.i(TAG, "Meta data ref " + name + ": " + v); + data.putInt(name, v.resourceId); + } else { + v = sa.peekValue(R.styleable.AndroidManifestMetaData_value); + //Slog.i(TAG, "Meta data " + name + ": " + v); + if (v != null) { + if (v.type == TypedValue.TYPE_STRING) { + CharSequence cs = v.coerceToString(); + data.putString(name, cs != null ? cs.toString() : null); + } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { + data.putBoolean(name, v.data != 0); + } else if (v.type >= TypedValue.TYPE_FIRST_INT + && v.type <= TypedValue.TYPE_LAST_INT) { + data.putInt(name, v.data); + } else if (v.type == TypedValue.TYPE_FLOAT) { + data.putFloat(name, v.getFloat()); + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, + "<meta-data> only supports string, integer, float, color, " + + "boolean, and resource reference types: " + + parser.getName() + " at " + + pkg.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + return input.error("<meta-data> only supports string, integer, float, " + + "color, boolean, and resource reference types"); + } + } + } else { + return input.error("<meta-data> requires an android:value " + + "or android:resource attribute"); + } + } + return input.success(data); + } finally { + sa.recycle(); + } + } + + /** + * Collect certificates from all the APKs described in the given package. Also asserts that + * all APK contents are signed correctly and consistently. + */ + public static SigningDetails collectCertificates(ParsingPackageRead pkg, boolean skipVerify) + throws PackageParserException { + SigningDetails signingDetails = SigningDetails.UNKNOWN; + + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); + try { + signingDetails = collectCertificates( + pkg.getBaseCodePath(), + skipVerify, + pkg.isStaticSharedLibrary(), + signingDetails, + pkg.getTargetSdkVersion() + ); + + String[] splitCodePaths = pkg.getSplitCodePaths(); + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + signingDetails = collectCertificates( + splitCodePaths[i], + skipVerify, + pkg.isStaticSharedLibrary(), + signingDetails, + pkg.getTargetSdkVersion() + ); + } + } + return signingDetails; + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + public static SigningDetails collectCertificates(String baseCodePath, boolean skipVerify, + boolean isStaticSharedLibrary, @NonNull SigningDetails existingSigningDetails, + int targetSdk) throws PackageParserException { + int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( + targetSdk); + if (isStaticSharedLibrary) { + // must use v2 signing scheme + minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2; + } + SigningDetails verified; + if (skipVerify) { + // systemDir APKs are already trusted, save time by not verifying + verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification( + baseCodePath, minSignatureScheme); + } else { + verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme); + } + + // Verify that entries are signed consistently with the first pkg + // we encountered. Note that for splits, certificates may have + // already been populated during an earlier parse of a base APK. + if (existingSigningDetails == SigningDetails.UNKNOWN) { + return verified; + } else { + if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) { + throw new PackageParserException( + INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, + baseCodePath + " has mismatched certificates"); + } + + return existingSigningDetails; + } + } + + /* + The following set of methods makes code easier to read by re-ordering the TypedArray methods. + + The first parameter is the default, which is the most important to understand for someone + reading through the parsing code. + + That's followed by the attribute name, which is usually irrelevant during reading because + it'll look like setSomeValue(true, R.styleable.ReallyLongParentName_SomeValueAttr... and + the "setSomeValue" part is enough to communicate what the line does. + + Last comes the TypedArray, which is by far the least important since each try-with-resources + should only have 1. + */ + + // Note there is no variant of bool without a defaultValue parameter, since explicit true/false + // is important to specify when adding an attribute. + private static boolean bool(boolean defaultValue, @StyleableRes int attribute, TypedArray sa) { + return sa.getBoolean(attribute, defaultValue); + } + + private static float aFloat(float defaultValue, @StyleableRes int attribute, TypedArray sa) { + return sa.getFloat(attribute, defaultValue); + } + + private static float aFloat(@StyleableRes int attribute, TypedArray sa) { + return sa.getFloat(attribute, 0f); + } + + private static int anInt(int defaultValue, @StyleableRes int attribute, TypedArray sa) { + return sa.getInt(attribute, defaultValue); + } + + private static int anInt(@StyleableRes int attribute, TypedArray sa) { + return sa.getInt(attribute, 0); + } + + @AnyRes + private static int resId(@StyleableRes int attribute, TypedArray sa) { + return sa.getResourceId(attribute, 0); + } + + private static String string(@StyleableRes int attribute, TypedArray sa) { + return sa.getString(attribute); + } + + private static String nonConfigString(int allowedChangingConfigs, @StyleableRes int attribute, + TypedArray sa) { + return sa.getNonConfigurationString(attribute, allowedChangingConfigs); + } + + private static String nonResString(@StyleableRes int index, TypedArray sa) { + return sa.getNonResourceString(index); + } + + /** + * Callback interface for retrieving information that may be needed while parsing + * a package. + */ + public interface Callback { + boolean hasFeature(String feature); + + ParsingPackage startParsingPackage(String packageName, String baseCodePath, String codePath, + TypedArray manifestArray, boolean isCoreApp); + } +} diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java new file mode 100644 index 000000000000..ba61de1cf950 --- /dev/null +++ b/core/java/android/content/pm/parsing/ParsingUtils.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.PackageParser; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.XmlResourceParser; +import android.util.Slog; + +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide **/ +public class ParsingUtils { + + // TODO(b/135203078): Consolidate log tags + public static final String TAG = "PackageParsing"; + + @Nullable + public static String buildClassName(String pkg, CharSequence clsSeq) { + if (clsSeq == null || clsSeq.length() <= 0) { + return null; + } + String cls = clsSeq.toString(); + char c = cls.charAt(0); + if (c == '.') { + return pkg + cls; + } + if (cls.indexOf('.') < 0) { + StringBuilder b = new StringBuilder(pkg); + b.append('.'); + b.append(cls); + return b.toString(); + } + return cls; + } + + @NonNull + public static ParseResult unknownTag(String parentTag, ParsingPackage pkg, + XmlResourceParser parser, ParseInput input) throws IOException, XmlPullParserException { + if (PackageParser.RIGID_PARSER) { + return input.error("Bad element under " + parentTag + ": " + parser.getName()); + } + Slog.w(TAG, "Unknown element under " + parentTag + ": " + + parser.getName() + " at " + pkg.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + return input.success(null); // Type doesn't matter + } +} diff --git a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java new file mode 100644 index 000000000000..c4caedcb87ff --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.AttrRes; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.PackageParser; +import android.content.pm.PackageUserState; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.ParsingUtils; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.text.TextUtils; + +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide */ +public class ComponentParseUtils { + + private static final String TAG = ParsingPackageUtils.TAG; + + public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) { + return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE) + || intentInfo.hasAction(Intent.ACTION_SEND) + || intentInfo.hasAction(Intent.ACTION_SENDTO) + || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE); + } + + static <Component extends ParsedComponent> ParseResult<Component> parseAllMetaData( + ParsingPackage pkg, Resources res, XmlResourceParser parser, String tag, + Component component, ParseInput input) throws XmlPullParserException, IOException { + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + if ("meta-data".equals(parser.getName())) { + result = ParsedComponentUtils.addMetaData(component, pkg, res, parser, input); + } else { + result = ParsingUtils.unknownTag(tag, pkg, parser, input); + } + + if (result.isError()) { + return input.error(result); + } + } + + return input.success(component); + } + + @NonNull + public static ParseResult<String> buildProcessName(@NonNull String pkg, String defProc, + CharSequence procSeq, int flags, String[] separateProcesses, ParseInput input) { + if ((flags & PackageParser.PARSE_IGNORE_PROCESSES) != 0 && !"system".contentEquals( + procSeq)) { + return input.success(defProc != null ? defProc : pkg); + } + if (separateProcesses != null) { + for (int i = separateProcesses.length - 1; i >= 0; i--) { + String sp = separateProcesses[i]; + if (sp.equals(pkg) || sp.equals(defProc) || sp.contentEquals(procSeq)) { + return input.success(pkg); + } + } + } + if (procSeq == null || procSeq.length() <= 0) { + return input.success(defProc); + } + + ParseResult<String> nameResult = ComponentParseUtils.buildCompoundName(pkg, procSeq, + "process", input); + return input.success(TextUtils.safeIntern(nameResult.getResult())); + } + + @NonNull + public static ParseResult<String> buildTaskAffinityName(String pkg, String defProc, + CharSequence procSeq, ParseInput input) { + if (procSeq == null) { + return input.success(defProc); + } + if (procSeq.length() <= 0) { + return input.success(null); + } + return buildCompoundName(pkg, procSeq, "taskAffinity", input); + } + + public static ParseResult<String> buildCompoundName(String pkg, CharSequence procSeq, + String type, ParseInput input) { + String proc = procSeq.toString(); + char c = proc.charAt(0); + if (pkg != null && c == ':') { + if (proc.length() < 2) { + return input.error("Bad " + type + " name " + proc + " in package " + pkg + + ": must be at least two characters"); + } + String subName = proc.substring(1); + String nameError = PackageParser.validateName(subName, false, false); + if (nameError != null) { + return input.error("Invalid " + type + " name " + proc + " in package " + pkg + + ": " + nameError); + } + return input.success(pkg + proc); + } + String nameError = PackageParser.validateName(proc, true, false); + if (nameError != null && !"system".equals(proc)) { + return input.error("Invalid " + type + " name " + proc + " in package " + pkg + + ": " + nameError); + } + return input.success(proc); + } + + public static int flag(int flag, @AttrRes int attribute, TypedArray typedArray) { + return typedArray.getBoolean(attribute, false) ? flag : 0; + } + + public static int flag(int flag, @AttrRes int attribute, boolean defaultValue, + TypedArray typedArray) { + return typedArray.getBoolean(attribute, defaultValue) ? flag : 0; + } + + /** + * This is not state aware. Avoid and access through PackageInfoUtils in the system server. + */ + @Nullable + public static CharSequence getNonLocalizedLabel( + ParsedComponent component) { + return component.nonLocalizedLabel; + } + + /** + * This is not state aware. Avoid and access through PackageInfoUtils in the system server. + * + * This is a method of the utility class to discourage use. + */ + public static int getIcon(ParsedComponent component) { + return component.icon; + } + + public static boolean isMatch(PackageUserState state, boolean isSystem, + boolean isPackageEnabled, ParsedMainComponent component, int flags) { + return state.isMatch(isSystem, isPackageEnabled, component.isEnabled(), + component.isDirectBootAware(), component.getName(), flags); + } + + public static boolean isEnabled(PackageUserState state, boolean isPackageEnabled, + ParsedMainComponent parsedComponent, int flags) { + return state.isEnabled(isPackageEnabled, parsedComponent.isEnabled(), + parsedComponent.getName(), flags); + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java new file mode 100644 index 000000000000..5495c225f811 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.content.pm.parsing.ParsingPackageImpl.sForString; +import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; + +import android.annotation.Nullable; +import android.app.ActivityTaskManager; +import android.content.ComponentName; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.parsing.ParsingPackageImpl; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +/** @hide **/ +public class ParsedActivity extends ParsedMainComponent { + + int theme; + int uiOptions; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String targetActivity; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String parentActivityName; + @Nullable + String taskAffinity; + int privateFlags; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String permission; + + int launchMode; + int documentLaunchMode; + int maxRecents; + int configChanges; + int softInputMode; + int persistableMode; + int lockTaskLaunchMode; + + int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + + @Nullable + private Float maxAspectRatio; + + @Nullable + private Float minAspectRatio; + + @Nullable + String requestedVrComponent; + int rotationAnimation = -1; + int colorMode; + + boolean preferMinimalPostProcessing; + + @Nullable + ActivityInfo.WindowLayout windowLayout; + + public ParsedActivity(ParsedActivity other) { + super(other); + this.theme = other.theme; + this.uiOptions = other.uiOptions; + this.targetActivity = other.targetActivity; + this.parentActivityName = other.parentActivityName; + this.taskAffinity = other.taskAffinity; + this.privateFlags = other.privateFlags; + this.permission = other.permission; + this.launchMode = other.launchMode; + this.documentLaunchMode = other.documentLaunchMode; + this.maxRecents = other.maxRecents; + this.configChanges = other.configChanges; + this.softInputMode = other.softInputMode; + this.persistableMode = other.persistableMode; + this.lockTaskLaunchMode = other.lockTaskLaunchMode; + this.screenOrientation = other.screenOrientation; + this.resizeMode = other.resizeMode; + this.maxAspectRatio = other.maxAspectRatio; + this.minAspectRatio = other.minAspectRatio; + this.requestedVrComponent = other.requestedVrComponent; + this.rotationAnimation = other.rotationAnimation; + this.colorMode = other.colorMode; + this.windowLayout = other.windowLayout; + } + + /** + * Generate activity object that forwards user to App Details page automatically. + * This activity should be invisible to user and user should not know or see it. + */ + public static ParsedActivity makeAppDetailsActivity(String packageName, String processName, + int uiOptions, String taskAffinity, boolean hardwareAccelerated) { + ParsedActivity activity = new ParsedActivity(); + activity.setPackageName(packageName); + activity.theme = android.R.style.Theme_NoDisplay; + activity.exported = true; + activity.setName(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME); + activity.setProcessName(processName); + activity.uiOptions = uiOptions; + activity.taskAffinity = taskAffinity; + activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE; + activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic(); + activity.configChanges = PackageParser.getActivityConfigChanges(0, 0); + activity.softInputMode = 0; + activity.persistableMode = ActivityInfo.PERSIST_NEVER; + activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; + activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; + activity.lockTaskLaunchMode = 0; + activity.setDirectBootAware(false); + activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; + activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT; + activity.preferMinimalPostProcessing = ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT; + if (hardwareAccelerated) { + activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_HARDWARE_ACCELERATED); + } + return activity; + } + + static ParsedActivity makeAlias(String targetActivityName, ParsedActivity target) { + ParsedActivity alias = new ParsedActivity(); + alias.setPackageName(target.getPackageName()); + alias.setTargetActivity(targetActivityName); + alias.configChanges = target.configChanges; + alias.flags = target.flags; + alias.privateFlags = target.privateFlags; + alias.icon = target.icon; + alias.logo = target.logo; + alias.banner = target.banner; + alias.labelRes = target.labelRes; + alias.nonLocalizedLabel = target.nonLocalizedLabel; + alias.launchMode = target.launchMode; + alias.lockTaskLaunchMode = target.lockTaskLaunchMode; + alias.descriptionRes = target.descriptionRes; + alias.screenOrientation = target.screenOrientation; + alias.taskAffinity = target.taskAffinity; + alias.theme = target.theme; + alias.softInputMode = target.softInputMode; + alias.uiOptions = target.uiOptions; + alias.parentActivityName = target.parentActivityName; + alias.maxRecents = target.maxRecents; + alias.windowLayout = target.windowLayout; + alias.resizeMode = target.resizeMode; + alias.maxAspectRatio = target.maxAspectRatio; + alias.minAspectRatio = target.minAspectRatio; + alias.requestedVrComponent = target.requestedVrComponent; + alias.directBootAware = target.directBootAware; + alias.setProcessName(target.getProcessName()); + return alias; + + // Not all attributes from the target ParsedActivity are copied to the alias. + // Careful when adding an attribute and determine whether or not it should be copied. +// alias.enabled = target.enabled; +// alias.exported = target.exported; +// alias.permission = target.permission; +// alias.splitName = target.splitName; +// alias.documentLaunchMode = target.documentLaunchMode; +// alias.persistableMode = target.persistableMode; +// alias.rotationAnimation = target.rotationAnimation; +// alias.colorMode = target.colorMode; +// alias.intents.addAll(target.intents); +// alias.order = target.order; +// alias.metaData = target.metaData; + } + + public ParsedActivity setMaxAspectRatio(int resizeMode, float maxAspectRatio) { + if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE + || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { + // Resizeable activities can be put in any aspect ratio. + return this; + } + + if (maxAspectRatio < 1.0f && maxAspectRatio != 0) { + // Ignore any value lesser than 1.0. + return this; + } + + this.maxAspectRatio = maxAspectRatio; + return this; + } + + public ParsedActivity setMinAspectRatio(int resizeMode, float minAspectRatio) { + if (resizeMode == RESIZE_MODE_RESIZEABLE + || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { + // Resizeable activities can be put in any aspect ratio. + return this; + } + + if (minAspectRatio < 1.0f && minAspectRatio != 0) { + // Ignore any value lesser than 1.0. + return this; + } + + this.minAspectRatio = minAspectRatio; + return this; + } + + public ParsedActivity setFlags(int flags) { + this.flags = flags; + return this; + } + + public ParsedActivity setResizeMode(int resizeMode) { + this.resizeMode = resizeMode; + return this; + } + + public ParsedActivity setTargetActivity(String targetActivity) { + this.targetActivity = TextUtils.safeIntern(targetActivity); + return this; + } + + public ParsedActivity setParentActivity(String parentActivity) { + this.parentActivityName = TextUtils.safeIntern(parentActivity); + return this; + } + + public ParsedActivity setPermission(String permission) { + // Empty string must be converted to null + this.permission = TextUtils.isEmpty(permission) ? null : permission.intern(); + return this; + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Activity{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + ComponentName.appendShortString(sb, getPackageName(), getName()); + sb.append('}'); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.theme); + dest.writeInt(this.uiOptions); + sForString.parcel(this.targetActivity, dest, flags); + sForString.parcel(this.parentActivityName, dest, flags); + dest.writeString(this.taskAffinity); + dest.writeInt(this.privateFlags); + sForString.parcel(this.permission, dest, flags); + dest.writeInt(this.launchMode); + dest.writeInt(this.documentLaunchMode); + dest.writeInt(this.maxRecents); + dest.writeInt(this.configChanges); + dest.writeInt(this.softInputMode); + dest.writeInt(this.persistableMode); + dest.writeInt(this.lockTaskLaunchMode); + dest.writeInt(this.screenOrientation); + dest.writeInt(this.resizeMode); + dest.writeValue(this.maxAspectRatio); + dest.writeValue(this.minAspectRatio); + dest.writeString(this.requestedVrComponent); + dest.writeInt(this.rotationAnimation); + dest.writeInt(this.colorMode); + dest.writeBoolean(this.preferMinimalPostProcessing); + dest.writeBundle(this.metaData); + + if (windowLayout != null) { + dest.writeBoolean(true); + dest.writeInt(windowLayout.width); + dest.writeFloat(windowLayout.widthFraction); + dest.writeInt(windowLayout.height); + dest.writeFloat(windowLayout.heightFraction); + dest.writeInt(windowLayout.gravity); + dest.writeInt(windowLayout.minWidth); + dest.writeInt(windowLayout.minHeight); + } else { + dest.writeBoolean(false); + } + } + + public ParsedActivity() { + } + + protected ParsedActivity(Parcel in) { + super(in); + this.theme = in.readInt(); + this.uiOptions = in.readInt(); + this.targetActivity = sForString.unparcel(in); + this.parentActivityName = sForString.unparcel(in); + this.taskAffinity = in.readString(); + this.privateFlags = in.readInt(); + this.permission = sForString.unparcel(in); + this.launchMode = in.readInt(); + this.documentLaunchMode = in.readInt(); + this.maxRecents = in.readInt(); + this.configChanges = in.readInt(); + this.softInputMode = in.readInt(); + this.persistableMode = in.readInt(); + this.lockTaskLaunchMode = in.readInt(); + this.screenOrientation = in.readInt(); + this.resizeMode = in.readInt(); + this.maxAspectRatio = (Float) in.readValue(Float.class.getClassLoader()); + this.minAspectRatio = (Float) in.readValue(Float.class.getClassLoader()); + this.requestedVrComponent = in.readString(); + this.rotationAnimation = in.readInt(); + this.colorMode = in.readInt(); + this.preferMinimalPostProcessing = in.readBoolean(); + this.metaData = in.readBundle(); + if (in.readBoolean()) { + windowLayout = new ActivityInfo.WindowLayout(in); + } + } + + public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() { + @Override + public ParsedActivity createFromParcel(Parcel source) { + return new ParsedActivity(source); + } + + @Override + public ParsedActivity[] newArray(int size) { + return new ParsedActivity[size]; + } + }; + + public int getTheme() { + return theme; + } + + public int getUiOptions() { + return uiOptions; + } + + @Nullable + public String getTargetActivity() { + return targetActivity; + } + + @Nullable + public String getParentActivityName() { + return parentActivityName; + } + + @Nullable + public String getTaskAffinity() { + return taskAffinity; + } + + public int getPrivateFlags() { + return privateFlags; + } + + @Nullable + public String getPermission() { + return permission; + } + + public int getLaunchMode() { + return launchMode; + } + + public int getDocumentLaunchMode() { + return documentLaunchMode; + } + + public int getMaxRecents() { + return maxRecents; + } + + public int getConfigChanges() { + return configChanges; + } + + public int getSoftInputMode() { + return softInputMode; + } + + public int getPersistableMode() { + return persistableMode; + } + + public int getLockTaskLaunchMode() { + return lockTaskLaunchMode; + } + + public int getScreenOrientation() { + return screenOrientation; + } + + public int getResizeMode() { + return resizeMode; + } + + @Nullable + public Float getMaxAspectRatio() { + return maxAspectRatio; + } + + @Nullable + public Float getMinAspectRatio() { + return minAspectRatio; + } + + @Nullable + public String getRequestedVrComponent() { + return requestedVrComponent; + } + + public int getRotationAnimation() { + return rotationAnimation; + } + + public int getColorMode() { + return colorMode; + } + + public boolean isPreferMinimalPostProcessing() { + return preferMinimalPostProcessing; + } + + @Nullable + public ActivityInfo.WindowLayout getWindowLayout() { + return windowLayout; + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java new file mode 100644 index 000000000000..555cdd0bc8cb --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + +import static android.content.pm.parsing.component.ComponentParseUtils.flag; + +import android.annotation.NonNull; +import android.app.ActivityTaskManager; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageParser; + +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.ParsingUtils; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.WindowManager; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; + +/** @hide */ +public class ParsedActivityUtils { + + private static final String TAG = ParsingPackageUtils.TAG; + + @NonNull + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public static ParseResult<ParsedActivity> parseActivityOrReceiver(String[] separateProcesses, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, + boolean useRoundIcon, ParseInput input) + throws XmlPullParserException, IOException { + final String packageName = pkg.getPackageName(); + final ParsedActivity + activity = new ParsedActivity(); + + boolean receiver = "receiver".equals(parser.getName()); + String tag = "<" + parser.getName() + ">"; + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); + try { + ParseResult<ParsedActivity> result = + ParsedMainComponentUtils.parseMainComponent( + activity, tag, separateProcesses, + pkg, sa, flags, useRoundIcon, input, + R.styleable.AndroidManifestActivity_banner, + R.styleable.AndroidManifestActivity_description, + R.styleable.AndroidManifestActivity_directBootAware, + R.styleable.AndroidManifestActivity_enabled, + R.styleable.AndroidManifestActivity_icon, + R.styleable.AndroidManifestActivity_label, + R.styleable.AndroidManifestActivity_logo, + R.styleable.AndroidManifestActivity_name, + R.styleable.AndroidManifestActivity_process, + R.styleable.AndroidManifestActivity_roundIcon, + R.styleable.AndroidManifestActivity_splitName); + if (result.isError()) { + return result; + } + + if (receiver && pkg.isCantSaveState()) { + // A heavy-weight application can not have receivers in its main process + if (Objects.equals(activity.getProcessName(), packageName)) { + return input.error("Heavy-weight applications can not have receivers " + + "in main process"); + } + } + + // The following section has formatting off to make it easier to read the flags. + // Multi-lining them to fit within the column restriction makes it hard to tell what + // field is assigned where. + // @formatter:off + activity.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0); + activity.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions()); + + activity.flags |= flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isAllowTaskReparenting(), sa) + | flag(ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE, R.styleable.AndroidManifestActivity_alwaysRetainTaskState, sa) + | flag(ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH, R.styleable.AndroidManifestActivity_clearTaskOnLaunch, sa) + | flag(ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS, R.styleable.AndroidManifestActivity_excludeFromRecents, sa) + | flag(ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS, R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, sa) + | flag(ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH, R.styleable.AndroidManifestActivity_finishOnTaskLaunch, sa) + | flag(ActivityInfo.FLAG_IMMERSIVE, R.styleable.AndroidManifestActivity_immersive, sa) + | flag(ActivityInfo.FLAG_MULTIPROCESS, R.styleable.AndroidManifestActivity_multiprocess, sa) + | flag(ActivityInfo.FLAG_NO_HISTORY, R.styleable.AndroidManifestActivity_noHistory, sa) + | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showForAllUsers, sa) + | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showOnLockScreen, sa) + | flag(ActivityInfo.FLAG_STATE_NOT_NEEDED, R.styleable.AndroidManifestActivity_stateNotNeeded, sa) + | flag(ActivityInfo.FLAG_SYSTEM_USER_ONLY, R.styleable.AndroidManifestActivity_systemUserOnly, sa); + + if (!receiver) { + activity.flags |= flag(ActivityInfo.FLAG_HARDWARE_ACCELERATED, R.styleable.AndroidManifestActivity_hardwareAccelerated, pkg.isBaseHardwareAccelerated(), sa) + | flag(ActivityInfo.FLAG_ALLOW_EMBEDDED, R.styleable.AndroidManifestActivity_allowEmbedded, sa) + | flag(ActivityInfo.FLAG_ALWAYS_FOCUSABLE, R.styleable.AndroidManifestActivity_alwaysFocusable, sa) + | flag(ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS, R.styleable.AndroidManifestActivity_autoRemoveFromRecents, sa) + | flag(ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY, R.styleable.AndroidManifestActivity_relinquishTaskIdentity, sa) + | flag(ActivityInfo.FLAG_RESUME_WHILE_PAUSING, R.styleable.AndroidManifestActivity_resumeWhilePausing, sa) + | flag(ActivityInfo.FLAG_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_showWhenLocked, sa) + | flag(ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE, R.styleable.AndroidManifestActivity_supportsPictureInPicture, sa) + | flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa); + + activity.privateFlags |= flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa); + + activity.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT); + activity.preferMinimalPostProcessing = sa.getBoolean(R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT); + activity.documentLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE); + activity.launchMode = sa.getInt(R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE); + activity.lockTaskLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0); + activity.maxRecents = sa.getInt(R.styleable.AndroidManifestActivity_maxRecents, ActivityTaskManager.getDefaultAppRecentsLimitStatic()); + activity.persistableMode = sa.getInteger(R.styleable.AndroidManifestActivity_persistableMode, ActivityInfo.PERSIST_ROOT_ONLY); + activity.requestedVrComponent = sa.getString(R.styleable.AndroidManifestActivity_enableVrMode); + activity.rotationAnimation = sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED); + activity.softInputMode = sa.getInt(R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); + + activity.configChanges = PackageParser.getActivityConfigChanges( + sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0), + sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0)); + + int screenOrientation = sa.getInt(R.styleable.AndroidManifestActivity_screenOrientation, SCREEN_ORIENTATION_UNSPECIFIED); + int resizeMode = getActivityResizeMode(pkg, sa, screenOrientation); + activity.screenOrientation = screenOrientation; + activity.resizeMode = resizeMode; + + if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio) + && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio) + == TypedValue.TYPE_FLOAT) { + activity.setMaxAspectRatio(resizeMode, + sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio, + 0 /*default*/)); + } + + if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio) + && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio) + == TypedValue.TYPE_FLOAT) { + activity.setMinAspectRatio(resizeMode, + sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio, + 0 /*default*/)); + } + } else { + activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + activity.configChanges = 0; + activity.flags |= flag(ActivityInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestActivity_singleUser, sa); + } + // @formatter:on + + String taskAffinity = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivity_taskAffinity, + Configuration.NATIVE_CONFIG_VERSION); + + ParseResult<String> affinityNameResult = ComponentParseUtils.buildTaskAffinityName( + packageName, pkg.getTaskAffinity(), taskAffinity, input); + if (affinityNameResult.isSuccess()) { + activity.taskAffinity = affinityNameResult.getResult(); + } else { + // Backwards-compat, ignore error + affinityNameResult.ignoreError(); + } + + boolean visibleToEphemeral = sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false); + if (visibleToEphemeral) { + activity.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + pkg.setVisibleToInstantApps(true); + } + + return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver, + false /*isAlias*/, visibleToEphemeral, input, + R.styleable.AndroidManifestActivity_parentActivityName, + R.styleable.AndroidManifestActivity_permission, + R.styleable.AndroidManifestActivity_exported + ); + } finally { + sa.recycle(); + } + } + + @NonNull + public static ParseResult<ParsedActivity> parseActivityAlias(ParsingPackage pkg, Resources res, + XmlResourceParser parser, boolean useRoundIcon, ParseInput input) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivityAlias); + try { + String targetActivity = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivityAlias_targetActivity, + Configuration.NATIVE_CONFIG_VERSION); + if (targetActivity == null) { + return input.error("<activity-alias> does not specify android:targetActivity"); + } + + String packageName = pkg.getPackageName(); + targetActivity = ParsingUtils.buildClassName(packageName, targetActivity); + if (targetActivity == null) { + return input.error("Empty class name in package " + packageName); + } + + ParsedActivity target = null; + + List<ParsedActivity> activities = pkg.getActivities(); + final int activitiesSize = ArrayUtils.size(activities); + for (int i = 0; i < activitiesSize; i++) { + ParsedActivity t = activities.get(i); + if (targetActivity.equals(t.getName())) { + target = t; + break; + } + } + + if (target == null) { + return input.error("<activity-alias> target activity " + targetActivity + + " not found in manifest with activities = " + + pkg.getActivities() + + ", parsedActivities = " + activities); + } + + ParsedActivity activity = ParsedActivity.makeAlias(targetActivity, target); + String tag = "<" + parser.getName() + ">"; + + ParseResult<ParsedActivity> result = ParsedMainComponentUtils.parseMainComponent( + activity, tag, null, pkg, sa, 0, useRoundIcon, input, + R.styleable.AndroidManifestActivityAlias_banner, + R.styleable.AndroidManifestActivityAlias_description, + null /*directBootAwareAttr*/, + R.styleable.AndroidManifestActivityAlias_enabled, + R.styleable.AndroidManifestActivityAlias_icon, + R.styleable.AndroidManifestActivityAlias_label, + R.styleable.AndroidManifestActivityAlias_logo, + R.styleable.AndroidManifestActivityAlias_name, + null /*processAttr*/, + R.styleable.AndroidManifestActivityAlias_roundIcon, + null /*splitNameAttr*/); + if (result.isError()) { + return result; + } + + // TODO add visibleToInstantApps attribute to activity alias + final boolean visibleToEphemeral = + ((activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0); + + return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, false /*isReceiver*/, true /*isAlias*/, + visibleToEphemeral, input, + R.styleable.AndroidManifestActivityAlias_parentActivityName, + R.styleable.AndroidManifestActivityAlias_permission, + R.styleable.AndroidManifestActivityAlias_exported); + } finally { + sa.recycle(); + } + } + + /** + * This method shares parsing logic between Activity/Receiver/alias instances, but requires + * passing in booleans for isReceiver/isAlias, since there's no indicator in the other + * parameters. + * + * They're used to filter the parsed tags and their behavior. This makes the method rather + * messy, but it's more maintainable than writing 3 separate methods for essentially the same + * type of logic. + */ + @NonNull + private static ParseResult<ParsedActivity> parseActivityOrAlias(ParsedActivity activity, + ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources, + TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral, + ParseInput input, int parentActivityNameAttr, int permissionAttr, + int exportedAttr) throws IOException, XmlPullParserException { + String parentActivityName = array.getNonConfigurationString(parentActivityNameAttr, Configuration.NATIVE_CONFIG_VERSION); + if (parentActivityName != null) { + String packageName = pkg.getPackageName(); + String parentClassName = ParsingUtils.buildClassName(packageName, parentActivityName); + if (parentClassName == null) { + Log.e(TAG, "Activity " + activity.getName() + + " specified invalid parentActivityName " + parentActivityName); + } else { + activity.setParentActivity(parentClassName); + } + } + + String permission = array.getNonConfigurationString(permissionAttr, 0); + activity.setPermission(permission != null ? permission : pkg.getPermission()); + + final boolean setExported = array.hasValue(exportedAttr); + if (setExported) { + activity.exported = array.getBoolean(exportedAttr, false); + } + + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + if (parser.getName().equals("intent-filter")) { + ParseResult<ParsedIntentInfo> intentResult = parseIntentFilter(pkg, activity, + !isReceiver, visibleToEphemeral, resources, parser, input); + if (intentResult.isSuccess()) { + ParsedIntentInfo intent = intentResult.getResult(); + if (intent != null) { + activity.order = Math.max(intent.getOrder(), activity.order); + activity.addIntent(intent); + if (PackageParser.LOG_UNSAFE_BROADCASTS && isReceiver + && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O) { + int actionCount = intent.countActions(); + for (int i = 0; i < actionCount; i++) { + final String action = intent.getAction(i); + if (action == null || !action.startsWith("android.")) { + continue; + } + + if (!PackageParser.SAFE_BROADCASTS.contains(action)) { + Slog.w(TAG, + "Broadcast " + action + " may never be delivered to " + + pkg.getPackageName() + " as requested at: " + + parser.getPositionDescription()); + } + } + } + } + } + result = intentResult; + } else if (parser.getName().equals("meta-data")) { + result = ParsedComponentUtils.addMetaData(activity, pkg, resources, parser, input); + } else if (!isReceiver && !isAlias && parser.getName().equals("preferred")) { + ParseResult<ParsedIntentInfo> intentResult = parseIntentFilter(pkg, activity, + true /*allowImplicitEphemeralVisibility*/, visibleToEphemeral, + resources, parser, input); + if (intentResult.isSuccess()) { + ParsedIntentInfo intent = intentResult.getResult(); + if (intent != null) { + pkg.addPreferredActivityFilter(activity.getClassName(), intent); + } + } + result = intentResult; + } else if (!isReceiver && !isAlias && parser.getName().equals("layout")) { + ParseResult<ActivityInfo.WindowLayout> layoutResult = parseLayout(resources, parser, + input); + if (layoutResult.isSuccess()) { + activity.windowLayout = layoutResult.getResult(); + } + result = layoutResult; + } else { + result = ParsingUtils.unknownTag(tag, pkg, parser, input); + } + + if (result.isError()) { + return input.error(result); + } + } + + if (!setExported) { + activity.exported = activity.getIntents().size() > 0; + } + + return input.success(activity); + } + + @NonNull + private static ParseResult<ParsedIntentInfo> parseIntentFilter(ParsingPackage pkg, + ParsedActivity activity, boolean allowImplicitEphemeralVisibility, + boolean visibleToEphemeral, Resources resources, XmlResourceParser parser, + ParseInput input) throws IOException, XmlPullParserException { + ParseResult<ParsedIntentInfo> result = ParsedMainComponentUtils.parseIntentFilter(activity, + pkg, resources, parser, visibleToEphemeral, true /*allowGlobs*/, + true /*allowAutoVerify*/, allowImplicitEphemeralVisibility, + true /*failOnNoActions*/, input); + if (result.isError()) { + return input.error(result); + } + + ParsedIntentInfo intent = result.getResult(); + if (intent != null) { + if (intent.isVisibleToInstantApp()) { + activity.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + if (intent.isImplicitlyVisibleToInstantApp()) { + activity.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; + } + } + + return input.success(intent); + } + + private static int getActivityResizeMode(ParsingPackage pkg, TypedArray sa, + int screenOrientation) { + Boolean resizeableActivity = pkg.getResizeableActivity(); + + if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity) + || resizeableActivity != null) { + // Activity or app explicitly set if it is resizeable or not; + if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, + resizeableActivity != null && resizeableActivity)) { + return ActivityInfo.RESIZE_MODE_RESIZEABLE; + } else { + return ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + } + } + + if (pkg.isResizeableActivityViaSdkVersion()) { + // The activity or app didn't explicitly set the resizing option, however we want to + // make it resize due to the sdk version it is targeting. + return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; + } + + // resize preference isn't set and target sdk version doesn't support resizing apps by + // default. For the app to be resizeable if it isn't fixed orientation or immersive. + if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; + } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; + } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; + } else { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; + } + } + + @NonNull + private static ParseResult<ActivityInfo.WindowLayout> parseLayout(Resources res, + AttributeSet attrs, ParseInput input) { + TypedArray sw = res.obtainAttributes(attrs, R.styleable.AndroidManifestLayout); + try { + int width = -1; + float widthFraction = -1f; + int height = -1; + float heightFraction = -1f; + final int widthType = sw.getType(R.styleable.AndroidManifestLayout_defaultWidth); + if (widthType == TypedValue.TYPE_FRACTION) { + widthFraction = sw.getFraction(R.styleable.AndroidManifestLayout_defaultWidth, 1, 1, + -1); + } else if (widthType == TypedValue.TYPE_DIMENSION) { + width = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_defaultWidth, + -1); + } + final int heightType = sw.getType(R.styleable.AndroidManifestLayout_defaultHeight); + if (heightType == TypedValue.TYPE_FRACTION) { + heightFraction = sw.getFraction(R.styleable.AndroidManifestLayout_defaultHeight, 1, + 1, -1); + } else if (heightType == TypedValue.TYPE_DIMENSION) { + height = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_defaultHeight, + -1); + } + int gravity = sw.getInt(R.styleable.AndroidManifestLayout_gravity, Gravity.CENTER); + int minWidth = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minWidth, -1); + int minHeight = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minHeight, + -1); + return input.success(new ActivityInfo.WindowLayout(width, widthFraction, height, + heightFraction, gravity, minWidth, minHeight)); + } finally { + sw.recycle(); + } + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedComponent.java b/core/java/android/content/pm/parsing/component/ParsedComponent.java new file mode 100644 index 000000000000..098d6204b021 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedComponent.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.parsing.ParsingPackageImpl.sForString; + +import android.annotation.CallSuper; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** @hide */ +public abstract class ParsedComponent implements Parcelable { + + private static ParsedIntentInfo.ListParceler sForIntentInfos = Parcelling.Cache.getOrCreate( + ParsedIntentInfo.ListParceler.class); + + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + private String name; + int icon; + int labelRes; + @Nullable + CharSequence nonLocalizedLabel; + int logo; + int banner; + int descriptionRes; + + // TODO(b/135203078): Replace flags with individual booleans, scoped by subclass + int flags; + + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + private String packageName; + + @Nullable + @DataClass.PluralOf("intent") + @DataClass.ParcelWith(ParsedIntentInfo.ListParceler.class) + private List<ParsedIntentInfo> intents; + + private ComponentName componentName; + + @Nullable + protected Bundle metaData; + + ParsedComponent() { + + } + + @SuppressWarnings("IncompleteCopyConstructor") + public ParsedComponent(ParsedComponent other) { + this.metaData = other.metaData; + this.name = other.name; + this.icon = other.getIcon(); + this.labelRes = other.getLabelRes(); + this.nonLocalizedLabel = other.getNonLocalizedLabel(); + this.logo = other.getLogo(); + this.banner = other.getBanner(); + + this.descriptionRes = other.getDescriptionRes(); + + this.flags = other.getFlags(); + + this.setPackageName(other.packageName); + this.intents = new ArrayList<>(other.getIntents()); + } + + public void addIntent(ParsedIntentInfo intent) { + this.intents = CollectionUtils.add(this.intents, intent); + } + + @NonNull + public List<ParsedIntentInfo> getIntents() { + return intents != null ? intents : Collections.emptyList(); + } + + public ParsedComponent setName(String name) { + this.name = TextUtils.safeIntern(name); + return this; + } + + @CallSuper + public void setPackageName(@NonNull String packageName) { + this.packageName = TextUtils.safeIntern(packageName); + //noinspection ConstantConditions + this.componentName = null; + + // Note: this method does not edit name (which can point to a class), because this package + // name change is not changing the package in code, but the identifier used by the system. + } + + @NonNull + public ComponentName getComponentName() { + if (componentName == null) { + componentName = new ComponentName(getPackageName(), getName()); + } + return componentName; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + sForString.parcel(this.name, dest, flags); + dest.writeInt(this.getIcon()); + dest.writeInt(this.getLabelRes()); + dest.writeCharSequence(this.getNonLocalizedLabel()); + dest.writeInt(this.getLogo()); + dest.writeInt(this.getBanner()); + dest.writeInt(this.getDescriptionRes()); + dest.writeInt(this.getFlags()); + sForString.parcel(this.packageName, dest, flags); + sForIntentInfos.parcel(this.getIntents(), dest, flags); + dest.writeBundle(this.metaData); + } + + protected ParsedComponent(Parcel in) { + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + //noinspection ConstantConditions + this.name = sForString.unparcel(in); + this.icon = in.readInt(); + this.labelRes = in.readInt(); + this.nonLocalizedLabel = in.readCharSequence(); + this.logo = in.readInt(); + this.banner = in.readInt(); + this.descriptionRes = in.readInt(); + this.flags = in.readInt(); + //noinspection ConstantConditions + this.packageName = sForString.unparcel(in); + this.intents = sForIntentInfos.unparcel(in); + this.metaData = in.readBundle(boot); + } + + @NonNull + public String getName() { + return name; + } + + public int getIcon() { + return icon; + } + + public int getLabelRes() { + return labelRes; + } + + @Nullable + public CharSequence getNonLocalizedLabel() { + return nonLocalizedLabel; + } + + public int getLogo() { + return logo; + } + + public int getBanner() { + return banner; + } + + public int getDescriptionRes() { + return descriptionRes; + } + + public int getFlags() { + return flags; + } + + @NonNull + public String getPackageName() { + return packageName; + } + + @Nullable + public Bundle getMetaData() { + return metaData; + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java new file mode 100644 index 000000000000..b37b61757053 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.PackageManager; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.ParsingUtils; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.TypedValue; + +import com.android.internal.annotations.VisibleForTesting; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; + +/** @hide */ +class ParsedComponentUtils { + + private static final String TAG = ParsingPackageUtils.TAG; + + @NonNull + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + static <Component extends ParsedComponent> ParseResult<Component> parseComponent( + Component component, String tag, ParsingPackage pkg, TypedArray array, + boolean useRoundIcon, ParseInput input, int bannerAttr, + @Nullable Integer descriptionAttr, int iconAttr, int labelAttr, int logoAttr, + int nameAttr, int roundIconAttr) { + String name = array.getNonConfigurationString(nameAttr, 0); + if (TextUtils.isEmpty(name)) { + return input.error(tag + " does not specify android:name"); + } + + String packageName = pkg.getPackageName(); + String className = ParsingUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + return input.error(tag + " invalid android:name"); + } + + //noinspection ConstantConditions; null check done above with isEmpty + component.setName(className); + component.setPackageName(packageName); + + if (useRoundIcon) { + component.icon = array.getResourceId(roundIconAttr, 0); + } + + if (component.icon == 0) { + component.icon = array.getResourceId(iconAttr, 0); + } + + component.logo = array.getResourceId(logoAttr, 0); + component.banner = array.getResourceId(bannerAttr, 0); + + if (descriptionAttr != null) { + component.descriptionRes = array.getResourceId(descriptionAttr, 0); + } + + TypedValue v = array.peekValue(labelAttr); + if (v != null) { + component.labelRes = v.resourceId; + if (v.resourceId == 0) { + component.nonLocalizedLabel = v.coerceToString(); + } + } + + return input.success(component); + } + + static ParseResult<Bundle> addMetaData(ParsedComponent component, ParsingPackage pkg, + Resources resources, XmlResourceParser parser, ParseInput input) { + ParseResult<Bundle> result = ParsingPackageUtils.parseMetaData(pkg, resources, + parser, component.metaData, input); + if (result.isError()) { + return input.error(result); + } + Bundle bundle = result.getResult(); + component.metaData = bundle; + return input.success(bundle); + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedFeature.java b/core/java/android/content/pm/parsing/component/ParsedFeature.java new file mode 100644 index 000000000000..b8a9098cfa0e --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedFeature.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.StringRes; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArraySet; + +import com.android.internal.util.DataClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * A {@link android.R.styleable#AndroidManifestFeature <feature>} tag parsed from the + * manifest. + * + * @hide + */ +@DataClass(genAidl = false) +public class ParsedFeature implements Parcelable { + /** Maximum length of featureId */ + public static final int MAX_FEATURE_ID_LEN = 50; + + /** Maximum amount of features per package */ + private static final int MAX_NUM_FEATURES = 1000; + + /** Id of the feature */ + public final @NonNull String id; + + /** User visible label fo the feature */ + public final @StringRes int label; + + /** Ids of previously declared features this feature inherits from */ + public final @NonNull List<String> inheritFrom; + + /** + * @return Is this set of features a valid combination for a single package? + */ + public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) { + if (features == null) { + return true; + } + + ArraySet<String> featureIds = new ArraySet<>(features.size()); + ArraySet<String> inheritFromFeatureIds = new ArraySet<>(); + + int numFeatures = features.size(); + if (numFeatures > MAX_NUM_FEATURES) { + return false; + } + + for (int featureNum = 0; featureNum < numFeatures; featureNum++) { + boolean wasAdded = featureIds.add(features.get(featureNum).id); + if (!wasAdded) { + // feature id is not unique + return false; + } + } + + for (int featureNum = 0; featureNum < numFeatures; featureNum++) { + ParsedFeature feature = features.get(featureNum); + + int numInheritFrom = feature.inheritFrom.size(); + for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) { + String inheritFrom = feature.inheritFrom.get(inheritFromNum); + + if (featureIds.contains(inheritFrom)) { + // Cannot inherit from a feature that is still defined + return false; + } + + boolean wasAdded = inheritFromFeatureIds.add(inheritFrom); + if (!wasAdded) { + // inheritFrom is not unique + return false; + } + } + } + + return true; + } + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedFeature.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @android.annotation.IntDef(prefix = "MAX_", value = { + MAX_FEATURE_ID_LEN, + MAX_NUM_FEATURES + }) + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) + @DataClass.Generated.Member + public @interface Max {} + + @DataClass.Generated.Member + public static String maxToString(@Max int value) { + switch (value) { + case MAX_FEATURE_ID_LEN: + return "MAX_FEATURE_ID_LEN"; + case MAX_NUM_FEATURES: + return "MAX_NUM_FEATURES"; + default: return Integer.toHexString(value); + } + } + + /** + * Creates a new ParsedFeature. + * + * @param id + * Id of the feature + * @param label + * User visible label fo the feature + * @param inheritFrom + * Ids of previously declared features this feature inherits from + */ + @DataClass.Generated.Member + public ParsedFeature( + @NonNull String id, + @StringRes int label, + @NonNull List<String> inheritFrom) { + this.id = id; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, id); + this.label = label; + com.android.internal.util.AnnotationValidations.validate( + StringRes.class, null, label); + this.inheritFrom = inheritFrom; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, inheritFrom); + + // onConstructed(); // You can define this method to get a callback + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeString(id); + dest.writeInt(label); + dest.writeStringList(inheritFrom); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected ParsedFeature(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + String _id = in.readString(); + int _label = in.readInt(); + List<String> _inheritFrom = new ArrayList<>(); + in.readStringList(_inheritFrom); + + this.id = _id; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, id); + this.label = _label; + com.android.internal.util.AnnotationValidations.validate( + StringRes.class, null, label); + this.inheritFrom = _inheritFrom; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, inheritFrom); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR + = new Parcelable.Creator<ParsedFeature>() { + @Override + public ParsedFeature[] newArray(int size) { + return new ParsedFeature[size]; + } + + @Override + public ParsedFeature createFromParcel(@NonNull Parcel in) { + return new ParsedFeature(in); + } + }; + + @DataClass.Generated( + time = 1581379861853L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedFeature.java", + inputSignatures = "public static final int MAX_FEATURE_ID_LEN\nprivate static final int MAX_NUM_FEATURES\npublic final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java b/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java new file mode 100644 index 000000000000..fb5280175d1a --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.NonNull; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; + +import com.android.internal.R; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** @hide */ +public class ParsedFeatureUtils { + + @NonNull + public static ParseResult<ParsedFeature> parseFeature(Resources res, XmlResourceParser parser, + ParseInput input) throws IOException, XmlPullParserException { + String featureId; + int label; + List<String> inheritFrom = null; + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature); + if (sa == null) { + return input.error("<feature> could not be parsed"); + } + + try { + featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId, + 0); + if (featureId == null) { + return input.error("<featureId> does not specify android:featureId"); + } + if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) { + return input.error("<featureId> is too long. Max length is " + + ParsedFeature.MAX_FEATURE_ID_LEN); + } + + label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0); + if (label == Resources.ID_NULL) { + return input.error("<featureId> does not specify android:label"); + } + } finally { + sa.recycle(); + } + + int type; + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("inherit-from")) { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom); + if (sa == null) { + return input.error("<inherit-from> could not be parsed"); + } + + try { + String inheritFromId = sa.getNonConfigurationString( + R.styleable.AndroidManifestFeatureInheritFrom_featureId,0); + + if (inheritFrom == null) { + inheritFrom = new ArrayList<>(); + } + inheritFrom.add(inheritFromId); + } finally { + sa.recycle(); + } + } else { + return input.error("Bad element under <feature>: " + tagName); + } + } + + if (inheritFrom == null) { + inheritFrom = Collections.emptyList(); + } else { + ((ArrayList) inheritFrom).trimToSize(); + } + + return input.success(new ParsedFeature(featureId, label, inheritFrom)); + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java new file mode 100644 index 000000000000..396a145311f2 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.parsing.ParsingPackageImpl.sForString; + +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +/** @hide */ +public class ParsedInstrumentation extends ParsedComponent { + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String targetPackage; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String targetProcesses; + boolean handleProfiling; + boolean functionalTest; + + public ParsedInstrumentation() { + } + + public void setTargetPackage(@Nullable String targetPackage) { + this.targetPackage = TextUtils.safeIntern(targetPackage); + } + + public void setTargetProcesses(@Nullable String targetProcesses) { + this.targetProcesses = TextUtils.safeIntern(targetProcesses); + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Instrumentation{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + ComponentName.appendShortString(sb, getPackageName(), getName()); + sb.append('}'); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + sForString.parcel(this.targetPackage, dest, flags); + sForString.parcel(this.targetProcesses, dest, flags); + dest.writeBoolean(this.handleProfiling); + dest.writeBoolean(this.functionalTest); + } + + protected ParsedInstrumentation(Parcel in) { + super(in); + this.targetPackage = sForString.unparcel(in); + this.targetProcesses = sForString.unparcel(in); + this.handleProfiling = in.readByte() != 0; + this.functionalTest = in.readByte() != 0; + } + + public static final Parcelable.Creator<ParsedInstrumentation> CREATOR = + new Parcelable.Creator<ParsedInstrumentation>() { + @Override + public ParsedInstrumentation createFromParcel(Parcel source) { + return new ParsedInstrumentation(source); + } + + @Override + public ParsedInstrumentation[] newArray(int size) { + return new ParsedInstrumentation[size]; + } + }; + + @Nullable + public String getTargetPackage() { + return targetPackage; + } + + @Nullable + public String getTargetProcesses() { + return targetProcesses; + } + + public boolean isHandleProfiling() { + return handleProfiling; + } + + public boolean isFunctionalTest() { + return functionalTest; + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java b/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java new file mode 100644 index 000000000000..89645fc3e9c9 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.NonNull; +import android.content.pm.parsing.ParsingPackage; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; + +import com.android.internal.R; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide */ +public class ParsedInstrumentationUtils { + + @NonNull + public static ParseResult<ParsedInstrumentation> parseInstrumentation(ParsingPackage pkg, + Resources res, XmlResourceParser parser, boolean useRoundIcon, + ParseInput input) throws IOException, XmlPullParserException { + ParsedInstrumentation + instrumentation = new ParsedInstrumentation(); + String tag = "<" + parser.getName() + ">"; + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation); + try { + ParseResult<ParsedInstrumentation> result = ParsedComponentUtils.parseComponent( + instrumentation, tag, pkg, sa, useRoundIcon, input, + R.styleable.AndroidManifestInstrumentation_banner, + null /*descriptionAttr*/, + R.styleable.AndroidManifestInstrumentation_icon, + R.styleable.AndroidManifestInstrumentation_label, + R.styleable.AndroidManifestInstrumentation_logo, + R.styleable.AndroidManifestInstrumentation_name, + R.styleable.AndroidManifestInstrumentation_roundIcon); + if (result.isError()) { + return result; + } + + // @formatter:off + // Note: don't allow this value to be a reference to a resource + // that may change. + instrumentation.setTargetPackage(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage)); + instrumentation.setTargetProcesses(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetProcesses)); + instrumentation.handleProfiling = sa.getBoolean(R.styleable.AndroidManifestInstrumentation_handleProfiling, false); + instrumentation.functionalTest = sa.getBoolean(R.styleable.AndroidManifestInstrumentation_functionalTest, false); + // @formatter:on + } finally { + sa.recycle(); + } + + return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, instrumentation, + input); + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java new file mode 100644 index 000000000000..0ba92cc4fef7 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.Nullable; +import android.content.IntentFilter; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Pair; + +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; + +import java.util.ArrayList; +import java.util.List; + +/** @hide **/ +public final class ParsedIntentInfo extends IntentFilter { + + public static final Parceler PARCELER = new Parceler(); + + public static class Parceler implements Parcelling<ParsedIntentInfo> { + + @Override + public void parcel(ParsedIntentInfo item, Parcel dest, int parcelFlags) { + item.writeIntentInfoToParcel(dest, parcelFlags); + } + + @Override + public ParsedIntentInfo unparcel(Parcel source) { + return new ParsedIntentInfo(source); + } + } + + public static class ListParceler implements Parcelling<List<ParsedIntentInfo>> { + + /** + * <p> + * Implementation note: The serialized form for the intent list also contains the name + * of the concrete class that's stored in the list, and assumes that every element of the + * list is of the same type. This is very similar to the original parcelable mechanism. + * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable + * and is public API. It also declares Parcelable related methods as final which means + * we can't extend them. The approach of using composition instead of inheritance leads to + * a large set of cascading changes in the PackageManagerService, which seem undesirable. + * + * <p> + * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up + * to make sure their owner fields are consistent. See {@code fixupOwner}. + */ + @Override + public void parcel(List<ParsedIntentInfo> item, Parcel dest, int parcelFlags) { + if (item == null) { + dest.writeInt(-1); + return; + } + + final int size = item.size(); + dest.writeInt(size); + + for (int index = 0; index < size; index++) { + PARCELER.parcel(item.get(index), dest, parcelFlags); + } + } + + @Override + public List<ParsedIntentInfo> unparcel(Parcel source) { + int size = source.readInt(); + if (size == -1) { + return null; + } + + if (size == 0) { + return new ArrayList<>(0); + } + + final ArrayList<ParsedIntentInfo> intentsList = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + intentsList.add(PARCELER.unparcel(source)); + } + + return intentsList; + } + } + + public static class StringPairListParceler implements Parcelling<List<Pair<String, ParsedIntentInfo>>> { + + @Override + public void parcel(List<Pair<String, ParsedIntentInfo>> item, Parcel dest, + int parcelFlags) { + if (item == null) { + dest.writeInt(-1); + return; + } + + final int size = item.size(); + dest.writeInt(size); + + for (int index = 0; index < size; index++) { + Pair<String, ParsedIntentInfo> pair = item.get(index); + dest.writeString(pair.first); + PARCELER.parcel(pair.second, dest, parcelFlags); + } + } + + @Override + public List<Pair<String, ParsedIntentInfo>> unparcel(Parcel source) { + int size = source.readInt(); + if (size == -1) { + return null; + } + + if (size == 0) { + return new ArrayList<>(0); + } + + final List<Pair<String, ParsedIntentInfo>> list = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + list.add(Pair.create(source.readString(), PARCELER.unparcel(source))); + } + + return list; + } + } + + boolean hasDefault; + int labelRes; + @Nullable + CharSequence nonLocalizedLabel; + int icon; + + public ParsedIntentInfo() { + } + + public ParsedIntentInfo(Parcel in) { + super(in); + hasDefault = in.readBoolean(); + labelRes = in.readInt(); + nonLocalizedLabel = in.readCharSequence(); + icon = in.readInt(); + } + + public void writeIntentInfoToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeBoolean(hasDefault); + dest.writeInt(labelRes); + dest.writeCharSequence(nonLocalizedLabel); + dest.writeInt(icon); + } + + public String toString() { + return "ProviderIntentInfo{" + + Integer.toHexString(System.identityHashCode(this)) + + '}'; + } + + public static final Parcelable.Creator<ParsedIntentInfo> CREATOR = + new Parcelable.Creator<ParsedIntentInfo>() { + @Override + public ParsedIntentInfo createFromParcel(Parcel source) { + return new ParsedIntentInfo(source); + } + + @Override + public ParsedIntentInfo[] newArray(int size) { + return new ParsedIntentInfo[size]; + } + }; + + public boolean isHasDefault() { + return hasDefault; + } + + public int getLabelRes() { + return labelRes; + } + + @Nullable + public CharSequence getNonLocalizedLabel() { + return nonLocalizedLabel; + } + + public int getIcon() { + return icon; + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java new file mode 100644 index 000000000000..a7b950b194d2 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.NonNull; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageParser; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.ParsingUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.PatternMatcher; +import android.text.TextUtils; +import android.util.Slog; +import android.util.TypedValue; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Iterator; + +/** @hide */ +public class ParsedIntentInfoUtils { + + private static final String TAG = ParsingPackageUtils.TAG; + + @NonNull + public static ParseResult<ParsedIntentInfo> parseIntentInfo(String className, + ParsingPackage pkg, Resources res, XmlResourceParser parser, boolean allowGlobs, + boolean allowAutoVerify, ParseInput input) + throws XmlPullParserException, IOException { + ParsedIntentInfo intentInfo = new ParsedIntentInfo(); + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestIntentFilter); + try { + intentInfo.setPriority(sa.getInt(R.styleable.AndroidManifestIntentFilter_priority, 0)); + intentInfo.setOrder(sa.getInt(R.styleable.AndroidManifestIntentFilter_order, 0)); + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestIntentFilter_label); + if (v != null) { + intentInfo.labelRes = v.resourceId; + if (v.resourceId == 0) { + intentInfo.nonLocalizedLabel = v.coerceToString(); + } + } + + if (PackageParser.sUseRoundIcon) { + intentInfo.icon = sa.getResourceId( + R.styleable.AndroidManifestIntentFilter_roundIcon, 0); + } + + if (intentInfo.icon == 0) { + intentInfo.icon = sa.getResourceId(R.styleable.AndroidManifestIntentFilter_icon, 0); + } + + if (allowAutoVerify) { + intentInfo.setAutoVerify(sa.getBoolean( + R.styleable.AndroidManifestIntentFilter_autoVerify, + false)); + } + } finally { + sa.recycle(); + } + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + String nodeName = parser.getName(); + switch (nodeName) { + case "action": { + String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES, + "name"); + if (TextUtils.isEmpty(value)) { + result = input.error("No value supplied for <android:name>"); + } else { + intentInfo.addAction(value); + result = input.success(null); + } + break; + } + case "category": { + String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES, + "name"); + if (TextUtils.isEmpty(value)) { + result = input.error("No value supplied for <android:name>"); + } else { + intentInfo.addCategory(value); + result = input.success(null); + } + break; + } + case "data": + result = parseData(intentInfo, res, parser, allowGlobs, input); + break; + default: + result = ParsingUtils.unknownTag("<intent-filter>", pkg, parser, input); + break; + } + + if (result.isError()) { + return input.error(result); + } + } + + intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT); + + if (PackageParser.DEBUG_PARSER) { + final StringBuilder cats = new StringBuilder("Intent d="); + cats.append(intentInfo.isHasDefault()); + cats.append(", cat="); + + final Iterator<String> it = intentInfo.categoriesIterator(); + if (it != null) { + while (it.hasNext()) { + cats.append(' '); + cats.append(it.next()); + } + } + Slog.d(TAG, cats.toString()); + } + + return input.success(intentInfo); + } + + @NonNull + private static ParseResult<ParsedIntentInfo> parseData(ParsedIntentInfo intentInfo, + Resources resources, XmlResourceParser parser, boolean allowGlobs, ParseInput input) { + TypedArray sa = resources.obtainAttributes(parser, R.styleable.AndroidManifestData); + try { + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_mimeType, 0); + if (str != null) { + try { + intentInfo.addDataType(str); + } catch (IntentFilter.MalformedMimeTypeException e) { + return input.error(e.toString()); + } + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_mimeGroup, 0); + if (str != null) { + intentInfo.addMimeGroup(str); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_scheme, 0); + if (str != null) { + intentInfo.addDataScheme(str); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_ssp, 0); + if (str != null) { + intentInfo.addDataSchemeSpecificPart(str, + PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspPrefix, 0); + if (str != null) { + intentInfo.addDataSchemeSpecificPart(str, + PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspPattern, 0); + if (str != null) { + if (!allowGlobs) { + return input.error( + "sspPattern not allowed here; ssp must be literal"); + } + intentInfo.addDataSchemeSpecificPart(str, + PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + String host = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_host, 0); + String port = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_port, 0); + if (host != null) { + intentInfo.addDataAuthority(host, port); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_path, 0); + if (str != null) { + intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathPrefix, 0); + if (str != null) { + intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathPattern, 0); + if (str != null) { + if (!allowGlobs) { + return input.error( + "pathPattern not allowed here; path must be literal"); + } + intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathAdvancedPattern, 0); + if (str != null) { + if (!allowGlobs) { + return input.error( + "pathAdvancedPattern not allowed here; path must be literal"); + } + intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB); + } + + return input.success(null); + } finally { + sa.recycle(); + } + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java new file mode 100644 index 000000000000..59e9a84e3ceb --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.parsing.ParsingPackageImpl.sForString; + +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +/** @hide */ +public class ParsedMainComponent extends ParsedComponent { + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String processName; + boolean directBootAware; + boolean enabled = true; + boolean exported; + int order; + + @Nullable + String splitName; + + public ParsedMainComponent() { + } + + public ParsedMainComponent(ParsedMainComponent other) { + super(other); + this.processName = other.processName; + this.directBootAware = other.directBootAware; + this.enabled = other.enabled; + this.exported = other.exported; + this.order = other.order; + this.splitName = other.splitName; + } + + public ParsedMainComponent setProcessName(String processName) { + this.processName = TextUtils.safeIntern(processName); + return this; + } + + public ParsedMainComponent setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * A main component's name is a class name. This makes code slightly more readable. + */ + public String getClassName() { + return getName(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + sForString.parcel(this.processName, dest, flags); + dest.writeBoolean(this.directBootAware); + dest.writeBoolean(this.enabled); + dest.writeBoolean(this.exported); + dest.writeInt(this.order); + dest.writeString(this.splitName); + } + + protected ParsedMainComponent(Parcel in) { + super(in); + this.processName = sForString.unparcel(in); + this.directBootAware = in.readBoolean(); + this.enabled = in.readBoolean(); + this.exported = in.readBoolean(); + this.order = in.readInt(); + this.splitName = in.readString(); + } + + public static final Parcelable.Creator<ParsedMainComponent> CREATOR = + new Parcelable.Creator<ParsedMainComponent>() { + @Override + public ParsedMainComponent createFromParcel(Parcel source) { + return new ParsedMainComponent(source); + } + + @Override + public ParsedMainComponent[] newArray(int size) { + return new ParsedMainComponent[size]; + } + }; + + @Nullable + public String getProcessName() { + return processName; + } + + public boolean isDirectBootAware() { + return directBootAware; + } + + public boolean isEnabled() { + return enabled; + } + + public boolean isExported() { + return exported; + } + + public int getOrder() { + return order; + } + + @Nullable + public String getSplitName() { + return splitName; + } + + public ParsedMainComponent setDirectBootAware(boolean value) { + directBootAware = value; + return this; + } + + public ParsedMainComponent setExported(boolean value) { + exported = value; + return this; + } + + public ParsedMainComponent setSplitName(@Nullable String value) { + splitName = value; + return this; + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java new file mode 100644 index 000000000000..6188f8933ab2 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.IntentFilter; +import android.content.pm.parsing.ParsingPackage; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide */ +class ParsedMainComponentUtils { + + private static final String TAG = ParsingPackageUtils.TAG; + + @NonNull + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + static <Component extends ParsedMainComponent> ParseResult<Component> parseMainComponent( + Component component, String tag, String[] separateProcesses, ParsingPackage pkg, + TypedArray array, int flags, boolean useRoundIcon, ParseInput input, + int bannerAttr, int descriptionAttr, @Nullable Integer directBootAwareAttr, + @Nullable Integer enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr, + @Nullable Integer processAttr, int roundIconAttr, @Nullable Integer splitNameAttr) { + ParseResult<Component> result = ParsedComponentUtils.parseComponent(component, tag, pkg, + array, useRoundIcon, input, bannerAttr, descriptionAttr, iconAttr, labelAttr, + logoAttr, nameAttr, roundIconAttr); + if (result.isError()) { + return result; + } + + if (directBootAwareAttr != null) { + component.directBootAware = array.getBoolean(directBootAwareAttr, false); + if (component.isDirectBootAware()) { + pkg.setPartiallyDirectBootAware(true); + } + } + + if (enabledAttr != null) { + component.enabled = array.getBoolean(enabledAttr, true); + } + + if (processAttr != null) { + CharSequence processName; + if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + processName = array.getNonConfigurationString(processAttr, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + processName = array.getNonResourceString(processAttr); + } + + // Backwards-compat, ignore error + ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName( + pkg.getPackageName(), pkg.getProcessName(), processName, flags, + separateProcesses, input); + if (processNameResult.isSuccess()) { + component.setProcessName(processNameResult.getResult()); + } else { + // Backwards-compat, ignore error + processNameResult.ignoreError(); + } + } + + if (splitNameAttr != null) { + component.splitName = array.getNonConfigurationString(splitNameAttr, 0); + } + + return input.success(component); + } + + static ParseResult<ParsedIntentInfo> parseIntentFilter( + ParsedMainComponent mainComponent, + ParsingPackage pkg, Resources resources, XmlResourceParser parser, + boolean visibleToEphemeral, boolean allowGlobs, boolean allowAutoVerify, + boolean allowImplicitEphemeralVisibility, boolean failOnNoActions, + ParseInput input) throws IOException, XmlPullParserException { + ParseResult<ParsedIntentInfo> intentResult = ParsedIntentInfoUtils.parseIntentInfo( + mainComponent.getName(), pkg, resources, parser, allowGlobs, + allowAutoVerify, input); + if (intentResult.isError()) { + return input.error(intentResult); + } + + ParsedIntentInfo intent = intentResult.getResult(); + int actionCount = intent.countActions(); + if (actionCount == 0 && failOnNoActions) { + Slog.w(TAG, "No actions in " + parser.getName() + " at " + pkg.getBaseCodePath() + " " + + parser.getPositionDescription()); + // Backward-compat, do not actually fail + return input.success(null); + } + + int intentVisibility; + if (visibleToEphemeral) { + intentVisibility = IntentFilter.VISIBILITY_EXPLICIT; + } else if (allowImplicitEphemeralVisibility + && ComponentParseUtils.isImplicitlyExposedIntent(intent)){ + intentVisibility = IntentFilter.VISIBILITY_IMPLICIT; + } else { + intentVisibility = IntentFilter.VISIBILITY_NONE; + } + intent.setVisibilityToInstantApp(intentVisibility); + + return input.success(intentResult.getResult()); + } + +} diff --git a/core/java/android/content/pm/parsing/component/ParsedPermission.java b/core/java/android/content/pm/parsing/component/ParsedPermission.java new file mode 100644 index 000000000000..6c36ecb76846 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedPermission.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.parsing.ParsingPackageImpl.sForString; + +import android.annotation.Nullable; +import android.content.pm.PermissionInfo; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +/** @hide */ +public class ParsedPermission extends ParsedComponent { + + @Nullable + String backgroundPermission; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String group; + int requestRes; + int protectionLevel; + boolean tree; + @Nullable + private ParsedPermissionGroup parsedPermissionGroup; + + @VisibleForTesting + public ParsedPermission() { + } + + public ParsedPermission(ParsedPermission other) { + super(other); + this.backgroundPermission = other.backgroundPermission; + this.group = other.group; + this.requestRes = other.requestRes; + this.protectionLevel = other.protectionLevel; + this.tree = other.tree; + this.parsedPermissionGroup = other.parsedPermissionGroup; + } + + public ParsedPermission(ParsedPermission other, PermissionInfo pendingPermissionInfo, + String packageName, String name) { + this(other); + + this.flags = pendingPermissionInfo.flags; + this.descriptionRes = pendingPermissionInfo.descriptionRes; + + this.backgroundPermission = pendingPermissionInfo.backgroundPermission; + this.group = pendingPermissionInfo.group; + this.requestRes = pendingPermissionInfo.requestRes; + this.protectionLevel = pendingPermissionInfo.protectionLevel; + + setName(name); + setPackageName(packageName); + } + + public ParsedPermission setGroup(String group) { + this.group = TextUtils.safeIntern(group); + return this; + } + + public ParsedPermission setFlags(int flags) { + this.flags = flags; + return this; + } + + public boolean isRuntime() { + return getProtection() == PermissionInfo.PROTECTION_DANGEROUS; + } + + public boolean isAppOp() { + return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0; + } + + @PermissionInfo.Protection + public int getProtection() { + return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; + } + + public int getProtectionFlags() { + return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE; + } + + public int calculateFootprint() { + int size = getName().length(); + if (getNonLocalizedLabel() != null) { + size += getNonLocalizedLabel().length(); + } + return size; + } + + public String toString() { + return "Permission{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + getName() + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(this.backgroundPermission); + sForString.parcel(this.group, dest, flags); + dest.writeInt(this.requestRes); + dest.writeInt(this.protectionLevel); + dest.writeBoolean(this.tree); + dest.writeParcelable(this.parsedPermissionGroup, flags); + } + + protected ParsedPermission(Parcel in) { + super(in); + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.backgroundPermission = in.readString(); + this.group = sForString.unparcel(in); + this.requestRes = in.readInt(); + this.protectionLevel = in.readInt(); + this.tree = in.readBoolean(); + this.parsedPermissionGroup = in.readParcelable(boot); + } + + public static final Parcelable.Creator<ParsedPermission> CREATOR = + new Parcelable.Creator<ParsedPermission>() { + @Override + public ParsedPermission createFromParcel(Parcel source) { + return new ParsedPermission(source); + } + + @Override + public ParsedPermission[] newArray(int size) { + return new ParsedPermission[size]; + } + }; + + @Nullable + public String getBackgroundPermission() { + return backgroundPermission; + } + + @Nullable + public String getGroup() { + return group; + } + + public int getRequestRes() { + return requestRes; + } + + public int getProtectionLevel() { + return protectionLevel; + } + + public boolean isTree() { + return tree; + } + + @Nullable + public ParsedPermissionGroup getParsedPermissionGroup() { + return parsedPermissionGroup; + } + + public ParsedPermission setProtectionLevel(int value) { + protectionLevel = value; + return this; + } + + public ParsedPermission setParsedPermissionGroup(@Nullable ParsedPermissionGroup value) { + parsedPermissionGroup = value; + return this; + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java b/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java new file mode 100644 index 000000000000..741c00cbb723 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** @hide */ +public class ParsedPermissionGroup extends ParsedComponent { + + int requestDetailResourceId; + int backgroundRequestResourceId; + int backgroundRequestDetailResourceId; + int requestRes; + int priority; + + public void setPriority(int priority) { + this.priority = priority; + } + + public String toString() { + return "PermissionGroup{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + getName() + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.requestDetailResourceId); + dest.writeInt(this.backgroundRequestResourceId); + dest.writeInt(this.backgroundRequestDetailResourceId); + dest.writeInt(this.requestRes); + dest.writeInt(this.priority); + } + + public ParsedPermissionGroup() { + } + + protected ParsedPermissionGroup(Parcel in) { + super(in); + this.requestDetailResourceId = in.readInt(); + this.backgroundRequestResourceId = in.readInt(); + this.backgroundRequestDetailResourceId = in.readInt(); + this.requestRes = in.readInt(); + this.priority = in.readInt(); + } + + public static final Parcelable.Creator<ParsedPermissionGroup> CREATOR = + new Parcelable.Creator<ParsedPermissionGroup>() { + @Override + public ParsedPermissionGroup createFromParcel(Parcel source) { + return new ParsedPermissionGroup(source); + } + + @Override + public ParsedPermissionGroup[] newArray(int size) { + return new ParsedPermissionGroup[size]; + } + }; + + public int getRequestDetailResourceId() { + return requestDetailResourceId; + } + + public int getBackgroundRequestResourceId() { + return backgroundRequestResourceId; + } + + public int getBackgroundRequestDetailResourceId() { + return backgroundRequestDetailResourceId; + } + + public int getRequestRes() { + return requestRes; + } + + public int getPriority() { + return priority; + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java new file mode 100644 index 000000000000..1884a1e27832 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.NonNull; +import android.content.pm.PermissionInfo; +import android.content.pm.parsing.ParsingPackage; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.util.Slog; + +import com.android.internal.R; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide */ +public class ParsedPermissionUtils { + + private static final String TAG = ParsingPackageUtils.TAG; + + @NonNull + public static ParseResult<ParsedPermission> parsePermission(ParsingPackage pkg, Resources res, + XmlResourceParser parser, boolean useRoundIcon, ParseInput input) + throws IOException, XmlPullParserException { + String packageName = pkg.getPackageName(); + ParsedPermission + permission = new ParsedPermission(); + String tag = "<" + parser.getName() + ">"; + final ParseResult<ParsedPermission> result; + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission); + try { + result = ParsedComponentUtils.parseComponent( + permission, tag, pkg, sa, useRoundIcon, input, + R.styleable.AndroidManifestPermission_banner, + R.styleable.AndroidManifestPermission_description, + R.styleable.AndroidManifestPermission_icon, + R.styleable.AndroidManifestPermission_label, + R.styleable.AndroidManifestPermission_logo, + R.styleable.AndroidManifestPermission_name, + R.styleable.AndroidManifestPermission_roundIcon); + if (result.isError()) { + return result; + } + + if (sa.hasValue( + R.styleable.AndroidManifestPermission_backgroundPermission)) { + if ("android".equals(packageName)) { + permission.backgroundPermission = sa.getNonResourceString( + R.styleable + .AndroidManifestPermission_backgroundPermission); + } else { + Slog.w(TAG, packageName + " defines a background permission. Only the " + + "'android' package can do that."); + } + } + + // Note: don't allow this value to be a reference to a resource + // that may change. + permission.setGroup(sa.getNonResourceString( + R.styleable.AndroidManifestPermission_permissionGroup)); + + permission.requestRes = sa.getResourceId( + R.styleable.AndroidManifestPermission_request, 0); + + permission.protectionLevel = sa.getInt( + R.styleable.AndroidManifestPermission_protectionLevel, + PermissionInfo.PROTECTION_NORMAL); + + permission.flags = sa.getInt( + R.styleable.AndroidManifestPermission_permissionFlags, 0); + + // For now only platform runtime permissions can be restricted + if (!permission.isRuntime() || !"android".equals(permission.getPackageName())) { + permission.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED; + permission.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED; + } else { + // The platform does not get to specify conflicting permissions + if ((permission.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0 + && (permission.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) { + throw new IllegalStateException("Permission cannot be both soft and hard" + + " restricted: " + permission.getName()); + } + } + } finally { + sa.recycle(); + } + + // TODO(b/135203078): This is impossible because of default value in above getInt + if (permission.protectionLevel == -1) { + return input.error("<permission> does not specify protectionLevel"); + } + + permission.protectionLevel = PermissionInfo.fixProtectionLevel(permission.protectionLevel); + + if (permission.getProtectionFlags() != 0) { + if ((permission.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0 + && (permission.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) + == 0 + && (permission.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) != + PermissionInfo.PROTECTION_SIGNATURE) { + return input.error("<permission> protectionLevel specifies a non-instant flag " + + "but is not based on signature type"); + } + } + + return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission, input); + } + + @NonNull + public static ParseResult<ParsedPermission> parsePermissionTree(ParsingPackage pkg, Resources res, + XmlResourceParser parser, boolean useRoundIcon, ParseInput input) + throws IOException, XmlPullParserException { + ParsedPermission permission = new ParsedPermission(); + String tag = "<" + parser.getName() + ">"; + final ParseResult<ParsedPermission> result; + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree); + try { + result = ParsedComponentUtils.parseComponent( + permission, tag, pkg, sa, useRoundIcon, input, + R.styleable.AndroidManifestPermissionTree_banner, + null /*descriptionAttr*/, + R.styleable.AndroidManifestPermissionTree_icon, + R.styleable.AndroidManifestPermissionTree_label, + R.styleable.AndroidManifestPermissionTree_logo, + R.styleable.AndroidManifestPermissionTree_name, + R.styleable.AndroidManifestPermissionTree_roundIcon); + if (result.isError()) { + return result; + } + } finally { + sa.recycle(); + } + + int index = permission.getName().indexOf('.'); + if (index > 0) { + index = permission.getName().indexOf('.', index + 1); + } + if (index < 0) { + return input.error("<permission-tree> name has less than three segments: " + + permission.getName()); + } + + permission.protectionLevel = PermissionInfo.PROTECTION_NORMAL; + permission.tree = true; + + return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission, + input); + } + + @NonNull + public static ParseResult<ParsedPermissionGroup> parsePermissionGroup(ParsingPackage pkg, + Resources res, XmlResourceParser parser, boolean useRoundIcon, ParseInput input) + throws IOException, XmlPullParserException { + ParsedPermissionGroup + permissionGroup = new ParsedPermissionGroup(); + String tag = "<" + parser.getName() + ">"; + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup); + try { + ParseResult<ParsedPermissionGroup> result = ParsedComponentUtils.parseComponent( + permissionGroup, tag, pkg, sa, useRoundIcon, input, + R.styleable.AndroidManifestPermissionGroup_banner, + R.styleable.AndroidManifestPermissionGroup_description, + R.styleable.AndroidManifestPermissionGroup_icon, + R.styleable.AndroidManifestPermissionGroup_label, + R.styleable.AndroidManifestPermissionGroup_logo, + R.styleable.AndroidManifestPermissionGroup_name, + R.styleable.AndroidManifestPermissionGroup_roundIcon); + if (result.isError()) { + return result; + } + + // @formatter:off + permissionGroup.requestDetailResourceId = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_requestDetail, 0); + permissionGroup.backgroundRequestResourceId = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequest, 0); + permissionGroup.backgroundRequestDetailResourceId = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequestDetail, 0); + permissionGroup.requestRes = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_request, 0); + permissionGroup.flags = sa.getInt(R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,0); + permissionGroup.priority = sa.getInt(R.styleable.AndroidManifestPermissionGroup_priority, 0); + // @formatter:on + } finally { + sa.recycle(); + } + + return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permissionGroup, + input); + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/core/java/android/content/pm/parsing/component/ParsedProcess.java new file mode 100644 index 000000000000..da7bf984aa7f --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static java.util.Collections.emptySet; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArraySet; + +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; + +import java.util.Set; + +/** @hide */ +@DataClass(genGetters = true, genSetters = false, genParcelable = true, genAidl = false, + genBuilder = false) +public class ParsedProcess implements Parcelable { + + @NonNull + protected String name; + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) + protected Set<String> deniedPermissions = emptySet(); + + public ParsedProcess() { + } + + public ParsedProcess(@NonNull ParsedProcess other) { + name = other.name; + deniedPermissions = new ArraySet<>(other.deniedPermissions); + } + + public void addStateFrom(@NonNull ParsedProcess other) { + deniedPermissions = CollectionUtils.addAll(deniedPermissions, other.deniedPermissions); + } + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcess.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedProcess( + @NonNull String name, + @NonNull Set<String> deniedPermissions) { + this.name = name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.deniedPermissions = deniedPermissions; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, deniedPermissions); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull String getName() { + return name; + } + + @DataClass.Generated.Member + public @NonNull Set<String> getDeniedPermissions() { + return deniedPermissions; + } + + @DataClass.Generated.Member + static Parcelling<Set<String>> sParcellingForDeniedPermissions = + Parcelling.Cache.get( + Parcelling.BuiltIn.ForInternedStringSet.class); + static { + if (sParcellingForDeniedPermissions == null) { + sParcellingForDeniedPermissions = Parcelling.Cache.put( + new Parcelling.BuiltIn.ForInternedStringSet()); + } + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeString(name); + sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected ParsedProcess(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + String _name = in.readString(); + Set<String> _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in); + + this.name = _name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.deniedPermissions = _deniedPermissions; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, deniedPermissions); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<ParsedProcess> CREATOR + = new Parcelable.Creator<ParsedProcess>() { + @Override + public ParsedProcess[] newArray(int size) { + return new ParsedProcess[size]; + } + + @Override + public ParsedProcess createFromParcel(@NonNull Parcel in) { + return new ParsedProcess(in); + } + }; + + @DataClass.Generated( + time = 1581452315946L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcess.java", + inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java new file mode 100644 index 000000000000..48250666a58b --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import android.annotation.NonNull; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.ParsingUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.util.ArrayMap; +import android.util.ArraySet; + +import com.android.internal.R; +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Set; + +/** @hide */ +public class ParsedProcessUtils { + + private static final String TAG = ParsingUtils.TAG; + + @NonNull + private static ParseResult<Set<String>> parseDenyPermission(Set<String> perms, + Resources res, XmlResourceParser parser, ParseInput input) + throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestDenyPermission); + try { + String perm = sa.getNonConfigurationString( + R.styleable.AndroidManifestDenyPermission_name, 0); + if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) { + perms = CollectionUtils.add(perms, perm); + } + } finally { + sa.recycle(); + } + XmlUtils.skipCurrentTag(parser); + return input.success(perms); + } + + @NonNull + private static ParseResult<Set<String>> parseAllowPermission(Set<String> perms, Resources res, + XmlResourceParser parser, ParseInput input) + throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAllowPermission); + try { + String perm = sa.getNonConfigurationString( + R.styleable.AndroidManifestAllowPermission_name, 0); + if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) { + perms = CollectionUtils.remove(perms, perm); + } + } finally { + sa.recycle(); + } + XmlUtils.skipCurrentTag(parser); + return input.success(perms); + } + + @NonNull + private static ParseResult<ParsedProcess> parseProcess(Set<String> perms, String[] separateProcesses, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, + ParseInput input) throws IOException, XmlPullParserException { + ParsedProcess proc = new ParsedProcess(); + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess); + try { + if (perms != null) { + proc.deniedPermissions = new ArraySet<>(perms); + } + + proc.name = sa.getNonConfigurationString( + R.styleable.AndroidManifestProcess_process, 0); + ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName( + pkg.getPackageName(), pkg.getPackageName(), proc.name, flags, separateProcesses, + input); + if (processNameResult.isError()) { + return input.error(processNameResult); + } + + proc.name = processNameResult.getResult(); + + if (proc.name == null || proc.name.length() <= 0) { + return input.error("<process> does not specify android:process"); + } + } finally { + sa.recycle(); + } + + int type; + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + ParseResult<?> result; + + String tagName = parser.getName(); + switch (tagName) { + case "deny-permission": + ParseResult<Set<String>> denyResult = parseDenyPermission( + proc.deniedPermissions, res, parser, input); + result = denyResult; + if (denyResult.isSuccess()) { + proc.deniedPermissions = denyResult.getResult(); + } + break; + case "allow-permission": + ParseResult<Set<String>> allowResult = parseAllowPermission( + proc.deniedPermissions, res, parser, input); + result = allowResult; + if (allowResult.isSuccess()) { + proc.deniedPermissions = allowResult.getResult(); + } + break; + default: + result = ParsingUtils.unknownTag("<process>", pkg, parser, input); + break; + } + + if (result.isError()) { + return input.error(result); + } + } + + return input.success(proc); + } + + @NonNull + public static ParseResult<ArrayMap<String, ParsedProcess>> parseProcesses( + String[] separateProcesses, ParsingPackage pkg, Resources res, + XmlResourceParser parser, int flags, ParseInput input) + throws IOException, XmlPullParserException { + Set<String> deniedPerms = null; + ArrayMap<String, ParsedProcess> processes = new ArrayMap<>(); + + int type; + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + ParseResult<?> result; + + String tagName = parser.getName(); + switch (tagName) { + case "deny-permission": + ParseResult<Set<String>> denyResult = parseDenyPermission(deniedPerms, res, + parser, input); + result = denyResult; + if (denyResult.isSuccess()) { + deniedPerms = denyResult.getResult(); + } + break; + case "allow-permission": + ParseResult<Set<String>> allowResult = parseAllowPermission(deniedPerms, res, + parser, input); + result = allowResult; + if (allowResult.isSuccess()) { + deniedPerms = allowResult.getResult(); + } + break; + case "process": + ParseResult<ParsedProcess> processResult = parseProcess(deniedPerms, + separateProcesses, pkg, res, parser, flags, input); + result = processResult; + if (processResult.isSuccess()) { + ParsedProcess process = processResult.getResult(); + if (processes.put(process.name, process) != null) { + result = input.error( + "<process> specified existing name '" + process.name + "'"); + } + } + break; + default: + result = ParsingUtils.unknownTag("<processes>", pkg, parser, input); + break; + } + + if (result.isError()) { + return input.error(result); + } + + } + + return input.success(processes); + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedProvider.java b/core/java/android/content/pm/parsing/component/ParsedProvider.java new file mode 100644 index 000000000000..d2c531dbe5d9 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedProvider.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.parsing.ParsingPackageImpl.sForString; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.pm.PathPermission; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.PatternMatcher; +import android.text.TextUtils; + +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +/** @hide **/ +public class ParsedProvider extends ParsedMainComponent { + + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + private String authority; + boolean syncable; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String readPermission; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String writePermission; + boolean grantUriPermissions; + boolean forceUriPermissions; + boolean multiProcess; + int initOrder; + @Nullable + PatternMatcher[] uriPermissionPatterns; + @Nullable + PathPermission[] pathPermissions; + + public ParsedProvider(ParsedProvider other) { + super(other); + + this.authority = other.authority; + this.syncable = other.syncable; + this.readPermission = other.readPermission; + this.writePermission = other.writePermission; + this.grantUriPermissions = other.grantUriPermissions; + this.forceUriPermissions = other.forceUriPermissions; + this.multiProcess = other.multiProcess; + this.initOrder = other.initOrder; + this.uriPermissionPatterns = other.uriPermissionPatterns; + this.pathPermissions = other.pathPermissions; + } + + public void setAuthority(String authority) { + this.authority = TextUtils.safeIntern(authority); + } + + public void setSyncable(boolean syncable) { + this.syncable = syncable; + } + + public void setReadPermission(String readPermission) { + // Empty string must be converted to null + this.readPermission = TextUtils.isEmpty(readPermission) + ? null : readPermission.intern(); + } + + public void setWritePermission(String writePermission) { + // Empty string must be converted to null + this.writePermission = TextUtils.isEmpty(writePermission) + ? null : writePermission.intern(); + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Provider{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + ComponentName.appendShortString(sb, getPackageName(), getName()); + sb.append('}'); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + sForString.parcel(this.authority, dest, flags); + dest.writeBoolean(this.syncable); + sForString.parcel(this.readPermission, dest, flags); + sForString.parcel(this.writePermission, dest, flags); + dest.writeBoolean(this.grantUriPermissions); + dest.writeBoolean(this.forceUriPermissions); + dest.writeBoolean(this.multiProcess); + dest.writeInt(this.initOrder); + dest.writeTypedArray(this.uriPermissionPatterns, flags); + dest.writeTypedArray(this.pathPermissions, flags); + } + + public ParsedProvider() { + } + + protected ParsedProvider(Parcel in) { + super(in); + //noinspection ConstantConditions + this.authority = sForString.unparcel(in); + this.syncable = in.readBoolean(); + this.readPermission = sForString.unparcel(in); + this.writePermission = sForString.unparcel(in); + this.grantUriPermissions = in.readBoolean(); + this.forceUriPermissions = in.readBoolean(); + this.multiProcess = in.readBoolean(); + this.initOrder = in.readInt(); + this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR); + this.pathPermissions = in.createTypedArray(PathPermission.CREATOR); + } + + public static final Parcelable.Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() { + @Override + public ParsedProvider createFromParcel(Parcel source) { + return new ParsedProvider(source); + } + + @Override + public ParsedProvider[] newArray(int size) { + return new ParsedProvider[size]; + } + }; + + @NonNull + public String getAuthority() { + return authority; + } + + public boolean isSyncable() { + return syncable; + } + + @Nullable + public String getReadPermission() { + return readPermission; + } + + @Nullable + public String getWritePermission() { + return writePermission; + } + + public boolean isGrantUriPermissions() { + return grantUriPermissions; + } + + public boolean isForceUriPermissions() { + return forceUriPermissions; + } + + public boolean isMultiProcess() { + return multiProcess; + } + + public int getInitOrder() { + return initOrder; + } + + @Nullable + public PatternMatcher[] getUriPermissionPatterns() { + return uriPermissionPatterns; + } + + @Nullable + public PathPermission[] getPathPermissions() { + return pathPermissions; + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java new file mode 100644 index 000000000000..aa5ea8d4295a --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.parsing.component.ComponentParseUtils.flag; + +import android.annotation.NonNull; +import android.content.pm.PackageParser; +import android.content.pm.PathPermission; +import android.content.pm.ProviderInfo; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.ParsingUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.os.PatternMatcher; +import android.util.Slog; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Objects; + +/** @hide */ +public class ParsedProviderUtils { + + private static final String TAG = ParsingPackageUtils.TAG; + + @NonNull + public static ParseResult<ParsedProvider> parseProvider(String[] separateProcesses, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, + boolean useRoundIcon, ParseInput input) + throws IOException, XmlPullParserException { + String authority; + boolean visibleToEphemeral; + + final int targetSdkVersion = pkg.getTargetSdkVersion(); + final String packageName = pkg.getPackageName(); + final ParsedProvider provider = new ParsedProvider(); + final String tag = parser.getName(); + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProvider); + try { + ParseResult<ParsedProvider> result = + ParsedMainComponentUtils.parseMainComponent(provider, tag, separateProcesses, + pkg, sa, flags, useRoundIcon, input, + R.styleable.AndroidManifestProvider_banner, + R.styleable.AndroidManifestProvider_description, + R.styleable.AndroidManifestProvider_directBootAware, + R.styleable.AndroidManifestProvider_enabled, + R.styleable.AndroidManifestProvider_icon, + R.styleable.AndroidManifestProvider_label, + R.styleable.AndroidManifestProvider_logo, + R.styleable.AndroidManifestProvider_name, + R.styleable.AndroidManifestProvider_process, + R.styleable.AndroidManifestProvider_roundIcon, + R.styleable.AndroidManifestProvider_splitName); + if (result.isError()) { + return result; + } + + authority = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_authorities, 0); + + // For compatibility, applications targeting API level 16 or lower + // should have their content providers exported by default, unless they + // specify otherwise. + provider.exported = sa.getBoolean(R.styleable.AndroidManifestProvider_exported, + targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1); + + provider.syncable = sa.getBoolean(R.styleable.AndroidManifestProvider_syncable, false); + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_permission, 0); + String readPermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_readPermission, 0); + if (readPermission == null) { + readPermission = permission; + } + if (readPermission == null) { + provider.setReadPermission(pkg.getPermission()); + } else { + provider.setReadPermission(readPermission); + } + String writePermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_writePermission, 0); + if (writePermission == null) { + writePermission = permission; + } + if (writePermission == null) { + provider.setWritePermission(pkg.getPermission()); + } else { + provider.setWritePermission(writePermission); + } + + provider.grantUriPermissions = sa.getBoolean(R.styleable.AndroidManifestProvider_grantUriPermissions, false); + provider.forceUriPermissions = sa.getBoolean(R.styleable.AndroidManifestProvider_forceUriPermissions, false); + provider.multiProcess = sa.getBoolean(R.styleable.AndroidManifestProvider_multiprocess, false); + provider.initOrder = sa.getInt(R.styleable.AndroidManifestProvider_initOrder, 0); + + provider.flags |= flag(ProviderInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestProvider_singleUser, sa); + + visibleToEphemeral = sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false); + if (visibleToEphemeral) { + provider.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; + pkg.setVisibleToInstantApps(true); + } + } finally { + sa.recycle(); + } + + if (pkg.isCantSaveState()) { + // A heavy-weight application can not have providers in its main process + if (Objects.equals(provider.getProcessName(), packageName)) { + return input.error("Heavy-weight applications can not have providers" + + " in main process"); + } + } + + if (authority == null) { + return input.error("<provider> does not include authorities attribute"); + } + if (authority.length() <= 0) { + return input.error("<provider> has empty authorities attribute"); + } + provider.setAuthority(authority); + + return parseProviderTags(pkg, tag, res, parser, visibleToEphemeral, provider, input); + } + + @NonNull + private static ParseResult<ParsedProvider> parseProviderTags(ParsingPackage pkg, String tag, + Resources res, XmlResourceParser parser, boolean visibleToEphemeral, + ParsedProvider provider, ParseInput input) + throws XmlPullParserException, IOException { + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + String name = parser.getName(); + final ParseResult result; + switch (name) { + case "intent-filter": + ParseResult<ParsedIntentInfo> intentResult = ParsedMainComponentUtils + .parseIntentFilter(provider, pkg, res, parser, visibleToEphemeral, + true /*allowGlobs*/, false /*allowAutoVerify*/, + false /*allowImplicitEphemeralVisibility*/, + false /*failOnNoActions*/, input); + result = intentResult; + if (intentResult.isSuccess()) { + ParsedIntentInfo intent = intentResult.getResult(); + provider.order = Math.max(intent.getOrder(), provider.order); + provider.addIntent(intent); + } + break; + case "meta-data": + result = ParsedComponentUtils.addMetaData(provider, pkg, res, parser, input); + break; + case "grant-uri-permission": { + result = parseGrantUriPermission(provider, pkg, res, parser, input); + break; + } + case "path-permission": { + result = parsePathPermission(provider, pkg, res, parser, input); + break; + } + default: + result = ParsingUtils.unknownTag(tag, pkg, parser, input); + break; + } + + if (result.isError()) { + return input.error(result); + } + } + + return input.success(provider); + } + + @NonNull + private static ParseResult<ParsedProvider> parseGrantUriPermission(ParsedProvider provider, + ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input) { + TypedArray sa = resources.obtainAttributes(parser, + R.styleable.AndroidManifestGrantUriPermission); + try { + String name = parser.getName(); + // Pattern has priority over prefix over literal path + PatternMatcher pa = null; + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } else { + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); + } else { + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_path, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); + } + } + } + + if (pa != null) { + if (provider.uriPermissionPatterns == null) { + provider.uriPermissionPatterns = new PatternMatcher[1]; + provider.uriPermissionPatterns[0] = pa; + } else { + final int N = provider.uriPermissionPatterns.length; + PatternMatcher[] newp = new PatternMatcher[N + 1]; + System.arraycopy(provider.uriPermissionPatterns, 0, newp, 0, N); + newp[N] = pa; + provider.uriPermissionPatterns = newp; + } + provider.grantUriPermissions = true; + } else { + if (PackageParser.RIGID_PARSER) { + return input.error("No path, pathPrefix, or pathPattern for <path-permission>"); + } + + Slog.w(TAG, "Unknown element under <path-permission>: " + name + " at " + + pkg.getBaseCodePath() + " " + parser.getPositionDescription()); + } + + return input.success(provider); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult<ParsedProvider> parsePathPermission(ParsedProvider provider, + ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input) { + TypedArray sa = resources.obtainAttributes(parser, + R.styleable.AndroidManifestPathPermission); + try { + String name = parser.getName(); + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_permission, 0); + String readPermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_readPermission, 0); + if (readPermission == null) { + readPermission = permission; + } + String writePermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_writePermission, 0); + if (writePermission == null) { + writePermission = permission; + } + + boolean havePerm = false; + if (readPermission != null) { + readPermission = readPermission.intern(); + havePerm = true; + } + if (writePermission != null) { + writePermission = writePermission.intern(); + havePerm = true; + } + + if (!havePerm) { + if (PackageParser.RIGID_PARSER) { + return input.error( + "No readPermission or writePermission for <path-permission>"); + } + Slog.w(TAG, "No readPermission or writePermission for <path-permission>: " + + name + " at " + pkg.getBaseCodePath() + " " + parser.getPositionDescription()); + return input.success(provider); + } + + // Advanced has priority over simply over prefix over literal + PathPermission pa = null; + String path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0); + if (path != null) { + pa = new PathPermission(path, PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, + writePermission); + } else { + path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_pathPattern, 0); + if (path != null) { + pa = new PathPermission(path, PatternMatcher.PATTERN_SIMPLE_GLOB, + readPermission, writePermission); + } else { + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_pathPrefix, 0); + if (path != null) { + pa = new PathPermission(path, PatternMatcher.PATTERN_PREFIX, readPermission, + writePermission); + } else { + path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_path, 0); + if (path != null) { + pa = new PathPermission(path, PatternMatcher.PATTERN_LITERAL, + readPermission, writePermission); + } + } + } + } + + if (pa != null) { + if (provider.pathPermissions == null) { + provider.pathPermissions = new PathPermission[1]; + provider.pathPermissions[0] = pa; + } else { + final int N = provider.pathPermissions.length; + PathPermission[] newp = new PathPermission[N + 1]; + System.arraycopy(provider.pathPermissions, 0, newp, 0, N); + newp[N] = pa; + provider.pathPermissions = newp; + } + } else { + if (PackageParser.RIGID_PARSER) { + return input.error( + "No path, pathPrefix, or pathPattern for <path-permission>"); + } + + Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " + + name + " at " + pkg.getBaseCodePath() + + " " + + parser.getPositionDescription()); + } + + return input.success(provider); + } finally { + sa.recycle(); + } + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedService.java b/core/java/android/content/pm/parsing/component/ParsedService.java new file mode 100644 index 000000000000..591eef74453a --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedService.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.parsing.ParsingPackageImpl.sForString; + +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +/** @hide **/ +public class ParsedService extends ParsedMainComponent { + + int foregroundServiceType; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String permission; + + public ParsedService(ParsedService other) { + super(other); + this.foregroundServiceType = other.foregroundServiceType; + this.permission = other.permission; + } + + public ParsedMainComponent setPermission(String permission) { + // Empty string must be converted to null + this.permission = TextUtils.isEmpty(permission) ? null : permission.intern(); + return this; + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Service{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + ComponentName.appendShortString(sb, getPackageName(), getName()); + sb.append('}'); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.foregroundServiceType); + sForString.parcel(this.permission, dest, flags); + } + + public ParsedService() { + } + + protected ParsedService(Parcel in) { + super(in); + this.foregroundServiceType = in.readInt(); + this.permission = sForString.unparcel(in); + } + + public static final Parcelable.Creator<ParsedService> CREATOR = new Creator<ParsedService>() { + @Override + public ParsedService createFromParcel(Parcel source) { + return new ParsedService(source); + } + + @Override + public ParsedService[] newArray(int size) { + return new ParsedService[size]; + } + }; + + public int getForegroundServiceType() { + return foregroundServiceType; + } + + @Nullable + public String getPermission() { + return permission; + } +} diff --git a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java new file mode 100644 index 000000000000..8a8a066839e3 --- /dev/null +++ b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.component; + +import static android.content.pm.parsing.component.ComponentParseUtils.flag; + +import android.annotation.NonNull; +import android.content.pm.ActivityInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.ParsingUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Objects; + +/** @hide */ +public class ParsedServiceUtils { + + private static final String TAG = ParsingPackageUtils.TAG; + + @NonNull + public static ParseResult<ParsedService> parseService(String[] separateProcesses, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, + boolean useRoundIcon, ParseInput input) + throws XmlPullParserException, IOException { + boolean visibleToEphemeral; + boolean setExported; + + final String packageName = pkg.getPackageName(); + final ParsedService service = new ParsedService(); + String tag = parser.getName(); + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestService); + try { + ParseResult<ParsedService> result = ParsedMainComponentUtils.parseMainComponent( + service, tag, separateProcesses, pkg, sa, flags, useRoundIcon, input, + R.styleable.AndroidManifestService_banner, + R.styleable.AndroidManifestService_description, + R.styleable.AndroidManifestService_directBootAware, + R.styleable.AndroidManifestService_enabled, + R.styleable.AndroidManifestService_icon, + R.styleable.AndroidManifestService_label, + R.styleable.AndroidManifestService_logo, + R.styleable.AndroidManifestService_name, + R.styleable.AndroidManifestService_process, + R.styleable.AndroidManifestService_roundIcon, + R.styleable.AndroidManifestService_splitName + ); + + if (result.isError()) { + return result; + } + + setExported = sa.hasValue(R.styleable.AndroidManifestService_exported); + if (setExported) { + service.exported = sa.getBoolean(R.styleable.AndroidManifestService_exported, + false); + } + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestService_permission, 0); + service.setPermission(permission != null ? permission : pkg.getPermission()); + + service.foregroundServiceType = sa.getInt( + R.styleable.AndroidManifestService_foregroundServiceType, + ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE); + + service.flags |= flag(ServiceInfo.FLAG_STOP_WITH_TASK, + R.styleable.AndroidManifestService_stopWithTask, sa) + | flag(ServiceInfo.FLAG_ISOLATED_PROCESS, + R.styleable.AndroidManifestService_isolatedProcess, sa) + | flag(ServiceInfo.FLAG_EXTERNAL_SERVICE, + R.styleable.AndroidManifestService_externalService, sa) + | flag(ServiceInfo.FLAG_USE_APP_ZYGOTE, + R.styleable.AndroidManifestService_useAppZygote, sa) + | flag(ServiceInfo.FLAG_SINGLE_USER, + R.styleable.AndroidManifestService_singleUser, sa); + + visibleToEphemeral = sa.getBoolean( + R.styleable.AndroidManifestService_visibleToInstantApps, false); + if (visibleToEphemeral) { + service.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + pkg.setVisibleToInstantApps(true); + } + } finally { + sa.recycle(); + } + + if (pkg.isCantSaveState()) { + // A heavy-weight application can not have services in its main process + // We can do direct compare because we intern all strings. + if (Objects.equals(service.getProcessName(), packageName)) { + return input.error("Heavy-weight applications can not have services " + + "in main process"); + } + } + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult parseResult; + switch (parser.getName()) { + case "intent-filter": + ParseResult<ParsedIntentInfo> intentResult = ParsedMainComponentUtils + .parseIntentFilter(service, pkg, res, parser, visibleToEphemeral, + true /*allowGlobs*/, false /*allowAutoVerify*/, + false /*allowImplicitEphemeralVisibility*/, + false /*failOnNoActions*/, input); + parseResult = intentResult; + if (intentResult.isSuccess()) { + ParsedIntentInfo intent = intentResult.getResult(); + service.order = Math.max(intent.getOrder(), service.order); + service.addIntent(intent); + } + break; + case "meta-data": + parseResult = ParsedComponentUtils.addMetaData(service, pkg, res, parser, input); + break; + default: + parseResult = ParsingUtils.unknownTag(tag, pkg, parser, input); + break; + } + + if (parseResult.isError()) { + return input.error(parseResult); + } + } + + if (!setExported) { + service.exported = service.getIntents().size() > 0; + } + + return input.success(service); + } +} diff --git a/core/java/android/content/pm/parsing/result/ParseInput.java b/core/java/android/content/pm/parsing/result/ParseInput.java new file mode 100644 index 000000000000..c46850609d9e --- /dev/null +++ b/core/java/android/content/pm/parsing/result/ParseInput.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.result; + +import android.annotation.Hide; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.PackageManager; + +/** + * Used as a method parameter which is then transformed into a {@link ParseResult}. This is + * generalized as it doesn't matter what type this input is for. It's simply to hide the + * methods of {@link ParseResult}. + * + * @hide + */ +public interface ParseInput { + + <ResultType> ParseResult<ResultType> success(ResultType result); + + /** @see #error(int, String, Exception) */ + <ResultType> ParseResult<ResultType> error(int parseError); + + /** + * This will assign errorCode to {@link PackageManager#INSTALL_PARSE_FAILED_MANIFEST_MALFORMED}. + * @see #error(int, String, Exception) + */ + <ResultType> ParseResult<ResultType> error(@NonNull String parseError); + + /** @see #error(int, String, Exception) */ + <ResultType> ParseResult<ResultType> error(int parseError, @Nullable String errorMessage); + + /** + * Marks this as an error result. When this method is called, the return value <b>must</b> + * be returned to the exit of the parent method that took in this {@link ParseInput} as a + * parameter. + * + * The calling site of that method is then expected to check the result for error, and + * continue to bubble up if it is an error. + * + * Or, if the code explicitly handles an error, + * {@link ParseResult#ignoreError()} should be called. + * + * If the result {@link ParseResult#isSuccess()}, then it can be used as-is, as + * overlapping/consecutive successes are allowed. + */ + <ResultType> ParseResult<ResultType> error(int parseError, @Nullable String errorMessage, + @Nullable Exception exception); + + /** + * Moves the error in {@param result} to this input's type. In practice this does nothing + * but cast the type of the {@link ParseResult} for type safety, since the parameter + * and the receiver should be the same object. + */ + <ResultType> ParseResult<ResultType> error(ParseResult result); +} diff --git a/core/java/android/content/pm/parsing/result/ParseResult.java b/core/java/android/content/pm/parsing/result/ParseResult.java new file mode 100644 index 000000000000..338048c3c1ec --- /dev/null +++ b/core/java/android/content/pm/parsing/result/ParseResult.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.result; + +import android.annotation.Nullable; +import android.content.pm.PackageParser; + +/** + * The output side of {@link ParseInput}, which must result from a method call on + * {@link ParseInput}. + * + * When using this class, keep in mind that all {@link ParseInput}s and {@link ParseResult}s + * are the exact same object, scoped to a per {@link PackageParser} instance, per thread basis, + * thrown around and casted everywhere for type safety. + * + * @hide + */ +public interface ParseResult<ResultType> { + + /** + * Un-marks this result as an error, also allowing it to be re-used as {@link ParseInput}. + * + * This should only be used in cases where it's absolutely certain that error handling is + * irrelevant. Such as for backwards compatibility where it previously didn't fail and that + * behavior has to be maintained. + * + * Mostly an alias for readability. + */ + void ignoreError(); + + /** + * Returns true if the result is not an error and thus contains a valid object. + * + * For backwards-compat reasons, it's possible to have a successful result with a null + * result object, depending on the behavior of the parsing method. + * + * It is expected that every method calls this to check for an error state to bubble up + * the error to its parent method after every parse method call. + * + * It is not always necessary to check this, as it is valid to return any ParseResult from + * a method so long as the type matches <b>without casting it</b>. + * + * The infrastructure is set up such that as long as a result is the proper type and + * the right side of success vs. error, it can be bubble up through all its parent methods. + */ + boolean isSuccess(); + + /** + * Opposite of {@link #isSuccess()} for readability. + */ + boolean isError(); + + ResultType getResult(); + + int getErrorCode(); + + @Nullable + String getErrorMessage(); + + @Nullable + Exception getException(); +} diff --git a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java new file mode 100644 index 000000000000..9b22f09b2978 --- /dev/null +++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.result; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.PackageManager; +import android.content.pm.parsing.ParsingUtils; +import android.util.Log; + +import java.util.Arrays; + +/** @hide */ +public class ParseTypeImpl implements ParseInput, ParseResult<Object> { + + private static final String TAG = ParsingUtils.TAG; + + private static final boolean DEBUG_FILL_STACK_TRACE = false; + + private static final boolean DEBUG_LOG_ON_ERROR = false; + + private Object result; + + private int errorCode = PackageManager.INSTALL_SUCCEEDED; + + @Nullable + private String errorMessage; + + @Nullable + private Exception exception; + + public ParseInput reset() { + this.result = null; + this.errorCode = PackageManager.INSTALL_SUCCEEDED; + this.errorMessage = null; + this.exception = null; + return this; + } + + @Override + public void ignoreError() { + reset(); + } + + @Override + public <ResultType> ParseResult<ResultType> success(ResultType result) { + if (errorCode != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) { + throw new IllegalStateException("Cannot set to success after set to error, was " + + errorMessage, exception); + } + this.result = result; + //noinspection unchecked + return (ParseResult<ResultType>) this; + } + + @Override + public <ResultType> ParseResult<ResultType> error(int parseError) { + return error(parseError, null); + } + + @Override + public <ResultType> ParseResult<ResultType> error(@NonNull String parseError) { + return error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, parseError); + } + + @Override + public <ResultType> ParseResult<ResultType> error(int errorCode, + @Nullable String errorMessage) { + return error(errorCode, errorMessage, null); + } + + @Override + public <ResultType> ParseResult<ResultType> error(ParseResult intentResult) { + return error(intentResult.getErrorCode(), intentResult.getErrorMessage()); + } + + @Override + public <ResultType> ParseResult<ResultType> error(int errorCode, @Nullable String errorMessage, + Exception exception) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + this.exception = exception; + + if (DEBUG_FILL_STACK_TRACE) { + if (exception == null) { + this.exception = new Exception(); + } + } + + if (DEBUG_LOG_ON_ERROR) { + Exception exceptionToLog = this.exception != null ? this.exception : new Exception(); + Log.w(TAG, "ParseInput set to error " + errorCode + ", " + errorMessage, + exceptionToLog); + } + + //noinspection unchecked + return (ParseResult<ResultType>) this; + } + + @Override + public Object getResult() { + return this.result; + } + + @Override + public boolean isSuccess() { + return errorCode == PackageManager.INSTALL_SUCCEEDED; + } + + @Override + public boolean isError() { + return !isSuccess(); + } + + @Override + public int getErrorCode() { + return errorCode; + } + + @Nullable + @Override + public String getErrorMessage() { + return errorMessage; + } + + @Nullable + @Override + public Exception getException() { + return exception; + } +} diff --git a/core/java/android/debug/AdbManager.java b/core/java/android/debug/AdbManager.java index 0a76bedcd66e..7714dd80f910 100644 --- a/core/java/android/debug/AdbManager.java +++ b/core/java/android/debug/AdbManager.java @@ -31,6 +31,114 @@ import android.os.RemoteException; public class AdbManager { private static final String TAG = "AdbManager"; + /** + * Action indicating the state change of wireless debugging. Can be either + * STATUS_CONNECTED + * STATUS_DISCONNECTED + * + * @hide + */ + public static final String WIRELESS_DEBUG_STATE_CHANGED_ACTION = + "com.android.server.adb.WIRELESS_DEBUG_STATUS"; + + /** + * Contains the list of paired devices. + * + * @hide + */ + public static final String WIRELESS_DEBUG_PAIRED_DEVICES_ACTION = + "com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES"; + + /** + * Action indicating the status of a pairing. Can be either + * WIRELESS_STATUS_FAIL + * WIRELESS_STATUS_SUCCESS + * WIRELESS_STATUS_CANCELLED + * WIRELESS_STATUS_PAIRING_CODE + * WIRELESS_STATUS_CONNECTED + * + * @hide + */ + public static final String WIRELESS_DEBUG_PAIRING_RESULT_ACTION = + "com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT"; + + /** + * Extra containing the PairDevice map of paired/pairing devices. + * + * @hide + */ + public static final String WIRELESS_DEVICES_EXTRA = "devices_map"; + + /** + * The status of the pairing/unpairing. + * + * @hide + */ + public static final String WIRELESS_STATUS_EXTRA = "status"; + + /** + * The PairDevice. + * + * @hide + */ + public static final String WIRELESS_PAIR_DEVICE_EXTRA = "pair_device"; + + /** + * The six-digit pairing code. + * + * @hide + */ + public static final String WIRELESS_PAIRING_CODE_EXTRA = "pairing_code"; + + /** + * The adb connection/pairing port that was opened. + * + * @hide + */ + public static final String WIRELESS_DEBUG_PORT_EXTRA = "adb_port"; + + /** + * Status indicating the pairing/unpairing failed. + * + * @hide + */ + public static final int WIRELESS_STATUS_FAIL = 0; + + /** + * Status indicating the pairing/unpairing succeeded. + * + * @hide + */ + public static final int WIRELESS_STATUS_SUCCESS = 1; + + /** + * Status indicating the pairing/unpairing was cancelled. + * + * @hide + */ + public static final int WIRELESS_STATUS_CANCELLED = 2; + + /** + * Status indicating the pairing code for pairing. + * + * @hide + */ + public static final int WIRELESS_STATUS_PAIRING_CODE = 3; + + /** + * Status indicating wireless debugging is connected. + * + * @hide + */ + public static final int WIRELESS_STATUS_CONNECTED = 4; + + /** + * Status indicating wireless debugging is disconnected. + * + * @hide + */ + public static final int WIRELESS_STATUS_DISCONNECTED = 5; + private final Context mContext; private final IAdbManager mService; diff --git a/core/java/android/debug/AdbManagerInternal.java b/core/java/android/debug/AdbManagerInternal.java index 51eb7fc2d804..0bd9f19f91fe 100644 --- a/core/java/android/debug/AdbManagerInternal.java +++ b/core/java/android/debug/AdbManagerInternal.java @@ -42,7 +42,7 @@ public abstract class AdbManagerInternal { /** * Returns {@code true} if ADB debugging is enabled. */ - public abstract boolean isAdbEnabled(); + public abstract boolean isAdbEnabled(byte transportType); /** * Returns the file that contains all of the ADB keys used by the device. diff --git a/core/java/android/service/controls/IControlsLoadCallback.aidl b/core/java/android/debug/AdbTransportType.aidl index bfc61cdb54db..69046150d0ee 100644 --- a/core/java/android/service/controls/IControlsLoadCallback.aidl +++ b/core/java/android/debug/AdbTransportType.aidl @@ -1,11 +1,11 @@ /* - * Copyright (c) 2020, The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,13 +14,12 @@ * limitations under the License. */ -package android.service.controls; +package android.debug; -import android.service.controls.Control; +/** @hide */ +@Backing(type="byte") +enum AdbTransportType { + USB, + WIFI, +} -/** - * @hide - */ -oneway interface IControlsLoadCallback { - void accept(in IBinder token, in List<Control> controls); -}
\ No newline at end of file diff --git a/core/java/android/debug/IAdbManager.aidl b/core/java/android/debug/IAdbManager.aidl index c48fc07791c0..aea7633d91dc 100644 --- a/core/java/android/debug/IAdbManager.aidl +++ b/core/java/android/debug/IAdbManager.aidl @@ -43,6 +43,62 @@ interface IAdbManager { void clearDebuggingKeys(); /** + * Allow ADB wireless debugging on the connected network. If {@code alwaysAllow} + * is {@code true}, add {@code bssid} to list of networks that the user has + * approved. + * + * @param alwaysAllow if true, add permanently to list of allowed networks + * @param bssid BSSID of the network + */ + void allowWirelessDebugging(boolean alwaysAllow, String bssid); + + /** + * Deny ADB wireless debugging on the connected network. + */ + void denyWirelessDebugging(); + + /** + * Returns a Map<String, PairDevice> with the key fingerprint mapped to the device information. + */ + Map getPairedDevices(); + + /** + * Unpair the device identified by the key fingerprint it uses. + * + * @param fingerprint fingerprint of the key the device is using. + */ + void unpairDevice(String fingerprint); + + /** + * Enables pairing by pairing code. The result of the enable will be sent via intent action + * {@link android.debug.AdbManager#WIRELESS_DEBUG_ENABLE_DISCOVER_ACTION}. Furthermore, the + * pairing code will also be sent in the intent as an extra + * @{link android.debug.AdbManager#WIRELESS_PAIRING_CODE_EXTRA}. Note that only one + * pairing method can be enabled at a time, either by pairing code, or by QR code. + */ + void enablePairingByPairingCode(); + + /** + * Enables pairing by QR code. The result of the enable will be sent via intent action + * {@link android.debug.AdbManager#WIRELESS_DEBUG_ENABLE_DISCOVER_ACTION}. Note that only one + * pairing method can be enabled at a time, either by pairing code, or by QR code. + * + * @param serviceName The MDNS service name parsed from the QR code. + * @param password The password parsed from the QR code. + */ + void enablePairingByQrCode(String serviceName, String password); + + /** + * Returns the network port that adb wireless server is running on. + */ + int getAdbWirelessPort(); + + /** + * Disables pairing. + */ + void disablePairing(); + + /** * Returns true if device supports secure Adb over Wi-Fi. */ boolean isAdbWifiSupported(); diff --git a/core/java/android/debug/IAdbTransport.aidl b/core/java/android/debug/IAdbTransport.aidl index 77211fc93693..f018813408c4 100644 --- a/core/java/android/debug/IAdbTransport.aidl +++ b/core/java/android/debug/IAdbTransport.aidl @@ -16,7 +16,9 @@ package android.debug; +import android.debug.AdbTransportType; + /** @hide */ interface IAdbTransport { - void onAdbEnabled(boolean enabled); + void onAdbEnabled(boolean enabled, in AdbTransportType type); } diff --git a/core/java/android/debug/PairDevice.java b/core/java/android/debug/PairDevice.java new file mode 100644 index 000000000000..2d5b446b4f8f --- /dev/null +++ b/core/java/android/debug/PairDevice.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.debug; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.annotations.Immutable; +import com.android.internal.util.Preconditions; + +/** + * Contains information about the client in an ADB connection. + * @hide + */ +@Immutable +public class PairDevice implements Parcelable { + /** + * The human-readable name of the device. + */ + @NonNull private final String mName; + + /** + * The device's guid. + */ + @NonNull private final String mGuid; + + /** + * Indicates whether the device is currently connected to adbd. + */ + private final boolean mConnected; + + public PairDevice(@NonNull String name, @NonNull String guid, boolean connected) { + Preconditions.checkStringNotEmpty(name); + Preconditions.checkStringNotEmpty(guid); + mName = name; + mGuid = guid; + mConnected = connected; + } + + /** + * @return the device name. + */ + @NonNull + public String getDeviceName() { + return mName; + } + + /** + * @return the device GUID. + */ + @NonNull + public String getGuid() { + return mGuid; + } + + /** + * @return the adb connection state of the device. + */ + public boolean isConnected() { + return mConnected; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mName); + dest.writeString(mGuid); + dest.writeBoolean(mConnected); + } + + /** + * @return Human-readable info about the object. + */ + @Override + public String toString() { + return "\n" + mName + "\n" + mGuid + "\n" + mConnected; + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull + public static final Parcelable.Creator<PairDevice> CREATOR = + new Creator<PairDevice>() { + @Override + public PairDevice createFromParcel(Parcel source) { + return new PairDevice(source.readString(), source.readString(), + source.readBoolean()); + } + + @Override + public PairDevice[] newArray(int size) { + return new PairDevice[size]; + } + }; +} diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 24d931154533..cc0c1a309038 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -688,17 +688,19 @@ public abstract class CameraDevice implements AutoCloseable { * <tr><th colspan="5">Concurrent stream guaranteed configurations</th></tr> * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr> - * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>In-app video / image processing.</td> </tr> - * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>In-app viewfinder analysis.</td> </tr> - * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr> - * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr> - * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>Standard Recording.</td> </tr> + * <tr> <td>{@code YUV}</td><td id="rb">{@code s1440p}</td> <td colspan="2" id="rb"></td> <td>In-app video / image processing.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code s1440p}</td> <td colspan="2" id="rb"></td> <td>In-app viewfinder analysis.</td> </tr> + * <tr> <td>{@code JPEG}</td><td id="rb">{@code s1440p}</td> <td colspan="2" id="rb"></td> <td>No viewfinder still image capture.</td> </tr> + * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s720p}</td> <td>{@code JPEG}</td><td id="rb">{@code s1440p}</td> <td> Standard still imaging.</td> </tr> + * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s720p}</td> <td>{@code YUV / PRIV }</td><td id="rb">{@code s1440p}</td> <td>In-app video / processing with preview.</td> </tr> * </table><br> * </p> * - * <p> For guaranteed concurrent stream configurations, MAXIMUM refers to the camera device's - * resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or + * <p> For guaranteed concurrent stream configurations:</p> + * <p> s720p refers to the camera device's resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or * 720p(1280X720) whichever is lower. </p> + * <p> s1440p refers to the camera device's resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or + * 1440p(1920X1440) whichever is lower. </p> * <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} * includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}) devices * supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV} diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 17c83f3a7eb9..743ce7b46792 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -140,6 +140,11 @@ public final class CameraManager { * <p>The set of combinations doesn't contain physical cameras that can only be used as * part of a logical multi-camera device.</p> * + * <p> If a new camera id becomes available through + * {@link AvailabilityCallback#onCameraUnavailable(String)}, clients can call + * this method to check if new combinations of camera ids which can stream concurrently are + * available. + * * @return The set of combinations of currently connected camera devices, that may have * sessions configured concurrently. The set of combinations will be empty if no such * combinations are supported by the camera subsystem. diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java index 41e1443d6866..f0fab6a99d14 100644 --- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java +++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java @@ -267,7 +267,7 @@ public final class MandatoryStreamCombination { mStreamsInformation.hashCode()); } - private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM, s720p } + private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM, s720p, s1440p } private static enum ReprocessType { NONE, PRIVATE, YUV } private static final class StreamTemplate { public int mFormat; @@ -651,23 +651,38 @@ public final class MandatoryStreamCombination { private static StreamCombinationTemplate sConcurrentStreamCombinations[] = { new StreamCombinationTemplate(new StreamTemplate [] { - new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p) }, + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p) }, "In-app video / image processing"), new StreamCombinationTemplate(new StreamTemplate [] { - new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p) }, + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p) }, "preview / preview to GPU"), new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p) }, + "No view-finder still image capture"), + new StreamCombinationTemplate(new StreamTemplate [] { new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p), - new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)}, - "In-app video / image processing with preview"), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)}, + "Two-input in app video / image processing"), new StreamCombinationTemplate(new StreamTemplate [] { new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p), - new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)}, + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)}, + "High resolution video recording with preview"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)}, + "In-app video / image processing with preview"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)}, "In-app video / image processing with preview"), new StreamCombinationTemplate(new StreamTemplate [] { new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p), - new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p)}, - "Standard Recording"), + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)}, + "Standard stil image capture"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p), + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)}, + "Standard still image capture"), }; /** @@ -720,6 +735,7 @@ public final class MandatoryStreamCombination { + " cannot have mandatory concurrent streams"); } Size size720p = new Size(1280, 720); + Size size1440p = new Size(1920, 1440); ArrayList<MandatoryStreamCombination> availableConcurrentStreamCombinations = new ArrayList<MandatoryStreamCombination>(); @@ -732,8 +748,16 @@ public final class MandatoryStreamCombination { for (StreamTemplate template : combTemplate.mStreamTemplates) { MandatoryStreamInformation streamInfo; List<Size> sizes = new ArrayList<Size>(); + Size formatSize = null; + switch (template.mSizeThreshold) { + case s1440p: + formatSize = size1440p; + break; + default: + formatSize = size720p; + } Size sizeChosen = - getMinSize(size720p, + getMinSize(formatSize, getMaxSize(mStreamConfigMap.getOutputSizes(template.mFormat))); sizes.add(sizeChosen); try { diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 086db1010f73..d16f070f7209 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -18,6 +18,7 @@ package android.hardware.usb; import android.Manifest; +import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; @@ -337,12 +338,14 @@ public class UsbManager { * Code for the mtp usb function. Passed as a mask into {@link #setCurrentFunctions(long)} * {@hide} */ + @SystemApi public static final long FUNCTION_MTP = GadgetFunction.MTP; /** * Code for the ptp usb function. Passed as a mask into {@link #setCurrentFunctions(long)} * {@hide} */ + @SystemApi public static final long FUNCTION_PTP = GadgetFunction.PTP; /** @@ -356,24 +359,28 @@ public class UsbManager { * Code for the midi usb function. Passed as a mask into {@link #setCurrentFunctions(long)} * {@hide} */ + @SystemApi public static final long FUNCTION_MIDI = GadgetFunction.MIDI; /** * Code for the accessory usb function. * {@hide} */ + @SystemApi public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY; /** * Code for the audio source usb function. * {@hide} */ + @SystemApi public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE; /** * Code for the adb usb function. * {@hide} */ + @SystemApi public static final long FUNCTION_ADB = GadgetFunction.ADB; /** @@ -399,6 +406,20 @@ public class UsbManager { FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_NCM, FUNCTION_NCM); } + /** @hide */ + @LongDef(flag = true, prefix = { "FUNCTION_" }, value = { + FUNCTION_NONE, + FUNCTION_MTP, + FUNCTION_PTP, + FUNCTION_RNDIS, + FUNCTION_MIDI, + FUNCTION_ACCESSORY, + FUNCTION_AUDIO_SOURCE, + FUNCTION_ADB, + FUNCTION_NCM, + }) + public @interface UsbFunctionMode {} + private final Context mContext; private final IUsbManager mService; @@ -721,7 +742,7 @@ public class UsbManager { */ @SystemApi @RequiresPermission(Manifest.permission.MANAGE_USB) - public void setCurrentFunctions(long functions) { + public void setCurrentFunctions(@UsbFunctionMode long functions) { try { mService.setCurrentFunctions(functions); } catch (RemoteException e) { diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index 2a441de067c6..f0b1eaa9f257 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -19,7 +19,6 @@ package android.inputmethodservice; import android.annotation.BinderThread; import android.annotation.MainThread; import android.compat.annotation.UnsupportedAppUsage; -import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; @@ -29,7 +28,6 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.util.Log; import android.view.InputChannel; -import android.view.autofill.AutofillId; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputConnection; @@ -46,6 +44,7 @@ import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethod; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.IInputSessionCallback; +import com.android.internal.view.InlineSuggestionsRequestInfo; import com.android.internal.view.InputConnectionWrapper; import java.io.FileDescriptor; @@ -233,8 +232,9 @@ class IInputMethodWrapper extends IInputMethod.Stub return; case DO_CREATE_INLINE_SUGGESTIONS_REQUEST: args = (SomeArgs) msg.obj; - inputMethod.onCreateInlineSuggestionsRequest((ComponentName) args.arg1, - (AutofillId) args.arg2, (IInlineSuggestionsRequestCallback) args.arg3); + inputMethod.onCreateInlineSuggestionsRequest( + (InlineSuggestionsRequestInfo) args.arg1, + (IInlineSuggestionsRequestCallback) args.arg2); return; } @@ -279,11 +279,10 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override - public void onCreateInlineSuggestionsRequest(ComponentName componentName, AutofillId autofillId, + public void onCreateInlineSuggestionsRequest(InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) { mCaller.executeOrSendMessage( - mCaller.obtainMessageOOO(DO_CREATE_INLINE_SUGGESTIONS_REQUEST, componentName, - autofillId, cb)); + mCaller.obtainMessageOO(DO_CREATE_INLINE_SUGGESTIONS_REQUEST, requestInfo, cb)); } @BinderThread diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index b1aa67e9f7ed..20a4ab35defe 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -34,7 +34,6 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.Dialog; import android.compat.annotation.UnsupportedAppUsage; -import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; @@ -74,7 +73,6 @@ import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.AnimationUtils; -import android.view.autofill.AutofillId; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; @@ -99,6 +97,7 @@ import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry; import com.android.internal.view.IInlineSuggestionsRequestCallback; +import com.android.internal.view.InlineSuggestionsRequestInfo; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -526,12 +525,13 @@ public class InputMethodService extends AbstractInputMethodService { */ @MainThread @Override - public void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { + public void onCreateInlineSuggestionsRequest( + @NonNull InlineSuggestionsRequestInfo requestInfo, + @NonNull IInlineSuggestionsRequestCallback cb) { if (DEBUG) { Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()"); } - handleOnCreateInlineSuggestionsRequest(componentName, cb); + handleOnCreateInlineSuggestionsRequest(requestInfo, cb); } /** @@ -742,11 +742,14 @@ public class InputMethodService extends AbstractInputMethodService { // TODO(b/137800469): Add detailed docs explaining the inline suggestions process. /** - * Returns an {@link InlineSuggestionsRequest} to be sent to Autofill. + * This method should be implemented by subclass which supports displaying autofill inline + * suggestion. * - * <p>Should be implemented by subclasses.</p> + * @param uiExtras the extras that contain the UI renderer related information + * @return an {@link InlineSuggestionsRequest} to be sent to Autofill. */ - public @Nullable InlineSuggestionsRequest onCreateInlineSuggestionsRequest() { + @Nullable + public InlineSuggestionsRequest onCreateInlineSuggestionsRequest(@NonNull Bundle uiExtras) { return null; } @@ -764,7 +767,8 @@ public class InputMethodService extends AbstractInputMethodService { } @MainThread - private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName, + private void handleOnCreateInlineSuggestionsRequest( + @NonNull InlineSuggestionsRequestInfo requestInfo, @NonNull IInlineSuggestionsRequestCallback callback) { if (!mInputStarted) { try { @@ -779,8 +783,9 @@ public class InputMethodService extends AbstractInputMethodService { if (mInlineSuggestionSession != null) { mInlineSuggestionSession.invalidateSession(); } - mInlineSuggestionSession = new InlineSuggestionSession(componentName, callback, - this::getEditorInfoPackageName, this::onCreateInlineSuggestionsRequest, + mInlineSuggestionSession = new InlineSuggestionSession(requestInfo.getComponentName(), + callback, this::getEditorInfoPackageName, + () -> onCreateInlineSuggestionsRequest(requestInfo.getUiExtras()), this::getHostInputToken, this::onInlineSuggestionsResponse); } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index ea26edef10d3..62eff4522d70 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1279,7 +1279,8 @@ public class ConnectivityManager { @UnsupportedAppUsage public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { try { - return mService.getDefaultNetworkCapabilitiesForUser(userId); + return mService.getDefaultNetworkCapabilitiesForUser( + userId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1361,7 +1362,7 @@ public class ConnectivityManager { @Nullable public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) { try { - return mService.getNetworkCapabilities(network); + return mService.getNetworkCapabilities(network, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4039,10 +4040,9 @@ public class ConnectivityManager { @NonNull PendingIntent operation) { printStackTrace(); checkPendingIntentNotNull(operation); - final String callingPackageName = mContext.getOpPackageName(); try { mService.pendingRequestForNetwork( - request.networkCapabilities, operation, callingPackageName); + request.networkCapabilities, operation, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { @@ -4154,10 +4154,9 @@ public class ConnectivityManager { @NonNull PendingIntent operation) { printStackTrace(); checkPendingIntentNotNull(operation); - final String callingPackageName = mContext.getOpPackageName(); try { mService.pendingListenForNetwork( - request.networkCapabilities, operation, callingPackageName); + request.networkCapabilities, operation, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 1c7628f6ad0a..d84d05d522c2 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -60,7 +60,8 @@ interface IConnectivityManager NetworkInfo[] getAllNetworkInfo(); Network getNetworkForType(int networkType); Network[] getAllNetworks(); - NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId); + NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser( + int userId, String callingPackageName); boolean isNetworkSupported(int networkType); @@ -69,7 +70,7 @@ interface IConnectivityManager LinkProperties getLinkPropertiesForType(int networkType); LinkProperties getLinkProperties(in Network network); - NetworkCapabilities getNetworkCapabilities(in Network network); + NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName); @UnsupportedAppUsage NetworkState[] getAllNetworkState(); diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java index 42b4da14d879..f19a3410d673 100644 --- a/core/java/android/net/Ikev2VpnProfile.java +++ b/core/java/android/net/Ikev2VpnProfile.java @@ -25,7 +25,10 @@ import static com.android.internal.util.Preconditions.checkStringNotEmpty; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Process; import android.security.Credentials; +import android.security.KeyStore; +import android.security.keystore.AndroidKeyStoreProvider; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.net.VpnProfile; @@ -59,6 +62,11 @@ import java.util.Objects; * Exchange, Version 2 (IKEv2)</a> */ public final class Ikev2VpnProfile extends PlatformVpnProfile { + /** Prefix for when a Private Key is an alias to look for in KeyStore @hide */ + public static final String PREFIX_KEYSTORE_ALIAS = "KEYSTORE_ALIAS:"; + /** Prefix for when a Private Key is stored directly in the profile @hide */ + public static final String PREFIX_INLINE = "INLINE:"; + private static final String MISSING_PARAM_MSG_TMPL = "Required parameter was not provided: %s"; private static final String EMPTY_CERT = ""; @@ -339,7 +347,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { break; case TYPE_IKEV2_IPSEC_RSA: profile.ipsecUserCert = certificateToPemString(mUserCert); - profile.ipsecSecret = encodeForIpsecSecret(mRsaPrivateKey.getEncoded()); + profile.ipsecSecret = + PREFIX_INLINE + encodeForIpsecSecret(mRsaPrivateKey.getEncoded()); profile.ipsecCaCert = mServerRootCaCert == null ? "" : certificateToPemString(mServerRootCaCert); break; @@ -360,6 +369,22 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { @NonNull public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile) throws IOException, GeneralSecurityException { + return fromVpnProfile(profile, null); + } + + /** + * Builds the Ikev2VpnProfile from the given profile. + * + * @param profile the source VpnProfile to build from + * @param keyStore the Android Keystore instance to use to retrieve the private key, or null if + * the private key is PEM-encoded into the profile. + * @return The IKEv2/IPsec VPN profile + * @hide + */ + @NonNull + public static Ikev2VpnProfile fromVpnProfile( + @NonNull VpnProfile profile, @Nullable KeyStore keyStore) + throws IOException, GeneralSecurityException { final Builder builder = new Builder(profile.server, profile.ipsecIdentifier); builder.setProxy(profile.proxy); builder.setAllowedAlgorithms(profile.getAllowedAlgorithms()); @@ -378,8 +403,21 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { builder.setAuthPsk(decodeFromIpsecSecret(profile.ipsecSecret)); break; case TYPE_IKEV2_IPSEC_RSA: + final PrivateKey key; + if (profile.ipsecSecret.startsWith(PREFIX_KEYSTORE_ALIAS)) { + Objects.requireNonNull(keyStore, "Missing Keystore for aliased PrivateKey"); + + final String alias = + profile.ipsecSecret.substring(PREFIX_KEYSTORE_ALIAS.length()); + key = AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore( + keyStore, alias, Process.myUid()); + } else if (profile.ipsecSecret.startsWith(PREFIX_INLINE)) { + key = getPrivateKey(profile.ipsecSecret.substring(PREFIX_INLINE.length())); + } else { + throw new IllegalArgumentException("Invalid RSA private key prefix"); + } + final X509Certificate userCert = certificateFromPemString(profile.ipsecUserCert); - final PrivateKey key = getPrivateKey(profile.ipsecSecret); final X509Certificate serverRootCa = certificateFromPemString(profile.ipsecCaCert); builder.setAuthDigitalSignature(userCert, key, serverRootCa); break; @@ -391,6 +429,39 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { } /** + * Validates that the VpnProfile is acceptable for the purposes of an Ikev2VpnProfile. + * + * @hide + */ + public static boolean isValidVpnProfile(@NonNull VpnProfile profile) { + if (profile.server.isEmpty() || profile.ipsecIdentifier.isEmpty()) { + return false; + } + + switch (profile.type) { + case TYPE_IKEV2_IPSEC_USER_PASS: + if (profile.username.isEmpty() || profile.password.isEmpty()) { + return false; + } + break; + case TYPE_IKEV2_IPSEC_PSK: + if (profile.ipsecSecret.isEmpty()) { + return false; + } + break; + case TYPE_IKEV2_IPSEC_RSA: + if (profile.ipsecSecret.isEmpty() || profile.ipsecUserCert.isEmpty()) { + return false; + } + break; + default: + return false; + } + + return true; + } + + /** * Converts a X509 Certificate to a PEM-formatted string. * * <p>Must be public due to runtime-package restrictions. @@ -432,7 +503,6 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { /** @hide */ @NonNull - @VisibleForTesting(visibility = Visibility.PRIVATE) public static String encodeForIpsecSecret(@NonNull byte[] secret) { checkNotNull(secret, MISSING_PARAM_MSG_TMPL, "secret"); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index f8b51dd9906b..83f99802b85f 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -830,6 +830,23 @@ public final class NetworkCapabilities implements Parcelable { * <p>This field keeps track of the UID of the app that created this network and is in charge of * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running * VPN, or Carrier Service app managing a cellular data connection. + * + * <p>For NetworkCapability instances being sent from ConnectivityService, this value MUST be + * reset to Process.INVALID_UID unless all the following conditions are met: + * + * <ol> + * <li>The destination app is the network owner + * <li>The destination app has the ACCESS_FINE_LOCATION permission granted + * <li>The user's location toggle is on + * </ol> + * + * This is because the owner UID is location-sensitive. The apps that request a network could + * know where the device is if they can tell for sure the system has connected to the network + * they requested. + * + * <p>This is populated by the network agents and for the NetworkCapabilities instance sent by + * an app to the System Server, the value MUST be reset to Process.INVALID_UID by the system + * server. */ private int mOwnerUid = Process.INVALID_UID; @@ -842,7 +859,16 @@ public final class NetworkCapabilities implements Parcelable { } /** - * Retrieves the UID of the owner app. + * Retrieves the UID of the app that owns this network. + * + * <p>For user privacy reasons, this field will only be populated if: + * + * <ol> + * <li>The calling app is the network owner + * <li>The calling app has the ACCESS_FINE_LOCATION permission granted + * <li>The user's location toggle is on + * </ol> + * */ public int getOwnerUid() { return mOwnerUid; @@ -880,8 +906,9 @@ public final class NetworkCapabilities implements Parcelable { * @param administratorUids the UIDs to be set as administrators of this Network. * @hide */ + @NonNull @SystemApi - public @NonNull NetworkCapabilities setAdministratorUids( + public NetworkCapabilities setAdministratorUids( @NonNull final List<Integer> administratorUids) { mAdministratorUids.clear(); mAdministratorUids.addAll(administratorUids); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 6d1f646f943b..84fd58063d39 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -33,8 +33,8 @@ import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; import android.app.ActivityManager; -import android.app.admin.DevicePolicyManager; import android.app.PropertyInvalidatedCache; +import android.app.admin.DevicePolicyManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; @@ -151,12 +151,23 @@ public class UserManager { public static final int QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED = 0x1; /** + * Flag passed to {@link #requestQuietModeEnabled} to request disabling quiet mode without + * asking for credentials. This is used when managed profile password is forgotten. It starts + * the user in locked state so that a direct boot aware DPC could reset the password. + * Should not be used together with + * {@link #QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED} or an exception will be thrown. + * @hide + */ + public static final int QUIET_MODE_DISABLE_DONT_ASK_CREDENTIAL = 0x2; + + /** * List of flags available for the {@link #requestQuietModeEnabled} method. * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "QUIET_MODE_" }, value = { - QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED }) + QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED, + QUIET_MODE_DISABLE_DONT_ASK_CREDENTIAL}) public @interface QuietModeFlag {} /** @@ -3521,12 +3532,13 @@ public class UserManager { boolean enableQuietMode, @NonNull UserHandle userHandle, IntentSender target) { return requestQuietModeEnabled(enableQuietMode, userHandle, target, 0); } + /** * Similar to {@link #requestQuietModeEnabled(boolean, UserHandle)}, except you can specify * a target to start when user is unlocked. If {@code target} is specified, caller must have * the {@link android.Manifest.permission#MANAGE_USERS} permission. * - * @see {@link #requestQuietModeEnabled(boolean, UserHandle)} + * @see #requestQuietModeEnabled(boolean, UserHandle) * @hide */ public boolean requestQuietModeEnabled( diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java index f4e1f967dca8..dea495bf9327 100644 --- a/core/java/android/os/incremental/IncrementalStorage.java +++ b/core/java/android/os/incremental/IncrementalStorage.java @@ -434,6 +434,11 @@ public final class IncrementalStorage { signature = V4Signature.readFrom(input); } + if (!signature.isVersionSupported()) { + throw new IOException("v4 signature version " + signature.version + + " is not supported"); + } + final byte[] rootHash = signature.verityRootHash; final byte[] additionalData = signature.v3Digest; final byte[] pkcs7Signature = signature.pkcs7SignatureBlock; diff --git a/core/java/android/os/incremental/V4Signature.java b/core/java/android/os/incremental/V4Signature.java index 6516917afd9d..17adfc8a05d9 100644 --- a/core/java/android/os/incremental/V4Signature.java +++ b/core/java/android/os/incremental/V4Signature.java @@ -31,7 +31,9 @@ import java.io.IOException; */ public class V4Signature { public static final String EXT = ".idsig"; + public static final int SUPPORTED_VERSION = 1; + public final int version; public final byte[] verityRootHash; public final byte[] v3Digest; public final byte[] pkcs7SignatureBlock; @@ -71,20 +73,27 @@ public class V4Signature { } } + boolean isVersionSupported() { + return this.version == SUPPORTED_VERSION; + } + static V4Signature readFrom(DataInputStream stream) throws IOException { + final int version = stream.readInt(); byte[] verityRootHash = readBytes(stream); byte[] v3Digest = readBytes(stream); byte[] pkcs7SignatureBlock = readBytes(stream); - return new V4Signature(verityRootHash, v3Digest, pkcs7SignatureBlock); + return new V4Signature(version, verityRootHash, v3Digest, pkcs7SignatureBlock); } - V4Signature(byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) { + V4Signature(int version, byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) { + this.version = version; this.verityRootHash = verityRootHash; this.v3Digest = v3Digest; this.pkcs7SignatureBlock = pkcs7SignatureBlock; } void writeTo(DataOutputStream stream) throws IOException { + stream.writeInt(this.version); writeBytes(stream, this.verityRootHash); writeBytes(stream, this.v3Digest); writeBytes(stream, this.pkcs7SignatureBlock); diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 8d04df0560f5..1454aac66d21 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -29,6 +29,7 @@ import static android.app.AppOpsManager.OP_WRITE_MEDIA_IMAGES; import static android.app.AppOpsManager.OP_WRITE_MEDIA_VIDEO; import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.UserHandle.PER_USER_RANGE; import android.annotation.BytesLong; import android.annotation.CallbackExecutor; @@ -2324,17 +2325,34 @@ public class StorageManager { private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone"; - // Matches AID_MEDIA_RW in android_filesystem_config.h - private static final int QUOTA_PROJECT_ID_MEDIA_NONE = 1023; + // Project IDs below must match android_projectid_config.h + /** + * Default project ID for files on external storage + * + * {@hide} + */ + public static final int PROJECT_ID_EXT_DEFAULT = 1000; - // Matches AID_MEDIA_IMAGE in android_filesystem_config.h - private static final int QUOTA_PROJECT_ID_MEDIA_IMAGE = 1057; + /** + * project ID for audio files on external storage + * + * {@hide} + */ + public static final int PROJECT_ID_EXT_MEDIA_AUDIO = 1001; - // Matches AID_MEDIA_AUDIO in android_filesystem_config.h - private static final int QUOTA_PROJECT_ID_MEDIA_AUDIO = 1055; + /** + * project ID for video files on external storage + * + * {@hide} + */ + public static final int PROJECT_ID_EXT_MEDIA_VIDEO = 1002; - // Matches AID_MEDIA_VIDEO in android_filesystem_config.h - private static final int QUOTA_PROJECT_ID_MEDIA_VIDEO = 1056; + /** + * project ID for image files on external storage + * + * {@hide} + */ + public static final int PROJECT_ID_EXT_MEDIA_IMAGE = 1003; /** * Constant for use with @@ -2388,6 +2406,11 @@ public class StorageManager { private static native boolean setQuotaProjectId(String path, long projectId); + private static long getProjectIdForUser(int userId, int projectId) { + // Much like UserHandle.getUid(), store the user ID in the upper bits + return userId * PER_USER_RANGE + projectId; + } + /** * Let StorageManager know that the quota type for a file on external storage should * be updated. Android tracks quotas for various media types. Consequently, this should be @@ -2417,18 +2440,27 @@ public class StorageManager { @QuotaType int quotaType) throws IOException { long projectId; final String filePath = path.getCanonicalPath(); + final StorageVolume volume = getStorageVolume(path); + if (volume == null) { + throw new IllegalStateException("Failed to update quota type for " + filePath); + } + + final int userId = volume.getOwner().getIdentifier(); + if (userId < 0) { + throw new IllegalStateException("Failed to update quota type for " + filePath); + } switch (quotaType) { case QUOTA_TYPE_MEDIA_NONE: - projectId = QUOTA_PROJECT_ID_MEDIA_NONE; + projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_DEFAULT); break; case QUOTA_TYPE_MEDIA_AUDIO: - projectId = QUOTA_PROJECT_ID_MEDIA_AUDIO; + projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_AUDIO); break; case QUOTA_TYPE_MEDIA_VIDEO: - projectId = QUOTA_PROJECT_ID_MEDIA_VIDEO; + projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_VIDEO); break; case QUOTA_TYPE_MEDIA_IMAGE: - projectId = QUOTA_PROJECT_ID_MEDIA_IMAGE; + projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_IMAGE); break; default: throw new IllegalArgumentException("Invalid quota type: " + quotaType); diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index 4bd31f8b0b3f..a2def7fff2d2 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IVold; +import java.util.Set; + /** * Mount service local interface. * @@ -98,6 +100,12 @@ public abstract class StorageManagerInternal { } /** + * Check if fuse is running in target user, if it's running then setup its obb directories. + * TODO: System server should store a list of active pids that obb is not mounted and use it. + */ + public abstract void prepareObbDirs(int userId, Set<String> packageList, String processName); + + /** * Add a listener to listen to reset event in StorageManagerService. * * @param listener The listener that will be notified on reset events. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4523acb0eb26..b9abdf83e260 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8760,6 +8760,13 @@ public final class Settings { "location_permissions_upgrade_to_q_mode"; /** + * Whether or not the system Auto Revoke feature is disabled. + * @hide + */ + @SystemApi + public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled"; + + /** * Map of android.theme.customization.* categories to the enabled overlay package for that * category, formatted as a serialized {@link org.json.JSONObject}. If there is no * corresponding package included for a category, then all overlay packages in that @@ -11502,6 +11509,7 @@ public final class Settings { * exempted_sync_duration (long) * system_interaction_duration (long) * initial_foreground_service_start_duration (long) + * cross_profile_apps_share_standby_buckets (boolean) * </pre> * * <p> @@ -14318,7 +14326,6 @@ public final class Settings { * * @hide */ - @SystemApi @RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS) public static void registerMonitorCallback(@NonNull ContentResolver resolver, @NonNull RemoteCallback callback) { diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java index 4aafb6302ab4..29069e7035f9 100644 --- a/core/java/android/service/autofill/InlineSuggestionRenderService.java +++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java @@ -25,6 +25,7 @@ import android.app.Service; import android.app.slice.Slice; import android.content.Intent; import android.graphics.PixelFormat; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -118,6 +119,14 @@ public abstract class InlineSuggestionRenderService extends Service { } /** + * Returns the metadata about the renderer. Returns {@code null} if no metadata is provided. + */ + @Nullable + public Bundle onGetInlineSuggestionsRendererInfo() { + return null; + } + + /** * Renders the slice into a view. */ @Nullable diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java index de4c056e5501..cb20db90f549 100644 --- a/core/java/android/service/controls/ControlsProviderService.java +++ b/core/java/android/service/controls/ControlsProviderService.java @@ -16,6 +16,7 @@ package android.service.controls; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.Service; @@ -34,7 +35,6 @@ import android.util.Log; import com.android.internal.util.Preconditions; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Flow.Publisher; @@ -70,25 +70,48 @@ public abstract class ControlsProviderService extends Service { * Retrieve all available controls, using the stateless builder * {@link Control.StatelessBuilder} to build each Control, then use the * provided consumer to callback to the call originator. + * + * @deprecated Removing consumer-based load apis. Use publisherForAllAvailable() instead */ - public abstract void loadAvailableControls(@NonNull Consumer<List<Control>> consumer); + @Deprecated + public void loadAvailableControls(@NonNull Consumer<List<Control>> consumer) { + // pending removal + consumer.accept(Collections.emptyList()); + } + + /** + * Publisher for all available controls + * + * Retrieve all available controls. Use the stateless builder {@link Control.StatelessBuilder} + * to build each Control. Call {@link Subscriber#onComplete} when done loading all unique + * controls, or {@link Subscriber#onError} for error scenarios. Duplicate Controls will + * replace the original. + */ + @Nullable + public Publisher<Control> publisherForAllAvailable() { + // will be abstract and @nonnull when consumers are removed + return null; + } /** - * (Optional) The service may be asked to provide a small number of recommended controls, in + * (Optional) Publisher for suggested controls + * + * The service may be asked to provide a small number of recommended controls, in * order to suggest some controls to the user for favoriting. The controls shall be built using - * the stateless builder {@link Control.StatelessBuilder}, followed by an invocation to the - * provided consumer to callback to the call originator. If the number of controls - * is greater than maxNumber, the list will be truncated. + * the stateless builder {@link Control.StatelessBuilder}. The number of controls requested + * through {@link Subscription#request} will be limited. Call {@link Subscriber#onComplete} + * when done, or {@link Subscriber#onError} for error scenarios. */ - public void loadSuggestedControls(int maxNumber, @NonNull Consumer<List<Control>> consumer) { - // Override to change the default behavior - consumer.accept(Collections.emptyList()); + @Nullable + public Publisher<Control> publisherForSuggested() { + return null; } /** - * Return a valid Publisher for the given controlIds. This publisher will be asked - * to provide updates for the given list of controlIds as long as the Subscription - * is valid. + * Return a valid Publisher for the given controlIds. This publisher will be asked to provide + * updates for the given list of controlIds as long as the {@link Subscription} is valid. + * Calls to {@link Subscriber#onComplete} will not be expected. Instead, wait for the call from + * {@link Subscription#cancel} to indicate that updates are no longer required. */ @NonNull public abstract Publisher<Control> publisherFor(@NonNull List<String> controlIds); @@ -113,13 +136,13 @@ public abstract class ControlsProviderService extends Service { mToken = bundle.getBinder(CALLBACK_TOKEN); return new IControlsProvider.Stub() { - public void load(IControlsLoadCallback cb) { - mHandler.obtainMessage(RequestHandler.MSG_LOAD, cb).sendToTarget(); + public void load(IControlsSubscriber subscriber) { + mHandler.obtainMessage(RequestHandler.MSG_LOAD, subscriber).sendToTarget(); } - public void loadSuggested(int maxNumber, IControlsLoadCallback cb) { - LoadMessage msg = new LoadMessage(maxNumber, cb); - mHandler.obtainMessage(RequestHandler.MSG_LOAD_SUGGESTED, msg).sendToTarget(); + public void loadSuggested(IControlsSubscriber subscriber) { + mHandler.obtainMessage(RequestHandler.MSG_LOAD_SUGGESTED, subscriber) + .sendToTarget(); } public void subscribe(List<String> controlIds, @@ -148,73 +171,56 @@ public abstract class ControlsProviderService extends Service { private static final int MSG_ACTION = 3; private static final int MSG_LOAD_SUGGESTED = 4; - /** - * This the maximum number of controls that can be loaded via - * {@link ControlsProviderService#loadAvailablecontrols}. Anything over this number - * will be truncated. - */ - private static final int MAX_NUMBER_OF_CONTROLS_ALLOWED = 1000; - RequestHandler(Looper looper) { super(looper); } public void handleMessage(Message msg) { switch(msg.what) { - case MSG_LOAD: - final IControlsLoadCallback cb = (IControlsLoadCallback) msg.obj; - ControlsProviderService.this.loadAvailableControls(consumerFor( - MAX_NUMBER_OF_CONTROLS_ALLOWED, cb)); + case MSG_LOAD: { + final IControlsSubscriber cs = (IControlsSubscriber) msg.obj; + final SubscriberProxy proxy = new SubscriberProxy(true, mToken, cs); + + Publisher<Control> publisher = + ControlsProviderService.this.publisherForAllAvailable(); + if (publisher == null) { + ControlsProviderService.this.loadAvailableControls(consumerFor(proxy)); + } else { + publisher.subscribe(proxy); + } break; + } + + case MSG_LOAD_SUGGESTED: { + final IControlsSubscriber cs = (IControlsSubscriber) msg.obj; + final SubscriberProxy proxy = new SubscriberProxy(true, mToken, cs); - case MSG_LOAD_SUGGESTED: - final LoadMessage lMsg = (LoadMessage) msg.obj; - ControlsProviderService.this.loadSuggestedControls(lMsg.mMaxNumber, - consumerFor(lMsg.mMaxNumber, lMsg.mCb)); + Publisher<Control> publisher = + ControlsProviderService.this.publisherForSuggested(); + if (publisher == null) { + Log.i(TAG, "No publisher provided for suggested controls"); + proxy.onComplete(); + } else { + publisher.subscribe(proxy); + } break; + } - case MSG_SUBSCRIBE: + case MSG_SUBSCRIBE: { final SubscribeMessage sMsg = (SubscribeMessage) msg.obj; - final IControlsSubscriber cs = sMsg.mSubscriber; - Subscriber<Control> s = new Subscriber<Control>() { - public void onSubscribe(Subscription subscription) { - try { - cs.onSubscribe(mToken, new SubscriptionAdapter(subscription)); - } catch (RemoteException ex) { - ex.rethrowAsRuntimeException(); - } - } - public void onNext(@NonNull Control statefulControl) { - Preconditions.checkNotNull(statefulControl); - try { - cs.onNext(mToken, statefulControl); - } catch (RemoteException ex) { - ex.rethrowAsRuntimeException(); - } - } - public void onError(Throwable t) { - try { - cs.onError(mToken, t.toString()); - } catch (RemoteException ex) { - ex.rethrowAsRuntimeException(); - } - } - public void onComplete() { - try { - cs.onComplete(mToken); - } catch (RemoteException ex) { - ex.rethrowAsRuntimeException(); - } - } - }; - ControlsProviderService.this.publisherFor(sMsg.mControlIds).subscribe(s); + final SubscriberProxy proxy = new SubscriberProxy(false, mToken, + sMsg.mSubscriber); + + ControlsProviderService.this.publisherFor(sMsg.mControlIds).subscribe(proxy); break; + } - case MSG_ACTION: + case MSG_ACTION: { final ActionMessage aMsg = (ActionMessage) msg.obj; ControlsProviderService.this.performControlAction(aMsg.mControlId, aMsg.mAction, consumerFor(aMsg.mControlId, aMsg.mCb)); break; + } } } @@ -234,39 +240,88 @@ public abstract class ControlsProviderService extends Service { }; } - private Consumer<List<Control>> consumerFor(int maxNumber, IControlsLoadCallback cb) { - return (@NonNull List<Control> controls) -> { + /** + * Method will be removed during migration to publisher + */ + private Consumer<List<Control>> consumerFor(final Subscriber<Control> subscriber) { + return (@NonNull final List<Control> controls) -> { Preconditions.checkNotNull(controls); - if (controls.size() > maxNumber) { - Log.w(TAG, "Too many controls. Provided: " + controls.size() + ", Max allowed: " - + maxNumber + ". Truncating the list."); - controls = controls.subList(0, maxNumber); - } - List<Control> list = new ArrayList<>(); - for (Control control: controls) { - if (control == null) { - Log.e(TAG, "onLoad: null control."); - } - if (isStatelessControl(control)) { - list.add(control); - } else { - Log.w(TAG, "onLoad: control is not stateless."); - list.add(new Control.StatelessBuilder(control).build()); - } - } - try { - cb.accept(mToken, list); - } catch (RemoteException ex) { - ex.rethrowAsRuntimeException(); - } + subscriber.onSubscribe(new Subscription() { + public void request(long n) { + for (Control control: controls) { + Control c; + if (control == null) { + Log.e(TAG, "onLoad: null control."); + } + if (isStatelessControl(control)) { + c = control; + } else { + Log.w(TAG, "onLoad: control is not stateless."); + c = new Control.StatelessBuilder(control).build(); + } + + subscriber.onNext(c); + } + subscriber.onComplete(); + } + + public void cancel() {} + }); }; } + } + + private static boolean isStatelessControl(Control control) { + return (control.getStatus() == Control.STATUS_UNKNOWN + && control.getControlTemplate().getTemplateType() == ControlTemplate.TYPE_NONE + && TextUtils.isEmpty(control.getStatusText())); + } + + private static class SubscriberProxy implements Subscriber<Control> { + private IBinder mToken; + private IControlsSubscriber mCs; + private boolean mEnforceStateless; - private boolean isStatelessControl(Control control) { - return (control.getStatus() == Control.STATUS_UNKNOWN - && control.getControlTemplate().getTemplateType() == ControlTemplate.TYPE_NONE - && TextUtils.isEmpty(control.getStatusText())); + SubscriberProxy(boolean enforceStateless, IBinder token, IControlsSubscriber cs) { + mEnforceStateless = enforceStateless; + mToken = token; + mCs = cs; + } + + public void onSubscribe(Subscription subscription) { + try { + mCs.onSubscribe(mToken, new SubscriptionAdapter(subscription)); + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } + } + public void onNext(@NonNull Control control) { + Preconditions.checkNotNull(control); + try { + if (mEnforceStateless && !isStatelessControl(control)) { + Log.w(TAG, "onNext(): control is not stateless. Use the " + + "Control.StatelessBuilder() to build the control."); + control = new Control.StatelessBuilder(control).build(); + } + mCs.onNext(mToken, control); + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } + } + public void onError(Throwable t) { + try { + mCs.onError(mToken, t.toString()); + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } + } + public void onComplete() { + try { + mCs.onComplete(mToken); + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } } } @@ -307,14 +362,4 @@ public abstract class ControlsProviderService extends Service { this.mSubscriber = subscriber; } } - - private static class LoadMessage { - final int mMaxNumber; - final IControlsLoadCallback mCb; - - LoadMessage(int maxNumber, IControlsLoadCallback cb) { - this.mMaxNumber = maxNumber; - this.mCb = cb; - } - } } diff --git a/core/java/android/service/controls/IControlsProvider.aidl b/core/java/android/service/controls/IControlsProvider.aidl index 4375fbb289db..0cb06b4a5cb6 100644 --- a/core/java/android/service/controls/IControlsProvider.aidl +++ b/core/java/android/service/controls/IControlsProvider.aidl @@ -17,7 +17,6 @@ package android.service.controls; import android.service.controls.IControlsActionCallback; -import android.service.controls.IControlsLoadCallback; import android.service.controls.IControlsSubscriber; import android.service.controls.actions.ControlActionWrapper; @@ -25,9 +24,9 @@ import android.service.controls.actions.ControlActionWrapper; * @hide */ oneway interface IControlsProvider { - void load(IControlsLoadCallback cb); + void load(IControlsSubscriber subscriber); - void loadSuggested(int maxNumber, IControlsLoadCallback cb); + void loadSuggested(IControlsSubscriber subscriber); void subscribe(in List<String> controlIds, IControlsSubscriber subscriber); diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java index 73e17a61d17f..55542d898784 100644 --- a/core/java/android/util/LongSparseArray.java +++ b/core/java/android/util/LongSparseArray.java @@ -16,15 +16,18 @@ package android.util; +import android.annotation.NonNull; import android.os.Parcel; import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.LongObjPredicate; import libcore.util.EmptyArray; import java.util.Arrays; +import java.util.Objects; /** * SparseArray mapping longs to Objects. Unlike a normal array of Objects, @@ -145,6 +148,18 @@ public class LongSparseArray<E> implements Cloneable { delete(key); } + /** @hide */ + @SuppressWarnings("unchecked") + public void removeIf(@NonNull LongObjPredicate<? super E> filter) { + Objects.requireNonNull(filter); + for (int i = 0; i < mSize; ++i) { + if (mValues[i] != DELETED && filter.test(mKeys[i], (E) mValues[i])) { + mValues[i] = DELETED; + mGarbage = true; + } + } + } + /** * Removes the mapping at the specified index. * diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index deff79d5486a..73707ca889dd 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1586,6 +1586,19 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall info.addChild(wrapper.getLeashToken()); } + @Override + public int getImportantForAccessibility() { + final int mode = super.getImportantForAccessibility(); + // If developers explicitly set the important mode for it, don't change the mode. + // Only change the mode to important when this SurfaceView isn't explicitly set and has + // an embedded hierarchy. + if (mRemoteAccessibilityEmbeddedConnection == null + || mode != IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + return mode; + } + return IMPORTANT_FOR_ACCESSIBILITY_YES; + } + private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) { final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection(); final RemoteAccessibilityEmbeddedConnection wrapper = diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4c7307ee5b8c..11ab5724d927 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13442,8 +13442,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #getImportantForAccessibility() */ public boolean isImportantForAccessibility() { - final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) - >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; + final int mode = getImportantForAccessibility(); if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { return false; diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java index cf34b0bad78d..f406be9ebac7 100644 --- a/core/java/android/view/WindowContainerTransaction.java +++ b/core/java/android/view/WindowContainerTransaction.java @@ -26,6 +26,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; +import android.view.SurfaceControl; import java.util.ArrayList; import java.util.List; @@ -77,8 +78,28 @@ public class WindowContainerTransaction implements Parcelable { public WindowContainerTransaction scheduleFinishEnterPip(IWindowContainer container, Rect bounds) { Change chg = getOrCreateChange(container.asBinder()); - chg.mSchedulePipCallback = true; chg.mPinnedBounds = new Rect(bounds); + chg.mChangeMask |= Change.CHANGE_PIP_CALLBACK; + + return this; + } + + /** + * Send a SurfaceControl transaction to the server, which the server will apply in sync with + * the next bounds change. As this uses deferred transaction and not BLAST it is only + * able to sync with a single window, and the first visible window in this hierarchy of type + * BASE_APPLICATION to resize will be used. If there are bound changes included in this + * WindowContainer transaction (from setBounds or scheduleFinishEnterPip), the SurfaceControl + * transaction will be synced with those bounds. If there are no changes, then + * the SurfaceControl transaction will be synced with the next bounds change. This means + * that you can call this, apply the WindowContainer transaction, and then later call + * dismissPip() to achieve synchronization. + */ + public WindowContainerTransaction setBoundsChangeTransaction(IWindowContainer container, + SurfaceControl.Transaction t) { + Change chg = getOrCreateChange(container.asBinder()); + chg.mBoundsChangeTransaction = t; + chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION; return this; } @@ -174,6 +195,8 @@ public class WindowContainerTransaction implements Parcelable { */ public static class Change implements Parcelable { public static final int CHANGE_FOCUSABLE = 1; + public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1; + public static final int CHANGE_PIP_CALLBACK = 1 << 2; private final Configuration mConfiguration = new Configuration(); private boolean mFocusable = true; @@ -181,8 +204,8 @@ public class WindowContainerTransaction implements Parcelable { private @ActivityInfo.Config int mConfigSetMask = 0; private @WindowConfiguration.WindowConfig int mWindowSetMask = 0; - private boolean mSchedulePipCallback = false; private Rect mPinnedBounds = null; + private SurfaceControl.Transaction mBoundsChangeTransaction = null; public Change() {} @@ -192,11 +215,14 @@ public class WindowContainerTransaction implements Parcelable { mChangeMask = in.readInt(); mConfigSetMask = in.readInt(); mWindowSetMask = in.readInt(); - mSchedulePipCallback = (in.readInt() != 0); - if (mSchedulePipCallback ) { + if ((mChangeMask & Change.CHANGE_PIP_CALLBACK) != 0) { mPinnedBounds = new Rect(); mPinnedBounds.readFromParcel(in); } + if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION) != 0) { + mBoundsChangeTransaction = + SurfaceControl.Transaction.CREATOR.createFromParcel(in); + } } public Configuration getConfiguration() { @@ -233,6 +259,10 @@ public class WindowContainerTransaction implements Parcelable { return mPinnedBounds; } + public SurfaceControl.Transaction getBoundsChangeTransaction() { + return mBoundsChangeTransaction; + } + @Override public String toString() { final boolean changesBounds = @@ -264,10 +294,12 @@ public class WindowContainerTransaction implements Parcelable { dest.writeInt(mConfigSetMask); dest.writeInt(mWindowSetMask); - dest.writeInt(mSchedulePipCallback ? 1 : 0); - if (mSchedulePipCallback ) { + if (mPinnedBounds != null) { mPinnedBounds.writeToParcel(dest, flags); } + if (mBoundsChangeTransaction != null) { + mBoundsChangeTransaction.writeToParcel(dest, flags); + } } @Override diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS index 265674a74b7e..c6f42f719caa 100644 --- a/core/java/android/view/accessibility/OWNERS +++ b/core/java/android/view/accessibility/OWNERS @@ -1,3 +1,4 @@ svetoslavganov@google.com pweaver@google.com rhedjao@google.com +qasid@google.com diff --git a/core/java/android/view/inline/InlinePresentationSpec.java b/core/java/android/view/inline/InlinePresentationSpec.java index 8bda339bea16..3cc04b8c5b86 100644 --- a/core/java/android/view/inline/InlinePresentationSpec.java +++ b/core/java/android/view/inline/InlinePresentationSpec.java @@ -18,6 +18,7 @@ package android.view.inline; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Bundle; import android.os.Parcelable; import android.util.Size; @@ -40,15 +41,13 @@ public final class InlinePresentationSpec implements Parcelable { private final Size mMaxSize; /** - * The fully qualified resource name of the UI style resource identifier, defaults to {@code - * null}. - * - * <p> The value can be obtained by calling {@code Resources#getResourceName(int)}. + * The extras encoding the UI style information. Defaults to {@code null} in which case the + * default system UI style will be used. */ @Nullable - private final String mStyle; + private final Bundle mStyle; - private static String defaultStyle() { + private static Bundle defaultStyle() { return null; } @@ -76,7 +75,7 @@ public final class InlinePresentationSpec implements Parcelable { /* package-private */ InlinePresentationSpec( @NonNull Size minSize, @NonNull Size maxSize, - @Nullable String style) { + @Nullable Bundle style) { this.mMinSize = minSize; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mMinSize); @@ -105,13 +104,11 @@ public final class InlinePresentationSpec implements Parcelable { } /** - * The fully qualified resource name of the UI style resource identifier, defaults to {@code - * null}. - * - * <p> The value can be obtained by calling {@code Resources#getResourceName(int)}. + * The extras encoding the UI style information. Defaults to null in which case the default + * system UI style will be used. */ @DataClass.Generated.Member - public @Nullable String getStyle() { + public @Nullable Bundle getStyle() { return mStyle; } @@ -170,7 +167,7 @@ public final class InlinePresentationSpec implements Parcelable { dest.writeByte(flg); dest.writeSize(mMinSize); dest.writeSize(mMaxSize); - if (mStyle != null) dest.writeString(mStyle); + if (mStyle != null) dest.writeBundle(mStyle); } @Override @@ -187,7 +184,7 @@ public final class InlinePresentationSpec implements Parcelable { byte flg = in.readByte(); Size minSize = (Size) in.readSize(); Size maxSize = (Size) in.readSize(); - String style = (flg & 0x4) == 0 ? null : in.readString(); + Bundle style = (flg & 0x4) == 0 ? null : in.readBundle(); this.mMinSize = minSize; com.android.internal.util.AnnotationValidations.validate( @@ -223,7 +220,7 @@ public final class InlinePresentationSpec implements Parcelable { private @NonNull Size mMinSize; private @NonNull Size mMaxSize; - private @Nullable String mStyle; + private @Nullable Bundle mStyle; private long mBuilderFieldsSet = 0L; @@ -247,13 +244,11 @@ public final class InlinePresentationSpec implements Parcelable { } /** - * The fully qualified resource name of the UI style resource identifier, defaults to {@code - * null}. - * - * <p> The value can be obtained by calling {@code Resources#getResourceName(int)}. + * The extras encoding the UI style information. Defaults to null in which case the default + * system UI style will be used. */ @DataClass.Generated.Member - public @NonNull Builder setStyle(@Nullable String value) { + public @NonNull Builder setStyle(@Nullable Bundle value) { checkNotUsed(); mBuilderFieldsSet |= 0x4; mStyle = value; @@ -284,10 +279,10 @@ public final class InlinePresentationSpec implements Parcelable { } @DataClass.Generated( - time = 1581736227796L, + time = 1582078731418L, codegenVersion = "1.0.14", sourceFile = "frameworks/base/core/java/android/view/inline/InlinePresentationSpec.java", - inputSignatures = "private final @android.annotation.NonNull android.util.Size mMinSize\nprivate final @android.annotation.NonNull android.util.Size mMaxSize\nprivate final @android.annotation.Nullable java.lang.String mStyle\nprivate static java.lang.String defaultStyle()\nclass InlinePresentationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nclass BaseBuilder extends java.lang.Object implements []") + inputSignatures = "private final @android.annotation.NonNull android.util.Size mMinSize\nprivate final @android.annotation.NonNull android.util.Size mMaxSize\nprivate final @android.annotation.Nullable android.os.Bundle mStyle\nprivate static android.os.Bundle defaultStyle()\nclass InlinePresentationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated private void __metadata() {} diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index 91e15c1949b6..71c9e33d0eee 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -21,17 +21,16 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.content.ComponentName; import android.inputmethodservice.InputMethodService; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; import android.util.Log; import android.view.View; -import android.view.autofill.AutofillId; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.view.IInlineSuggestionsRequestCallback; +import com.android.internal.view.InlineSuggestionsRequestInfo; /** * The InputMethod interface represents an input method which can generate key @@ -114,14 +113,13 @@ public interface InputMethod { /** * Called to notify the IME that Autofill Frameworks requested an inline suggestions request. * - * @param componentName {@link ComponentName} of current app/activity. - * @param autofillId {@link AutofillId} of currently focused field. + * @param requestInfo information needed to create an {@link InlineSuggestionsRequest}. * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object. * * @hide */ - default void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { + default void onCreateInlineSuggestionsRequest(InlineSuggestionsRequestInfo requestInfo, + IInlineSuggestionsRequestCallback cb) { try { cb.onInlineSuggestionsUnsupported(); } catch (RemoteException e) { diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index dbab81b129a9..39d5f5c396a1 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -93,12 +93,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; @@ -415,16 +410,6 @@ public final class InputMethodManager { int mCursorCandEnd; /** - * Initial startInput with {@link StartInputReason.WINDOW_FOCUS_GAIN} is executed - * in a background thread. Later, if there is an actual startInput it will wait on - * main thread till the background thread completes. - */ - private Future<?> mWindowFocusGainFuture; - - private ExecutorService mStartInputWorker = Executors.newSingleThreadExecutor( - new ImeThreadFactory("StartInputWorker")); - - /** * The instance that has previously been sent to the input method. */ private CursorAnchorInfo mCursorAnchorInfo = null; @@ -612,41 +597,36 @@ public final class InputMethodManager { final boolean forceNewFocus1 = forceNewFocus; final int startInputFlags = getStartInputFlags(focusedView, 0); - if (mWindowFocusGainFuture != null) { - mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */); + final ImeFocusController controller = getFocusController(); + if (controller == null) { + return; } - mWindowFocusGainFuture = mStartInputWorker.submit(() -> { - final ImeFocusController controller = getFocusController(); - if (controller == null) { + if (controller.checkFocus(forceNewFocus1, false)) { + // We need to restart input on the current focus view. This + // should be done in conjunction with telling the system service + // about the window gaining focus, to help make the transition + // smooth. + if (startInput(StartInputReason.WINDOW_FOCUS_GAIN, + focusedView, startInputFlags, softInputMode, windowFlags)) { return; } - if (controller.checkFocus(forceNewFocus1, false)) { - // We need to restart input on the current focus view. This - // should be done in conjunction with telling the system service - // about the window gaining focus, to help make the transition - // smooth. - if (startInput(StartInputReason.WINDOW_FOCUS_GAIN, - focusedView, startInputFlags, softInputMode, windowFlags)) { - return; - } - } + } - synchronized (mH) { - // For some reason we didn't do a startInput + windowFocusGain, so - // we'll just do a window focus gain and call it a day. - try { - if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); - mService.startInputOrWindowGainedFocus( - StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, - focusedView.getWindowToken(), startInputFlags, softInputMode, - windowFlags, - null, null, 0 /* missingMethodFlags */, - mCurRootView.mContext.getApplicationInfo().targetSdkVersion); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + synchronized (mH) { + // For some reason we didn't do a startInput + windowFocusGain, so + // we'll just do a window focus gain and call it a day. + try { + if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); + mService.startInputOrWindowGainedFocus( + StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, + focusedView.getWindowToken(), startInputFlags, softInputMode, + windowFlags, + null, null, 0 /* missingMethodFlags */, + mCurRootView.mContext.getApplicationInfo().targetSdkVersion); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - }); + } } /** @@ -664,10 +644,6 @@ public final class InputMethodManager { */ @Override public void setCurrentRootView(ViewRootImpl rootView) { - if (mWindowFocusGainFuture != null) { - mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */); - mWindowFocusGainFuture = null; - } synchronized (mH) { if (mCurRootView != null) { // Reset the last served view and restart window focus state of the root view. @@ -845,19 +821,16 @@ public final class InputMethodManager { } catch (RemoteException e) { } } - } - // Check focus again in case that "onWindowFocus" is called before - // handling this message. - final View servedView; - synchronized (mH) { - servedView = getServedViewLocked(); - } - if (servedView != null && canStartInput(servedView)) { - if (mCurRootView != null && mCurRootView.getImeFocusController() - .checkFocus(mRestartOnNextWindowFocus, false)) { - final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS - : StartInputReason.DEACTIVATED_BY_IMMS; - mDelegate.startInput(reason, null, 0, 0, 0); + // Check focus again in case that "onWindowFocus" is called before + // handling this message. + final View servedView = getServedViewLocked(); + if (servedView != null && canStartInput(servedView)) { + if (mCurRootView != null && mCurRootView.getImeFocusController() + .checkFocus(mRestartOnNextWindowFocus, false)) { + final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS + : StartInputReason.DEACTIVATED_BY_IMMS; + mDelegate.startInput(reason, null, 0, 0, 0); + } } } return; @@ -1035,6 +1008,13 @@ public final class InputMethodManager { } @Override + public void scheduleStartInputIfNecessary(boolean fullscreen) { + // TODO(b/149859205): See if we can optimize this by having a fused dedicated operation. + mH.obtainMessage(MSG_SET_ACTIVE, 0 /* active */, fullscreen ? 1 : 0).sendToTarget(); + mH.obtainMessage(MSG_SET_ACTIVE, 1 /* active */, fullscreen ? 1 : 0).sendToTarget(); + } + + @Override public void reportFullscreenMode(boolean fullscreen) { mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0) .sendToTarget(); @@ -1430,10 +1410,6 @@ public final class InputMethodManager { */ void clearBindingLocked() { if (DEBUG) Log.v(TAG, "Clearing binding!"); - if (mWindowFocusGainFuture != null) { - mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */); - mWindowFocusGainFuture = null; - } clearConnectionLocked(); setInputChannelLocked(null); mBindSequence = -1; @@ -1826,18 +1802,6 @@ public final class InputMethodManager { boolean startInputInner(@StartInputReason int startInputReason, @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags) { - if (startInputReason != StartInputReason.WINDOW_FOCUS_GAIN - && mWindowFocusGainFuture != null) { - try { - mWindowFocusGainFuture.get(); - } catch (ExecutionException | InterruptedException e) { - // do nothing - } catch (CancellationException e) { - // window no longer has focus. - return true; - } - } - final View view; synchronized (mH) { view = getServedViewLocked(); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 12f245e87da2..13c1f67ef85b 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -83,6 +83,7 @@ import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Log; import android.util.SparseArray; +import android.util.TypedValue; import android.view.ActionMode; import android.view.ActionMode.Callback; import android.view.ContextMenu; @@ -151,9 +152,6 @@ public class Editor { private static final String TAG = "Editor"; private static final boolean DEBUG_UNDO = false; - // Specifies whether to allow starting a cursor drag by dragging anywhere over the text. - @VisibleForTesting - public static boolean FLAG_ENABLE_CURSOR_DRAG = true; // Specifies whether to use the magnifier when pressing the insertion or selection handles. private static final boolean FLAG_USE_MAGNIFIER = true; @@ -387,13 +385,25 @@ public class Editor { private final SuggestionHelper mSuggestionHelper = new SuggestionHelper(); - // Specifies whether the cursor control feature set is enabled. - // This can only be true if the text view is editable. - private boolean mCursorControlEnabled; + private boolean mFlagCursorDragFromAnywhereEnabled; + private boolean mFlagInsertionHandleGesturesEnabled; // Specifies whether the new magnifier (with fish-eye effect) is enabled. private final boolean mNewMagnifierEnabled; + // Line height range in DP for the new magnifier. + static private final int MIN_LINE_HEIGHT_FOR_MAGNIFIER = 20; + static private final int MAX_LINE_HEIGHT_FOR_MAGNIFIER = 32; + // Line height range in pixels for the new magnifier. + // - If the line height is bigger than the max, magnifier should be dismissed. + // - If the line height is smaller than the min, magnifier should apply a bigger zoom factor + // to make sure the text can be seen clearly. + private int mMinLineHeightForMagnifier; + private int mMaxLineHeightForMagnifier; + // The zoom factor initially configured. + // The actual zoom value may changes based on this initial zoom value. + private float mInitialZoom = 1f; + Editor(TextView textView) { mTextView = textView; // Synchronize the filter list, which places the undo input filter at the end. @@ -402,26 +412,43 @@ public class Editor { mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean( com.android.internal.R.bool.config_enableHapticTextHandle); - mCursorControlEnabled = AppGlobals.getIntCoreSetting( - WidgetFlags.KEY_ENABLE_CURSOR_CONTROL , 0) != 0; + mFlagCursorDragFromAnywhereEnabled = AppGlobals.getIntCoreSetting( + WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, + WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT ? 1 : 0) != 0; + mFlagInsertionHandleGesturesEnabled = AppGlobals.getIntCoreSetting( + WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES, + WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT ? 1 : 0) != 0; mNewMagnifierEnabled = AppGlobals.getIntCoreSetting( - WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, 0) != 0; + WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, + WidgetFlags.ENABLE_NEW_MAGNIFIER_DEFAULT ? 1 : 0) != 0; if (TextView.DEBUG_CURSOR) { - logCursor("Editor", "Cursor control is %s.", - mCursorControlEnabled ? "enabled" : "disabled"); + logCursor("Editor", "Cursor drag from anywhere is %s.", + mFlagCursorDragFromAnywhereEnabled ? "enabled" : "disabled"); + logCursor("Editor", "Insertion handle gestures is %s.", + mFlagInsertionHandleGesturesEnabled ? "enabled" : "disabled"); logCursor("Editor", "New magnifier is %s.", mNewMagnifierEnabled ? "enabled" : "disabled"); } } @VisibleForTesting - public void setCursorControlEnabled(boolean enabled) { - mCursorControlEnabled = enabled; + public boolean getFlagCursorDragFromAnywhereEnabled() { + return mFlagCursorDragFromAnywhereEnabled; + } + + @VisibleForTesting + public void setFlagCursorDragFromAnywhereEnabled(boolean enabled) { + mFlagCursorDragFromAnywhereEnabled = enabled; } @VisibleForTesting - public boolean getCursorControlEnabled() { - return mCursorControlEnabled; + public boolean getFlagInsertionHandleGesturesEnabled() { + return mFlagInsertionHandleGesturesEnabled; + } + + @VisibleForTesting + public void setFlagInsertionHandleGesturesEnabled(boolean enabled) { + mFlagInsertionHandleGesturesEnabled = enabled; } // Lazy creates the magnifier animator. @@ -440,12 +467,12 @@ public class Editor { private Magnifier.Builder createBuilderWithInlineMagnifierDefaults() { final Magnifier.Builder params = new Magnifier.Builder(mTextView); - // TODO: supports changing the height/width dynamically because the text height can be - // dynamically changed. float zoom = AppGlobals.getFloatCoreSetting( - WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, 1.5f); + WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, + WidgetFlags.MAGNIFIER_ZOOM_FACTOR_DEFAULT); float aspectRatio = AppGlobals.getFloatCoreSetting( - WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, 5.5f); + WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, + WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT); // Avoid invalid/unsupported values. if (zoom < 1.2f || zoom > 1.8f) { zoom = 1.5f; @@ -454,13 +481,20 @@ public class Editor { aspectRatio = 5.5f; } + mInitialZoom = zoom; + mMinLineHeightForMagnifier = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, MIN_LINE_HEIGHT_FOR_MAGNIFIER, + mTextView.getContext().getResources().getDisplayMetrics()); + mMaxLineHeightForMagnifier = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, MAX_LINE_HEIGHT_FOR_MAGNIFIER, + mTextView.getContext().getResources().getDisplayMetrics()); + final Layout layout = mTextView.getLayout(); final int line = layout.getLineForOffset(mTextView.getSelectionStart()); final int sourceHeight = layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line); - // Slightly increase the height to avoid tooLargeTextForMagnifier() returns true. - int height = (int)(sourceHeight * zoom) + 2; - int width = (int)(aspectRatio * height); + final int height = (int)(sourceHeight * zoom); + final int width = (int)(aspectRatio * Math.max(sourceHeight, mMinLineHeightForMagnifier)); params.setFishEyeStyle() .setSize(width, height) @@ -4902,6 +4936,12 @@ public class Editor { } private boolean tooLargeTextForMagnifier() { + if (mNewMagnifierEnabled) { + Layout layout = mTextView.getLayout(); + final int line = layout.getLineForOffset(getCurrentCursorOffset()); + return layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line) + >= mMaxLineHeightForMagnifier; + } final float magnifierContentHeight = Math.round( mMagnifierAnimator.mMagnifier.getHeight() / mMagnifierAnimator.mMagnifier.getZoom()); @@ -5111,9 +5151,16 @@ public class Editor { int lineRight = (int) layout.getLineRight(line); lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight); + final int lineHeight = + layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line); + float zoom = mInitialZoom; + if (lineHeight < mMinLineHeightForMagnifier) { + zoom = zoom * mMinLineHeightForMagnifier / lineHeight; + } + mMagnifierAnimator.mMagnifier.updateSourceFactors(lineHeight, zoom); mMagnifierAnimator.mMagnifier.show(showPosInView.x, showPosInView.y); } else { - mMagnifierAnimator.show(showPosInView.x, showPosInView.y); + mMagnifierAnimator.show(showPosInView.x, showPosInView.y); } updateHandlesVisibility(); } else { @@ -5259,11 +5306,13 @@ public class Editor { int deltaHeight = 0; int opacity = 255; - if (mCursorControlEnabled) { + if (mFlagInsertionHandleGesturesEnabled) { deltaHeight = AppGlobals.getIntCoreSetting( - WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, 25); + WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, + WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT); opacity = AppGlobals.getIntCoreSetting( - WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, 50); + WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, + WidgetFlags.INSERTION_HANDLE_OPACITY_DEFAULT); // Avoid invalid/unsupported values. if (deltaHeight < -25 || deltaHeight > 50) { deltaHeight = 25; @@ -5329,7 +5378,7 @@ public class Editor { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (mCursorControlEnabled) { + if (mFlagInsertionHandleGesturesEnabled) { final int height = Math.max( getPreferredHeight() + mDeltaHeight, mDrawable.getIntrinsicHeight()); setMeasuredDimension(getPreferredWidth(), height); @@ -5340,7 +5389,7 @@ public class Editor { @Override public boolean onTouchEvent(MotionEvent ev) { - if (mCursorControlEnabled && FLAG_ENABLE_CURSOR_DRAG) { + if (mFlagInsertionHandleGesturesEnabled && mFlagCursorDragFromAnywhereEnabled) { // Should only enable touch through when cursor drag is enabled. // Otherwise the insertion handle view cannot be moved. return touchThrough(ev); @@ -6012,7 +6061,13 @@ public class Editor { @VisibleForTesting public class InsertionPointCursorController implements CursorController { private InsertionHandleView mHandle; + // Tracks whether the cursor is currently being dragged. private boolean mIsDraggingCursor; + // During a drag, tracks whether the user's finger has adjusted to be over the handle rather + // than the cursor bar. + private boolean mIsTouchSnappedToHandleDuringDrag; + // During a drag, tracks the line of text where the cursor was last positioned. + private int mPrevLineDuringDrag; public void onTouchEvent(MotionEvent event) { if (hasSelectionController() && getSelectionController().isCursorBeingModified()) { @@ -6025,7 +6080,7 @@ public class Editor { } if (mIsDraggingCursor) { performCursorDrag(event); - } else if (FLAG_ENABLE_CURSOR_DRAG + } else if (mFlagCursorDragFromAnywhereEnabled && mTextView.getLayout() != null && mTextView.isFocused() && mTouchState.isMovedEnoughForDrag() @@ -6043,8 +6098,8 @@ public class Editor { } private void positionCursorDuringDrag(MotionEvent event) { - int line = mTextView.getLineAtCoordinate(event.getY()); - int offset = mTextView.getOffsetAtCoordinate(line, event.getX()); + mPrevLineDuringDrag = getLineDuringDrag(event); + int offset = mTextView.getOffsetAtCoordinate(mPrevLineDuringDrag, event.getX()); int oldSelectionStart = mTextView.getSelectionStart(); int oldSelectionEnd = mTextView.getSelectionEnd(); if (offset == oldSelectionStart && offset == oldSelectionEnd) { @@ -6057,11 +6112,58 @@ public class Editor { } } + /** + * Returns the line where the cursor should be positioned during a cursor drag. Rather than + * simply returning the line directly at the touch position, this function has the following + * additional logic: + * 1) Apply some slop to avoid switching lines if the touch moves just slightly off the + * current line. + * 2) Allow the user's finger to slide down and "snap" to the handle to provide better + * visibility of the cursor and text. + */ + private int getLineDuringDrag(MotionEvent event) { + final Layout layout = mTextView.getLayout(); + if (mTouchState.isOnHandle()) { + // The drag was initiated from the handle, so no need to apply the snap logic. See + // InsertionHandleView.touchThrough(). + return getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, event.getY()); + } + if (mIsTouchSnappedToHandleDuringDrag) { + float cursorY = event.getY() - getHandle().getIdealVerticalOffset(); + return getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY); + } + int line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, event.getY()); + if (mPrevLineDuringDrag == UNSET_LINE || line <= mPrevLineDuringDrag) { + // User's finger is on the same line or moving up; continue positioning the cursor + // directly at the touch location. + return line; + } + // User's finger is moving downwards; delay jumping to the lower line to allow the + // touch to move to the handle. + float cursorY = event.getY() - getHandle().getIdealVerticalOffset(); + line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY); + if (line < mPrevLineDuringDrag) { + return mPrevLineDuringDrag; + } + // User's finger is now over the handle, at the ideal offset from the cursor. From now + // on, position the cursor higher up from the actual touch location so that the user's + // finger stays "snapped" to the handle. This provides better visibility of the text. + mIsTouchSnappedToHandleDuringDrag = true; + if (TextView.DEBUG_CURSOR) { + logCursor("InsertionPointCursorController", + "snapped touch to handle: eventY=%d, cursorY=%d, mLastLine=%d, line=%d", + (int) event.getY(), (int) cursorY, mPrevLineDuringDrag, line); + } + return line; + } + private void startCursorDrag(MotionEvent event) { if (TextView.DEBUG_CURSOR) { logCursor("InsertionPointCursorController", "start cursor drag"); } mIsDraggingCursor = true; + mIsTouchSnappedToHandleDuringDrag = false; + mPrevLineDuringDrag = UNSET_LINE; // We don't want the parent scroll/long-press handlers to take over while dragging. mTextView.getParent().requestDisallowInterceptTouchEvent(true); mTextView.cancelLongPress(); @@ -6084,6 +6186,8 @@ public class Editor { logCursor("InsertionPointCursorController", "end cursor drag"); } mIsDraggingCursor = false; + mIsTouchSnappedToHandleDuringDrag = false; + mPrevLineDuringDrag = UNSET_LINE; // Hide the magnifier and set the handle to be hidden after a delay. getHandle().dismissMagnifier(); getHandle().hideAfterDelay(); diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 47ea1cbade93..a299b0185433 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -89,7 +89,7 @@ public final class Magnifier { // The width of the window containing the magnifier. private final int mWindowWidth; // The height of the window containing the magnifier. - private final int mWindowHeight; + private int mWindowHeight; // The zoom applied to the view region copied to the magnifier view. private float mZoom; // The width of the content that will be copied to the magnifier. @@ -485,6 +485,21 @@ public final class Magnifier { } /** + * Updates the factors of source which may impact the magnifier's size. + * This can be called while the magnifier is showing and moving. + * @param sourceHeight the new source height. + * @param zoom the new zoom factor. + */ + void updateSourceFactors(final int sourceHeight, final float zoom) { + mZoom = zoom; + mSourceHeight = sourceHeight; + mWindowHeight = (int) (sourceHeight * zoom); + if (mWindow != null) { + mWindow.updateContentFactors(mWindowHeight, zoom); + } + } + + /** * Returns the zoom to be applied to the magnified view region copied to the magnifier. * If the zoom is x and the magnifier window size is (width, height), the original size * of the content being magnified will be (width / x, height / x). @@ -904,7 +919,7 @@ public final class Magnifier { private final Display mDisplay; // The size of the content of the magnifier. private final int mContentWidth; - private final int mContentHeight; + private int mContentHeight; // The insets of the content inside the allocated surface. private final int mOffsetX; private final int mOffsetY; @@ -947,7 +962,7 @@ public final class Magnifier { // The current content of the magnifier. It is mBitmap + mOverlay, only used for testing. private Bitmap mCurrentContent; - private final float mZoom; + private float mZoom; // The width of the ramp region in pixels on the left & right sides of the fish-eye effect. private final int mRamp; // Whether is in the new magnifier style. @@ -1009,11 +1024,11 @@ public final class Magnifier { final RecordingCanvas canvas = mRenderer.getRootNode().beginRecording(width, height); try { - canvas.insertReorderBarrier(); + canvas.enableZ(); canvas.drawRenderNode(mBitmapRenderNode); - canvas.insertInorderBarrier(); + canvas.disableZ(); canvas.drawRenderNode(mOverlayRenderNode); - canvas.insertInorderBarrier(); + canvas.disableZ(); } finally { mRenderer.getRootNode().endRecording(); } @@ -1034,15 +1049,66 @@ public final class Magnifier { } } + /** + * Updates the factors of content which may resize the window. + * @param contentHeight the new height of content. + * @param zoom the new zoom factor. + */ + private void updateContentFactors(final int contentHeight, final float zoom) { + if (mContentHeight == contentHeight && mZoom == zoom) { + return; + } + if (mContentHeight < contentHeight) { + // Grows the surface height as necessary. + new SurfaceControl.Transaction().setBufferSize( + mSurfaceControl, mContentWidth, contentHeight).apply(); + mSurface.copyFrom(mSurfaceControl); + mRenderer.setSurface(mSurface); + + final Outline outline = new Outline(); + outline.setRoundRect(0, 0, mContentWidth, contentHeight, 0); + outline.setAlpha(1.0f); + + mBitmapRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY, + mOffsetX + mContentWidth, mOffsetY + contentHeight); + mBitmapRenderNode.setOutline(outline); + + mOverlayRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY, + mOffsetX + mContentWidth, mOffsetY + contentHeight); + mOverlayRenderNode.setOutline(outline); + + final RecordingCanvas canvas = + mRenderer.getRootNode().beginRecording(mContentWidth, contentHeight); + try { + canvas.enableZ(); + canvas.drawRenderNode(mBitmapRenderNode); + canvas.disableZ(); + canvas.drawRenderNode(mOverlayRenderNode); + canvas.disableZ(); + } finally { + mRenderer.getRootNode().endRecording(); + } + } + mContentHeight = contentHeight; + mZoom = zoom; + fillMeshMatrix(); + } + private void createMeshMatrixForFishEyeEffect() { mMeshWidth = 1; mMeshHeight = 6; + mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; + mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; + fillMeshMatrix(); + } + + private void fillMeshMatrix() { + mMeshWidth = 1; + mMeshHeight = 6; final float w = mContentWidth; final float h = mContentHeight; final float h0 = h / mZoom; final float dh = h - h0; - mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; - mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; for (int i = 0; i < 2 * (mMeshWidth + 1) * (mMeshHeight + 1); i += 2) { // Calculates X value. final int colIndex = i % (2 * (mMeshWidth + 1)) / 2; @@ -1197,6 +1263,7 @@ public final class Magnifier { if (mBitmap != null) { mBitmap.recycle(); } + mOverlay.setCallback(null); } private void doDraw() { diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java index 1a8e7a713e7a..bce5497a7c2d 100644 --- a/core/java/android/widget/WidgetFlags.java +++ b/core/java/android/widget/WidgetFlags.java @@ -17,27 +17,49 @@ package android.widget; /** - * Keeps the flags related to the Widget namespace in {@link DeviceConfig}. + * Flags in the {@link android.provider.DeviceConfig#NAMESPACE_WIDGET "widget" namespace}. * * @hide */ public final class WidgetFlags { /** - * Whether the cursor control feature set is enabled. - * TODO: Makes this flag key visible to webview/chrome. + * Whether starting a cursor drag from anywhere in the text should be enabled. */ - public static final String ENABLE_CURSOR_CONTROL = - "CursorControlFeature__enable_cursor_control"; + public static final String ENABLE_CURSOR_DRAG_FROM_ANYWHERE = + "CursorControlFeature__enable_cursor_drag_from_anywhere"; /** - * The key name used in app core settings for enable cursor control. + * The key used in app core settings for the flag {@link #ENABLE_CURSOR_DRAG_FROM_ANYWHERE}. */ - public static final String KEY_ENABLE_CURSOR_CONTROL = "widget__enable_cursor_control"; + public static final String KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE = + "widget__enable_cursor_drag_from_anywhere"; + + /** + * Default value for the flag {@link #ENABLE_CURSOR_DRAG_FROM_ANYWHERE}. + */ + public static final boolean ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT = true; + + /** + * Whether additional gestures should be enabled for the insertion cursor handle (e.g. + * long-press or double-tap on the handle to trigger selection). + */ + public static final String ENABLE_INSERTION_HANDLE_GESTURES = + "CursorControlFeature__enable_insertion_handle_gestures"; + + /** + * The key used in app core settings for the flag {@link #ENABLE_INSERTION_HANDLE_GESTURES}. + */ + public static final String KEY_ENABLE_INSERTION_HANDLE_GESTURES = + "widget__enable_insertion_handle_gestures"; + + /** + * Default value for the flag {@link #ENABLE_INSERTION_HANDLE_GESTURES}. + */ + public static final boolean ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT = false; /** * The flag of delta height applies to the insertion handle when cursor control flag is enabled. - * The default value is 25. */ public static final String INSERTION_HANDLE_DELTA_HEIGHT = "CursorControlFeature__insertion_handle_delta_height"; @@ -49,8 +71,13 @@ public final class WidgetFlags { "widget__insertion_handle_delta_height"; /** + * Default value for the flag {@link #INSERTION_HANDLE_DELTA_HEIGHT}. + */ + public static final int INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT = 25; + + /** * The flag of opacity applies to the insertion handle when cursor control flag is enabled. - * The opacity value is in the range of {0..100}. The default value is 50. + * The opacity value is in the range of {0..100}. */ public static final String INSERTION_HANDLE_OPACITY = "CursorControlFeature__insertion_handle_opacity"; @@ -62,6 +89,11 @@ public final class WidgetFlags { "widget__insertion_handle_opacity"; /** + * Default value for the flag {@link #INSERTION_HANDLE_OPACITY}. + */ + public static final int INSERTION_HANDLE_OPACITY_DEFAULT = 50; + + /** * The flag of enabling the new magnifier. */ public static final String ENABLE_NEW_MAGNIFIER = "CursorControlFeature__enable_new_magnifier"; @@ -72,8 +104,12 @@ public final class WidgetFlags { public static final String KEY_ENABLE_NEW_MAGNIFIER = "widget__enable_new_magnifier"; /** + * Default value for the flag {@link #ENABLE_NEW_MAGNIFIER}. + */ + public static final boolean ENABLE_NEW_MAGNIFIER_DEFAULT = false; + + /** * The flag of zoom factor applies to the new magnifier. - * The default value is 1.5f. */ public static final String MAGNIFIER_ZOOM_FACTOR = "CursorControlFeature__magnifier_zoom_factor"; @@ -84,8 +120,12 @@ public final class WidgetFlags { public static final String KEY_MAGNIFIER_ZOOM_FACTOR = "widget__magnifier_zoom_factor"; /** + * Default value for the flag {@link #MAGNIFIER_ZOOM_FACTOR}. + */ + public static final float MAGNIFIER_ZOOM_FACTOR_DEFAULT = 1.5f; + + /** * The flag of aspect ratio (width/height) applies to the new magnifier. - * The default value is 5.5f. */ public static final String MAGNIFIER_ASPECT_RATIO = "CursorControlFeature__magnifier_aspect_ratio"; @@ -95,6 +135,11 @@ public final class WidgetFlags { */ public static final String KEY_MAGNIFIER_ASPECT_RATIO = "widget__magnifier_aspect_ratio"; + /** + * Default value for the flag {@link #MAGNIFIER_ASPECT_RATIO}. + */ + public static final float MAGNIFIER_ASPECT_RATIO_DEFAULT = 5.5f; + private WidgetFlags() { } } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index a201a335622a..250b1ea5a4e9 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1805,6 +1805,10 @@ public class ChooserActivity extends ResolverActivity implements if (!TextUtils.isEmpty(dataString)) { return new IntentFilter(intent.getAction(), dataString); } + if (intent.getType() == null) { + Log.e(TAG, "Failed to get target intent filter: intent data and type are null"); + return null; + } IntentFilter intentFilter = new IntentFilter(intent.getAction(), intent.getType()); List<Uri> contentUris = new ArrayList<>(); if (Intent.ACTION_SEND.equals(intent.getAction())) { @@ -1825,7 +1829,7 @@ public class ChooserActivity extends ResolverActivity implements } return intentFilter; } catch (Exception e) { - Log.e(TAG, "failed to get target intent filter", e); + Log.e(TAG, "Failed to get target intent filter", e); return null; } } diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 2f1a15f39ca5..dc6942cdc2c3 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -133,7 +133,7 @@ interface IBatteryStats { void noteNetworkStatsEnabled(); void noteDeviceIdleMode(int mode, String activeReason, int activeUid); void setBatteryState(int status, int health, int plugType, int level, int temp, int volt, - int chargeUAh, int chargeFullUAh); + int chargeUAh, int chargeFullUAh, long chargeTimeToFullSeconds); @UnsupportedAppUsage long getAwakeTimeBattery(); long getAwakeTimePlugged(); diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 0ccc45e000e6..04bf91567986 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -31,7 +31,6 @@ import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.IBinder; import android.os.SELinux; @@ -95,20 +94,12 @@ public class NativeLibraryHelper { } } - public static Handle create(AndroidPackage pkg) throws IOException { - return create( - pkg.makeListAllCodePaths(), - (pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0, - (pkg.getFlags() & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0, - (pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0); - } - public static Handle create(PackageLite lite) throws IOException { return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs, lite.debuggable); } - private static Handle create(List<String> codePaths, boolean multiArch, + public static Handle create(List<String> codePaths, boolean multiArch, boolean extractNativeLibs, boolean debuggable) throws IOException { final int size = codePaths.size(); final String[] apkPaths = new String[size]; diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java index f699eb8c4639..ffa347c168f6 100644 --- a/core/java/com/android/internal/content/om/OverlayConfig.java +++ b/core/java/com/android/internal/content/om/OverlayConfig.java @@ -19,7 +19,7 @@ package com.android.internal.content.om; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PackagePartitions; -import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsingPackageRead; import android.os.Build; import android.os.Process; import android.os.Trace; @@ -36,7 +36,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; -import java.util.function.Consumer; +import java.util.function.BiConsumer; import java.util.function.Supplier; /** @@ -71,10 +71,10 @@ public class OverlayConfig { * Interface for providing information on scanned packages. * TODO(147840005): Remove this when android:isStatic and android:priority are fully deprecated */ - public interface AndroidPackageProvider { + public interface PackageProvider { /** Performs the given action for each package. */ - void forEachPackage(Consumer<AndroidPackage> p); + void forEachPackage(BiConsumer<ParsingPackageRead, Boolean> p); } private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> { @@ -100,7 +100,7 @@ public class OverlayConfig { @VisibleForTesting public OverlayConfig(@Nullable File rootDirectory, @Nullable Supplier<OverlayScanner> scannerFactory, - @Nullable AndroidPackageProvider packageProvider) { + @Nullable PackageProvider packageProvider) { Preconditions.checkArgument((scannerFactory == null) != (packageProvider == null), "scannerFactory and packageProvider cannot be both null or both non-null"); @@ -208,7 +208,7 @@ public class OverlayConfig { * {@link #getSystemInstance()} will return the initialized instance. */ @NonNull - public static OverlayConfig initializeSystemInstance(AndroidPackageProvider packageProvider) { + public static OverlayConfig initializeSystemInstance(PackageProvider packageProvider) { if (Process.myUid() != Process.SYSTEM_UID) { throw new IllegalStateException("Can only be invoked in the system process"); } @@ -221,7 +221,7 @@ public class OverlayConfig { /** * Retrieves the singleton instance initialized by - * {@link #initializeSystemInstance(AndroidPackageProvider)}. + * {@link #initializeSystemInstance(PackageProvider)}. */ @NonNull public static OverlayConfig getSystemInstance() { @@ -291,10 +291,10 @@ public class OverlayConfig { @NonNull private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos( - @NonNull AndroidPackageProvider packageManager) { + @NonNull PackageProvider packageManager) { final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>(); - packageManager.forEachPackage((AndroidPackage p) -> { - if (p.getOverlayTarget() != null && p.isSystem()) { + packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> { + if (p.getOverlayTarget() != null && isSystem) { overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(), new File(p.getBaseCodePath()))); diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java index bbae0273ef4e..23b1ab52cb21 100644 --- a/core/java/com/android/internal/net/VpnProfile.java +++ b/core/java/com/android/internal/net/VpnProfile.java @@ -18,6 +18,7 @@ package com.android.internal.net; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; +import android.net.Ikev2VpnProfile; import android.net.ProxyInfo; import android.os.Build; import android.os.Parcel; @@ -332,15 +333,38 @@ public final class VpnProfile implements Cloneable, Parcelable { return builder.toString().getBytes(StandardCharsets.UTF_8); } + /** Checks if this profile specifies a LegacyVpn type. */ + public static boolean isLegacyType(int type) { + switch (type) { + case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: // fall through + case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through + case VpnProfile.TYPE_IKEV2_IPSEC_PSK: + return false; + default: + return true; + } + } + + private boolean isValidLockdownLegacyVpnProfile() { + return isLegacyType(type) && isServerAddressNumeric() && hasDns() + && areDnsAddressesNumeric(); + } + + private boolean isValidLockdownPlatformVpnProfile() { + return Ikev2VpnProfile.isValidVpnProfile(this); + } + /** - * Tests if profile is valid for lockdown, which requires IPv4 address for both server and DNS. - * Server hostnames would require using DNS before connection. + * Tests if profile is valid for lockdown. + * + * <p>For LegacyVpn profiles, this requires an IPv4 address for both the server and DNS. + * + * <p>For PlatformVpn profiles, this requires a server, an identifier and the relevant fields to + * be non-null. */ public boolean isValidLockdownProfile() { return isTypeValidForLockdown() - && isServerAddressNumeric() - && hasDns() - && areDnsAddressesNumeric(); + && (isValidLockdownLegacyVpnProfile() || isValidLockdownPlatformVpnProfile()); } /** Returns {@code true} if the VPN type is valid for lockdown. */ diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 18066dce287e..27c7cb6de903 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -1000,6 +1000,8 @@ public class BatteryStatsImpl extends BatteryStats { private int mMinLearnedBatteryCapacity = -1; private int mMaxLearnedBatteryCapacity = -1; + private long mBatteryTimeToFullSeconds = -1; + private long[] mCpuFreqs; @VisibleForTesting @@ -12226,7 +12228,7 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void setBatteryStateLocked(final int status, final int health, final int plugType, final int level, /* not final */ int temp, final int volt, final int chargeUAh, - final int chargeFullUAh) { + final int chargeFullUAh, final long chargeTimeToFullSeconds) { // Temperature is encoded without the signed bit, so clamp any negative temperatures to 0. temp = Math.max(0, temp); @@ -12429,6 +12431,8 @@ public class BatteryStatsImpl extends BatteryStats { mMinLearnedBatteryCapacity = Math.min(mMinLearnedBatteryCapacity, chargeFullUAh); } mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh); + + mBatteryTimeToFullSeconds = chargeTimeToFullSeconds; } public static boolean isOnBattery(int plugType, int status) { @@ -12578,19 +12582,10 @@ public class BatteryStatsImpl extends BatteryStats { // Not yet working. return -1; } - /* Broken - int curLevel = mCurrentBatteryLevel; - int plugLevel = mDischargePlugLevel; - if (plugLevel < 0 || curLevel < (plugLevel+1)) { - return -1; + if (mBatteryTimeToFullSeconds >= 0) { + return mBatteryTimeToFullSeconds * (1000 * 1000); // s to us } - long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED); - if (duration < 1000*1000) { - return -1; - } - long usPerLevel = duration/(curLevel-plugLevel); - return usPerLevel * (100-curLevel); - */ + // Else use algorithmic approach if (mChargeStepTracker.mNumStepDurations < 1) { return -1; } @@ -12598,7 +12593,7 @@ public class BatteryStatsImpl extends BatteryStats { if (msPerLevel <= 0) { return -1; } - return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000; + return (msPerLevel * (100 - mCurrentBatteryLevel)) * 1000; } /*@hide */ diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index 3db8f4ed9408..add2304afe9d 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -393,6 +393,9 @@ public class PowerProfile { } public int getNumCoresInCpuCluster(int cluster) { + if (cluster < 0 || cluster >= mCpuClusters.length) { + return 0; // index out of bound + } return mCpuClusters[cluster].numCpus; } diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING new file mode 100644 index 000000000000..f44b9fb7e723 --- /dev/null +++ b/core/java/com/android/internal/os/TEST_MAPPING @@ -0,0 +1,30 @@ +{ + "presubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "com.android.internal.os.KernelCpuUidFreqTimeReaderTest" + }, + { + "include-filter": "com.android.internal.os.KernelCpuUidActiveTimeReaderTest" + }, + { + "include-filter": "com.android.internal.os.KernelCpuUidClusterTimeReaderTest" + }, + { + "include-filter": "com.android.internal.os.KernelSingleUidTimeReaderTest" + }, + { + "include-filter": "com.android.internal.os.KernelCpuUidBpfMapReaderTest" + } + + ], + "file_patterns": [ + "KernelCpuUidTimeReader\\.java", + "KernelCpuUidBpfMapReader\\.java", + "KernelSingleUidTimeReader\\.java" + ] + } + ] +} diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java index 4dac5427095b..9b2bcfbe89c7 100644 --- a/core/java/com/android/internal/util/CollectionUtils.java +++ b/core/java/com/android/internal/util/CollectionUtils.java @@ -186,6 +186,17 @@ public class CollectionUtils { } /** + * Returns the given map, or an immutable empty map if the provided map is null + * + * This can be used to guarantee null-safety without paying the price of extra allocations + * + * @see Collections#emptyMap + */ + public static @NonNull <K, V> Map<K, V> emptyIfNull(@Nullable Map<K, V> cur) { + return cur == null ? Collections.emptyMap() : cur; + } + + /** * Returns the size of the given collection, or 0 if null */ public static int size(@Nullable Collection<?> cur) { @@ -297,6 +308,33 @@ public class CollectionUtils { } /** + * Similar to {@link List#add(int, Object)}, but with support for list values of {@code null} + * and {@link Collections#emptyList} + */ + public static @NonNull <T> List<T> add(@Nullable List<T> cur, int index, T val) { + if (cur == null || cur == Collections.emptyList()) { + cur = new ArrayList<>(); + } + cur.add(index, val); + return cur; + } + + /** + * Similar to {@link Set#addAll(Collection)}}, but with support for list values of {@code null} + * and {@link Collections#emptySet} + */ + public static @NonNull <T> Set<T> addAll(@Nullable Set<T> cur, @Nullable Collection<T> val) { + if (isEmpty(val)) { + return cur != null ? cur : Collections.emptySet(); + } + if (cur == null || cur == Collections.emptySet()) { + cur = new ArraySet<>(); + } + cur.addAll(val); + return cur; + } + + /** * @see #add(List, Object) */ public static @NonNull <T> Set<T> add(@Nullable Set<T> cur, T val) { diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java index 390c5969c08c..6258a6956b09 100644 --- a/core/java/com/android/internal/util/Parcelling.java +++ b/core/java/com/android/internal/util/Parcelling.java @@ -15,10 +15,18 @@ */ package com.android.internal.util; +import static java.util.Collections.emptySet; + import android.annotation.Nullable; import android.os.Parcel; +import android.text.TextUtils; import android.util.ArrayMap; +import android.util.ArraySet; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** @@ -90,6 +98,132 @@ public interface Parcelling<T> { */ interface BuiltIn { + class ForInternedString implements Parcelling<String> { + @Override + public void parcel(@Nullable String item, Parcel dest, int parcelFlags) { + dest.writeString(item); + } + + @Nullable + @Override + public String unparcel(Parcel source) { + return TextUtils.safeIntern(source.readString()); + } + } + + class ForInternedStringArray implements Parcelling<String[]> { + @Override + public void parcel(String[] item, Parcel dest, int parcelFlags) { + dest.writeStringArray(item); + } + + @Nullable + @Override + public String[] unparcel(Parcel source) { + String[] array = source.readStringArray(); + if (array != null) { + int size = ArrayUtils.size(array); + for (int index = 0; index < size; index++) { + array[index] = TextUtils.safeIntern(array[index]); + } + } + return array; + } + } + + class ForInternedStringList implements Parcelling<List<String>> { + @Override + public void parcel(List<String> item, Parcel dest, int parcelFlags) { + dest.writeStringList(item); + } + + @Override + public List<String> unparcel(Parcel source) { + ArrayList<String> list = source.createStringArrayList(); + if (list != null) { + int size = list.size(); + for (int index = 0; index < size; index++) { + list.set(index, list.get(index).intern()); + } + } + return CollectionUtils.emptyIfNull(list); + } + } + + class ForInternedStringValueMap implements Parcelling<Map<String, String>> { + @Override + public void parcel(Map<String, String> item, Parcel dest, int parcelFlags) { + dest.writeMap(item); + } + + @Override + public Map<String, String> unparcel(Parcel source) { + ArrayMap<String, String> map = new ArrayMap<>(); + source.readMap(map, String.class.getClassLoader()); + for (int index = 0; index < map.size(); index++) { + map.setValueAt(index, TextUtils.safeIntern(map.valueAt(index))); + } + return map; + } + } + + class ForInternedStringSet implements Parcelling<Set<String>> { + @Override + public void parcel(Set<String> item, Parcel dest, int parcelFlags) { + if (item == null) { + dest.writeInt(-1); + } else { + dest.writeInt(item.size()); + for (String string : item) { + dest.writeString(string); + } + } + } + + @Override + public Set<String> unparcel(Parcel source) { + final int size = source.readInt(); + if (size < 0) { + return emptySet(); + } + Set<String> set = new ArraySet<>(); + for (int count = 0; count < size; count++) { + set.add(TextUtils.safeIntern(source.readString())); + } + return set; + } + } + + class ForBoolean implements Parcelling<Boolean> { + @Override + public void parcel(@Nullable Boolean item, Parcel dest, int parcelFlags) { + if (item == null) { + // This writes 1 for null to mirror TypedArray.getInteger(booleanResId, 1) + dest.writeInt(1); + } else if (!item) { + dest.writeInt(0); + } else { + dest.writeInt(-1); + } + } + + @Nullable + @Override + public Boolean unparcel(Parcel source) { + switch (source.readInt()) { + default: + throw new IllegalStateException("Malformed Parcel reading Boolean: " + + source); + case 1: + return null; + case 0: + return Boolean.FALSE; + case -1: + return Boolean.TRUE; + } + } + } + class ForPattern implements Parcelling<Pattern> { @Override diff --git a/core/java/com/android/internal/util/function/LongObjPredicate.java b/core/java/com/android/internal/util/function/LongObjPredicate.java new file mode 100644 index 000000000000..9e4630744809 --- /dev/null +++ b/core/java/com/android/internal/util/function/LongObjPredicate.java @@ -0,0 +1,35 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.util.function; + +/** + * Represents a predicate (boolean-valued function) of a {@code long}-valued argument + * and an object-valued argument. + * + * @param <T> the type of the object-valued argument to the predicate + */ +@FunctionalInterface +public interface LongObjPredicate<T> { + /** + * Evaluates this predicate on the given arguments. + * + * @param value the first input argument + * @param t the second input argument + * @return {@code true} if the input arguments match the predicate, + * otherwise {@code false} + */ + boolean test(long value, T t); +} diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl index 475a3214096d..fd4b5abe2b21 100644 --- a/core/java/com/android/internal/view/IInputMethod.aidl +++ b/core/java/com/android/internal/view/IInputMethod.aidl @@ -16,10 +16,8 @@ package com.android.internal.view; -import android.content.ComponentName; import android.os.IBinder; import android.os.ResultReceiver; -import android.view.autofill.AutofillId; import android.view.InputChannel; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputBinding; @@ -29,6 +27,7 @@ import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.IInputSessionCallback; +import com.android.internal.view.InlineSuggestionsRequestInfo; /** * Top-level interface to an input method component (implemented in a @@ -38,7 +37,7 @@ import com.android.internal.view.IInputSessionCallback; oneway interface IInputMethod { void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps); - void onCreateInlineSuggestionsRequest(in ComponentName componentName, in AutofillId autofillId, + void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo, in IInlineSuggestionsRequestCallback cb); void bindInput(in InputBinding binding); diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl index 41f902e2f852..45090320c192 100644 --- a/core/java/com/android/internal/view/IInputMethodClient.aidl +++ b/core/java/com/android/internal/view/IInputMethodClient.aidl @@ -28,6 +28,7 @@ oneway interface IInputMethodClient { void onBindMethod(in InputBindResult res); void onUnbindMethod(int sequence, int unbindReason); void setActive(boolean active, boolean fullscreen); + void scheduleStartInputIfNecessary(boolean fullscreen); void reportFullscreenMode(boolean fullscreen); void reportPreRendered(in EditorInfo info); void applyImeVisibility(boolean setVisible); diff --git a/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.aidl b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.aidl new file mode 100644 index 000000000000..8125c0df219b --- /dev/null +++ b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.view; + +parcelable InlineSuggestionsRequestInfo; diff --git a/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java new file mode 100644 index 000000000000..61484906269e --- /dev/null +++ b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.view; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.os.Bundle; +import android.os.Parcelable; +import android.view.autofill.AutofillId; +import android.view.inputmethod.InlineSuggestionsRequest; + +import com.android.internal.util.DataClass; + +/** + * Wraps the information needed to create an {@link InlineSuggestionsRequest}. + * + * @hide + */ +@DataClass( + genToString = true, + genHiddenConstDefs = true, + genEqualsHashCode = true) +public final class InlineSuggestionsRequestInfo implements Parcelable { + /** + * The {@link ComponentName} of current app/activity + */ + private final @NonNull ComponentName mComponentName; + + /** + * The {@link AutofillId} of currently focused field. + */ + private final @NonNull AutofillId mAutofillId; + + /** + * The extras that contain the UI renderer related information + */ + private final @NonNull Bundle mUiExtras; + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new InlineSuggestionsRequestInfo. + * + * @param componentName + * The {@link ComponentName} of current app/activity + * @param autofillId + * The {@link AutofillId} of currently focused field. + * @param uiExtras + * The extras that contain the ui renderer related information + */ + @DataClass.Generated.Member + public InlineSuggestionsRequestInfo( + @NonNull ComponentName componentName, + @NonNull AutofillId autofillId, + @NonNull Bundle uiExtras) { + this.mComponentName = componentName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mComponentName); + this.mAutofillId = autofillId; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAutofillId); + this.mUiExtras = uiExtras; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mUiExtras); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The {@link ComponentName} of current app/activity + */ + @DataClass.Generated.Member + public @NonNull ComponentName getComponentName() { + return mComponentName; + } + + /** + * The {@link AutofillId} of currently focused field. + */ + @DataClass.Generated.Member + public @NonNull AutofillId getAutofillId() { + return mAutofillId; + } + + /** + * The extras that contain the ui renderer related information + */ + @DataClass.Generated.Member + public @NonNull Bundle getUiExtras() { + return mUiExtras; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "InlineSuggestionsRequestInfo { " + + "componentName = " + mComponentName + ", " + + "autofillId = " + mAutofillId + ", " + + "uiExtras = " + mUiExtras + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@android.annotation.Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(InlineSuggestionsRequestInfo other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + InlineSuggestionsRequestInfo that = (InlineSuggestionsRequestInfo) o; + //noinspection PointlessBooleanExpression + return true + && java.util.Objects.equals(mComponentName, that.mComponentName) + && java.util.Objects.equals(mAutofillId, that.mAutofillId) + && java.util.Objects.equals(mUiExtras, that.mUiExtras); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + java.util.Objects.hashCode(mComponentName); + _hash = 31 * _hash + java.util.Objects.hashCode(mAutofillId); + _hash = 31 * _hash + java.util.Objects.hashCode(mUiExtras); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeTypedObject(mComponentName, flags); + dest.writeTypedObject(mAutofillId, flags); + dest.writeBundle(mUiExtras); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ InlineSuggestionsRequestInfo(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + ComponentName componentName = (ComponentName) in.readTypedObject(ComponentName.CREATOR); + AutofillId autofillId = (AutofillId) in.readTypedObject(AutofillId.CREATOR); + Bundle uiExtras = in.readBundle(); + + this.mComponentName = componentName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mComponentName); + this.mAutofillId = autofillId; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAutofillId); + this.mUiExtras = uiExtras; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mUiExtras); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<InlineSuggestionsRequestInfo> CREATOR + = new Parcelable.Creator<InlineSuggestionsRequestInfo>() { + @Override + public InlineSuggestionsRequestInfo[] newArray(int size) { + return new InlineSuggestionsRequestInfo[size]; + } + + @Override + public InlineSuggestionsRequestInfo createFromParcel(@NonNull android.os.Parcel in) { + return new InlineSuggestionsRequestInfo(in); + } + }; + + @DataClass.Generated( + time = 1582076613213L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java", + inputSignatures = "private final @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate final @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.NonNull android.os.Bundle mUiExtras\nclass InlineSuggestionsRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java index a5964b509b3c..f29e95ccdf65 100644 --- a/core/java/com/android/internal/view/InputBindResult.java +++ b/core/java/com/android/internal/view/InputBindResult.java @@ -89,57 +89,64 @@ public final class InputBindResult implements Parcelable { */ int SUCCESS_WAITING_IME_BINDING = 2; /** + * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} has a + * pending operation to switch to a different user. + * + * <p>Note that in this state even what would be the next current IME is not determined.</p> + */ + int SUCCESS_WAITING_USER_SWITCHING = 3; + /** * Indicates that this is not intended for starting input but just for reporting window * focus change from the application process. * * <p>All other fields do not have meaningful value.</p> */ - int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 3; + int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 4; /** * Indicates somehow * {@link * com.android.server.inputmethod.InputMethodManagerService#startInputOrWindowGainedFocus} * is trying to return null {@link InputBindResult}, which must never happen. */ - int ERROR_NULL = 4; + int ERROR_NULL = 5; /** * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} * recognizes no IME. */ - int ERROR_NO_IME = 5; + int ERROR_NO_IME = 6; /** * Indicates that {@link android.view.inputmethod.EditorInfo#packageName} does not match * the caller UID. * * @see android.view.inputmethod.EditorInfo#packageName */ - int ERROR_INVALID_PACKAGE_NAME = 6; + int ERROR_INVALID_PACKAGE_NAME = 7; /** * Indicates that the system is still in an early stage of the boot process and any 3rd * party application is not allowed to run. * * @see com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START */ - int ERROR_SYSTEM_NOT_READY = 7; + int ERROR_SYSTEM_NOT_READY = 8; /** * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to * connect to an {@link android.inputmethodservice.InputMethodService} but failed. * * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, UserHandle) */ - int ERROR_IME_NOT_CONNECTED = 8; + int ERROR_IME_NOT_CONNECTED = 9; /** * Indicates that the caller is not the foreground user, does not have * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission, or the user * specified in {@link android.view.inputmethod.EditorInfo#targetInputMethodUser} is not * running. */ - int ERROR_INVALID_USER = 9; + int ERROR_INVALID_USER = 10; /** * Indicates that the caller should have specified non-null * {@link android.view.inputmethod.EditorInfo}. */ - int ERROR_NULL_EDITOR_INFO = 10; + int ERROR_NULL_EDITOR_INFO = 11; /** * Indicates that the target window the client specified cannot be the IME target right now. * @@ -149,24 +156,24 @@ public final class InputBindResult implements Parcelable { * * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int) */ - int ERROR_NOT_IME_TARGET_WINDOW = 11; + int ERROR_NOT_IME_TARGET_WINDOW = 12; /** * Indicates that focused view in the current window is not an editor. */ - int ERROR_NO_EDITOR = 12; + int ERROR_NO_EDITOR = 13; /** * Indicates that there is a mismatch in display ID between IME client and focused Window. */ - int ERROR_DISPLAY_ID_MISMATCH = 13; + int ERROR_DISPLAY_ID_MISMATCH = 14; /** * Indicates that current IME client is no longer allowed to access to the associated * display. */ - int ERROR_INVALID_DISPLAY_ID = 14; + int ERROR_INVALID_DISPLAY_ID = 15; /** * Indicates that the client is not recognized by the system. */ - int ERROR_INVALID_CLIENT = 15; + int ERROR_INVALID_CLIENT = 16; } @ResultCode @@ -299,6 +306,8 @@ public final class InputBindResult implements Parcelable { return "SUCCESS_WAITING_IME_SESSION"; case ResultCode.SUCCESS_WAITING_IME_BINDING: return "SUCCESS_WAITING_IME_BINDING"; + case ResultCode.SUCCESS_WAITING_USER_SWITCHING: + return "SUCCESS_WAITING_USER_SWITCHING"; case ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY: return "SUCCESS_REPORT_WINDOW_FOCUS_ONLY"; case ResultCode.ERROR_NULL: @@ -386,4 +395,11 @@ public final class InputBindResult implements Parcelable { * Predefined error object for {@link ResultCode#ERROR_INVALID_CLIENT}. */ public static final InputBindResult INVALID_CLIENT = error(ResultCode.ERROR_INVALID_CLIENT); + + /** + * Predefined <strong>success</strong> object for + * {@link ResultCode#SUCCESS_WAITING_USER_SWITCHING}. + */ + public static final InputBindResult USER_SWITCHING = + error(ResultCode.SUCCESS_WAITING_USER_SWITCHING); } diff --git a/core/jni/android_os_storage_StorageManager.cpp b/core/jni/android_os_storage_StorageManager.cpp index aee6733ecf53..fd3e66b1bbce 100644 --- a/core/jni/android_os_storage_StorageManager.cpp +++ b/core/jni/android_os_storage_StorageManager.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "StorageManager" +#include <android-base/file.h> #include <android-base/logging.h> #include <android-base/unique_fd.h> #include <fcntl.h> @@ -25,11 +26,30 @@ namespace android { +static const char* kProcFilesystems = "/proc/filesystems"; + +// Checks whether the passed in filesystem is listed in /proc/filesystems +static bool IsFilesystemSupported(const std::string& fsType) { + std::string supported; + if (!android::base::ReadFileToString(kProcFilesystems, &supported)) { + PLOG(ERROR) << "Failed to read supported filesystems"; + return false; + } + return supported.find(fsType + "\n") != std::string::npos; +} + jboolean android_os_storage_StorageManager_setQuotaProjectId(JNIEnv* env, jobject self, jstring path, jlong projectId) { struct fsxattr fsx; ScopedUtfChars utf_chars_path(env, path); + static bool sdcardFsSupported = IsFilesystemSupported("sdcardfs"); + if (sdcardFsSupported) { + // sdcardfs doesn't support project ID quota tracking and takes care of quota + // in a different way. + return JNI_TRUE; + } + if (projectId > UINT32_MAX) { LOG(ERROR) << "Invalid project id: " << projectId; return JNI_FALSE; diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 27c5a7302ba4..93449ffeae1b 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -186,6 +186,7 @@ static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz, proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer); } proxy->setSurface(window, enableTimeout); + ANativeWindow_release(window); } static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index d91911c3a6c0..e4141e02ab1c 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -105,10 +105,12 @@ namespace { using namespace std::placeholders; using android::String8; +using android::base::ReadFileToString; using android::base::StringAppendF; using android::base::StringPrintf; using android::base::WriteStringToFile; using android::base::GetBoolProperty; +using android::base::GetProperty; #define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \ append(StringPrintf(__VA_ARGS__)) @@ -174,6 +176,12 @@ static constexpr int DEFAULT_DATA_DIR_PERMISSION = 0751; static const std::string ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY = "persist.zygote.app_data_isolation"; +/** + * Property to enable app data isolation for sdcard obb or data in vold. + */ +static const std::string ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY = + "persist.sys.vold_app_data_isolation_enabled"; + static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000; static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF; @@ -603,6 +611,15 @@ static void EnableDebugger() { } } +static bool IsFilesystemSupported(const std::string& fsType) { + std::string supported; + if (!ReadFileToString("/proc/filesystems", &supported)) { + ALOGE("Failed to read supported filesystems"); + return false; + } + return supported.find(fsType + "\n") != std::string::npos; +} + static void PreApplicationInit() { // The child process sets this to indicate it's not the zygote. android_mallopt(M_SET_ZYGOTE_CHILD, nullptr, 0); @@ -782,6 +799,31 @@ static void MountAppDataTmpFs(const std::string& target_dir, } } +static void BindMountObbPackage(std::string_view package_name, int userId, fail_fn_t fail_fn) { + + // TODO(148772775): Pass primary volume name from zygote argument to here + std::string source; + if (IsFilesystemSupported("sdcardfs")) { + source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s", + userId, package_name.data()); + } else { + source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s", + userId, userId, package_name.data()); + } + std::string target( + StringPrintf("/storage/emulated/%d/Android/obb/%s", userId, package_name.data())); + + if (access(source.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Cannot access source %s: %s", source.c_str(), strerror(errno))); + } + + if (access(target.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Cannot access target %s: %s", target.c_str(), strerror(errno))); + } + + BindMount(source, target, fail_fn); +} + // Create a private mount namespace and bind mount appropriate emulated // storage for the given user. static void MountEmulatedStorage(uid_t uid, jint mount_mode, @@ -1504,6 +1546,60 @@ static void isolateJitProfile(JNIEnv* env, jobjectArray pkg_data_info_list, } } +// Bind mount all obb directories that are visible to this app. +// If app data isolation is not enabled for this process, bind mount the whole obb +// directory instead. +static void BindMountAppObbDirs(JNIEnv* env, jobjectArray pkg_data_info_list, + uid_t uid, const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) { + + auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); + const userid_t user_id = multiuser_get_user_id(uid); + + // If FUSE is not ready for this user, skip it + // TODO(148772775): Pass primary volume name from zygote argument to here + std::string tmp = GetProperty("vold.fuse_running_users", ""); + std::istringstream fuse_running_users(tmp); + bool user_found = false; + std::string s; + std::string user_id_str = std::to_string(user_id); + while (!user_found && std::getline(fuse_running_users, s, ',')) { + if (user_id_str == s) { + user_found = true; + } + } + if (!user_found) { + ALOGI("User %d is not running fuse yet, fuse_running_users=%s", user_id, tmp.c_str()); + return; + } + + // Fuse is ready, so we can start using fuse path. + int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0; + + if (size == 0) { + // App data isolation is not enabled for this process, so we bind mount to whole obb/ dir. + std::string source; + if (IsFilesystemSupported("sdcardfs")) { + source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", user_id); + } else { + source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", user_id, user_id); + } + std::string target(StringPrintf("/storage/emulated/%d/Android/obb", user_id)); + + if (access(source.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno))); + } + BindMount(source, target, fail_fn); + return; + } + + // Bind mount each package obb directory + for (int i = 0; i < size; i += 3) { + jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i)); + std::string packageName = extract_fn(package_str).value(); + BindMountObbPackage(packageName, user_id, fail_fn); + } +} + // Utility routine to specialize a zygote child process. static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, @@ -1552,6 +1648,12 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); } + if ((mount_external != MOUNT_EXTERNAL_INSTALLER) && + GetBoolProperty(kPropFuse, false) && + GetBoolProperty(ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) { + BindMountAppObbDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); + } + // If this zygote isn't root, it won't be able to create a process group, // since the directory is owned by root. if (!is_system_server && getuid() == 0) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c9fb25e6bb2e..ddfc4b8e94a4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -399,6 +399,9 @@ <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" /> <protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" /> <protected-broadcast android:name="android.intent.action.APPLICATION_RESTRICTIONS_CHANGED" /> + <protected-broadcast android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES" /> + <protected-broadcast android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT" /> + <protected-broadcast android:name="com.android.server.adb.WIRELESS_DEBUG_STATUS" /> <!-- Legacy --> <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" /> @@ -1200,6 +1203,15 @@ android:description="@string/permdesc_acceptHandovers" android:protectionLevel="dangerous" /> + <!-- Allows an application assigned to the Dialer role to be granted access to the telephony + call audio streams, both TX and RX. + <p>Protection level: signature|appop + --> + <permission android:name="android.permission.ACCESS_CALL_AUDIO" + android.label="@string/permlab_accessCallAudio" + android:description="@string/permdesc_accessCallAudio" + android:protectionLevel="signature|appop" /> + <!-- ====================================================================== --> <!-- Permissions for accessing the device microphone --> <!-- ====================================================================== --> @@ -2762,7 +2774,7 @@ <permission android:name="android.permission.READ_DEVICE_CONFIG" android:protectionLevel="signature|preinstalled" /> - <!-- @SystemApi @hide Allows an application to monitor config settings access. + <!-- @hide Allows an application to monitor {@link android.provider.Settings.Config} access. <p>Not for use by third-party applications. --> <permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS" android:protectionLevel="signature"/> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index c15b794266cc..68c86b263a75 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2460,6 +2460,12 @@ rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max --> <string name="config_ethernet_tcp_buffers" translatable="false">524288,1048576,3145728,524288,1048576,2097152</string> + <!-- What source to use to estimate link upstream and downstream bandwidth capacities. + Default is carrier_config, but it should be set to modem if the modem is returning + predictive (instead of instantaneous) bandwidth estimate. + Values are carrier_config and modem. --> + <string name="config_bandwidthEstimateSource">carrier_config</string> + <!-- Whether WiFi display is supported by this device. There are many prerequisites for this feature to work correctly. Here are a few of them: @@ -3532,6 +3538,8 @@ mode --> <string-array translatable="false" name="config_priorityOnlyDndExemptPackages"> <item>com.android.dialer</item> + <item>com.android.systemui</item> + <item>android</item> </string-array> <!-- The default value for transition animation scale found in developer settings. diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index e6a93e550a5f..d513e2b5a9e5 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -5364,4 +5364,9 @@ <string name="resolver_no_apps_available_explanation">We couldn\u2019t find any apps</string> <!-- Button which switches on the disabled work profile [CHAR LIMIT=NONE] --> <string name="resolver_switch_on_work">Switch on work</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] --> + <string name="permlab_accessCallAudio">Record or play audio in telephony calls</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] --> + <string name="permdesc_accessCallAudio">Allows this app, when assigned as default dialer application, to record or play audio in telephony calls.</string> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 85c2a2a24749..1c9e2cd72f28 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -473,6 +473,7 @@ <java-symbol type="integer" name="config_num_physical_slots" /> <java-symbol type="array" name="config_integrityRuleProviderPackages" /> <java-symbol type="bool" name="config_useAssistantVolume" /> + <java-symbol type="string" name="config_bandwidthEstimateSource" /> <java-symbol type="color" name="tab_indicator_text_v4" /> diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml index 899d630a51b7..d8ec72f33ddc 100644 --- a/core/res/res/xml/power_profile.xml +++ b/core/res/res/xml/power_profile.xml @@ -51,6 +51,12 @@ <value>0.1</value> <!-- ~1mA --> </array> + <!-- Additional power consumption by CPU excluding cluster and core when + running --> + <array name="cpu.active"> + <value>0.1</value> + </array> + <!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the number of CPU cores for that cluster. diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 8e4e684bc1c0..33fead6c98c6 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -83,21 +83,13 @@ java_genrule { ":FrameworksCoreTests_install_bad_dex", ":FrameworksCoreTests_install_complete_package_info", ":FrameworksCoreTests_install_decl_perm", - ":FrameworksCoreTests_install_intent_filters", ":FrameworksCoreTests_install_jni_lib_open_from_apk", ":FrameworksCoreTests_install_loc_auto", ":FrameworksCoreTests_install_loc_internal", ":FrameworksCoreTests_install_loc_sdcard", ":FrameworksCoreTests_install_loc_unspecified", - ":FrameworksCoreTests_install_split_base", - ":FrameworksCoreTests_install_split_feature_a", ":FrameworksCoreTests_install_use_perm_good", ":FrameworksCoreTests_install_uses_feature", - ":FrameworksCoreTests_install_uses_sdk_0", - ":FrameworksCoreTests_install_uses_sdk_q0", - ":FrameworksCoreTests_install_uses_sdk_r", - ":FrameworksCoreTests_install_uses_sdk_r0", - ":FrameworksCoreTests_install_uses_sdk_r5", ":FrameworksCoreTests_install_verifier_bad", ":FrameworksCoreTests_install_verifier_good", ":FrameworksCoreTests_keyset_permdef_sa_unone", diff --git a/core/tests/coretests/apks/install-split-base/Android.bp b/core/tests/coretests/apks/install-split-base/Android.bp deleted file mode 100644 index ddf75b224359..000000000000 --- a/core/tests/coretests/apks/install-split-base/Android.bp +++ /dev/null @@ -1,6 +0,0 @@ -android_test_helper_app { - name: "FrameworksCoreTests_install_split_base", - defaults: ["FrameworksCoreTests_apks_defaults"], - - srcs: ["**/*.java"], -} diff --git a/core/tests/coretests/apks/install_intent_filters/Android.bp b/core/tests/coretests/apks/install_intent_filters/Android.bp deleted file mode 100644 index 6cc5ebac9e6a..000000000000 --- a/core/tests/coretests/apks/install_intent_filters/Android.bp +++ /dev/null @@ -1,7 +0,0 @@ -android_test_helper_app { - name: "FrameworksCoreTests_install_intent_filters", - defaults: ["FrameworksCoreTests_apks_defaults"], - - srcs: ["**/*.java"], -} - diff --git a/core/tests/coretests/apks/install_uses_sdk/Android.bp b/core/tests/coretests/apks/install_uses_sdk/Android.bp deleted file mode 100644 index 92b09ed3818d..000000000000 --- a/core/tests/coretests/apks/install_uses_sdk/Android.bp +++ /dev/null @@ -1,39 +0,0 @@ -android_test_helper_app { - name: "FrameworksCoreTests_install_uses_sdk_r0", - defaults: ["FrameworksCoreTests_apks_defaults"], - manifest: "AndroidManifest-r0.xml", - - srcs: ["**/*.java"], -} - -android_test_helper_app { - name: "FrameworksCoreTests_install_uses_sdk_r5", - defaults: ["FrameworksCoreTests_apks_defaults"], - manifest: "AndroidManifest-r5.xml", - - srcs: ["**/*.java"], -} - -android_test_helper_app { - name: "FrameworksCoreTests_install_uses_sdk_q0", - defaults: ["FrameworksCoreTests_apks_defaults"], - manifest: "AndroidManifest-q0.xml", - - srcs: ["**/*.java"], -} - -android_test_helper_app { - name: "FrameworksCoreTests_install_uses_sdk_r", - defaults: ["FrameworksCoreTests_apks_defaults"], - manifest: "AndroidManifest-r.xml", - - srcs: ["**/*.java"], -} - -android_test_helper_app { - name: "FrameworksCoreTests_install_uses_sdk_0", - defaults: ["FrameworksCoreTests_apks_defaults"], - manifest: "AndroidManifest-0.xml", - - srcs: ["**/*.java"], -} diff --git a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java index 82a7b2c9217e..9f0af60f33b7 100644 --- a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java +++ b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java @@ -90,6 +90,12 @@ public class AccessibilityShortcutInfoTest { } @Test + public void testLoadAnimatedImage() { + assertNotNull("Can't find animated image", + mShortcutInfo.loadAnimatedImage(mPackageManager)); + } + + @Test public void testHtmlDescription() { final String htmlDescription = mTargetContext.getResources() .getString(R.string.accessibility_shortcut_html_description); diff --git a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java index 62c9c98f4e1d..7e4c138ccd3c 100644 --- a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java +++ b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java @@ -109,8 +109,8 @@ public class IntegrityFormulaTest { @Test public void createGreaterThanOrEqualsToFormula_versionCode() { int versionCode = 12; - IntegrityFormula formula = IntegrityFormula.Application.versionCodeGreaterThanOrEqualTo( - versionCode); + IntegrityFormula formula = + IntegrityFormula.Application.versionCodeGreaterThanOrEqualTo(versionCode); AtomicFormula.LongAtomicFormula stringAtomicFormula = (AtomicFormula.LongAtomicFormula) formula; @@ -124,11 +124,11 @@ public class IntegrityFormulaTest { public void createIsTrueFormula_preInstalled() { IntegrityFormula formula = IntegrityFormula.Application.isPreInstalled(); - AtomicFormula.BooleanAtomicFormula stringAtomicFormula = + AtomicFormula.BooleanAtomicFormula booleanAtomicFormula = (AtomicFormula.BooleanAtomicFormula) formula; - assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PRE_INSTALLED); - assertThat(stringAtomicFormula.getValue()).isTrue(); + assertThat(booleanAtomicFormula.getKey()).isEqualTo(AtomicFormula.PRE_INSTALLED); + assertThat(booleanAtomicFormula.getValue()).isTrue(); } @Test @@ -136,8 +136,8 @@ public class IntegrityFormulaTest { String packageName = "com.test.package"; String certificateName = "certificate"; IntegrityFormula formula1 = IntegrityFormula.Application.packageNameEquals(packageName); - IntegrityFormula formula2 = IntegrityFormula.Application.certificatesContain( - certificateName); + IntegrityFormula formula2 = + IntegrityFormula.Application.certificatesContain(certificateName); IntegrityFormula compoundFormula = IntegrityFormula.all(formula1, formula2); @@ -149,8 +149,8 @@ public class IntegrityFormulaTest { String packageName = "com.test.package"; String certificateName = "certificate"; IntegrityFormula formula1 = IntegrityFormula.Application.packageNameEquals(packageName); - IntegrityFormula formula2 = IntegrityFormula.Application.certificatesContain( - certificateName); + IntegrityFormula formula2 = + IntegrityFormula.Application.certificatesContain(certificateName); IntegrityFormula compoundFormula = IntegrityFormula.any(formula1, formula2); @@ -166,4 +166,29 @@ public class IntegrityFormulaTest { assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG); } + + @Test + public void createIsTrueFormula_stampNotTrusted() { + IntegrityFormula formula = IntegrityFormula.SourceStamp.notTrusted(); + + AtomicFormula.BooleanAtomicFormula booleanAtomicFormula = + (AtomicFormula.BooleanAtomicFormula) formula; + + assertThat(booleanAtomicFormula.getKey()).isEqualTo(AtomicFormula.STAMP_TRUSTED); + assertThat(booleanAtomicFormula.getValue()).isFalse(); + } + + @Test + public void createEqualsFormula_stampCertificateHash() { + String stampCertificateHash = "test-cert"; + IntegrityFormula formula = + IntegrityFormula.SourceStamp.stampCertificateHashEquals(stampCertificateHash); + + AtomicFormula.StringAtomicFormula stringAtomicFormula = + (AtomicFormula.StringAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.STAMP_CERTIFICATE_HASH); + assertThat(stringAtomicFormula.getValue()).matches(stampCertificateHash); + assertThat(stringAtomicFormula.getIsHashedValue()).isTrue(); + } } diff --git a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java index a24b4e06225a..78c88d71d953 100644 --- a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java +++ b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -62,8 +63,6 @@ public class ControlProviderServiceTest { @Mock private IControlsActionCallback.Stub mActionCallback; @Mock - private IControlsLoadCallback.Stub mLoadCallback; - @Mock private IControlsSubscriber.Stub mSubscriber; @Mock private IIntentSender mIIntentSender; @@ -79,8 +78,6 @@ public class ControlProviderServiceTest { when(mActionCallback.asBinder()).thenCallRealMethod(); when(mActionCallback.queryLocalInterface(any())).thenReturn(mActionCallback); - when(mLoadCallback.asBinder()).thenCallRealMethod(); - when(mLoadCallback.queryLocalInterface(any())).thenReturn(mLoadCallback); when(mSubscriber.asBinder()).thenCallRealMethod(); when(mSubscriber.queryLocalInterface(any())).thenReturn(mSubscriber); @@ -102,22 +99,28 @@ public class ControlProviderServiceTest { Control control2 = new Control.StatelessBuilder("TEST_ID_2", mPendingIntent) .setDeviceType(DeviceTypes.TYPE_AIR_FRESHENER).build(); - @SuppressWarnings("unchecked") - ArgumentCaptor<List<Control>> captor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor<IControlsSubscription.Stub> subscriptionCaptor = + ArgumentCaptor.forClass(IControlsSubscription.Stub.class); + ArgumentCaptor<Control> controlCaptor = + ArgumentCaptor.forClass(Control.class); ArrayList<Control> list = new ArrayList<>(); list.add(control1); list.add(control2); mControlsProviderService.setControls(list); - mControlsProvider.load(mLoadCallback); + mControlsProvider.load(mSubscriber); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - verify(mLoadCallback).accept(eq(mToken), captor.capture()); - List<Control> l = captor.getValue(); - assertEquals(2, l.size()); - assertTrue(equals(control1, l.get(0))); - assertTrue(equals(control2, l.get(1))); + verify(mSubscriber).onSubscribe(eq(mToken), subscriptionCaptor.capture()); + subscriptionCaptor.getValue().request(1000); + + verify(mSubscriber, times(2)).onNext(eq(mToken), controlCaptor.capture()); + List<Control> values = controlCaptor.getAllValues(); + assertTrue(equals(values.get(0), list.get(0))); + assertTrue(equals(values.get(1), list.get(1))); + + verify(mSubscriber).onComplete(eq(mToken)); } @Test @@ -128,50 +131,57 @@ public class ControlProviderServiceTest { .build(); Control statelessControl = new Control.StatelessBuilder(control).build(); - @SuppressWarnings("unchecked") - ArgumentCaptor<List<Control>> captor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor<IControlsSubscription.Stub> subscriptionCaptor = + ArgumentCaptor.forClass(IControlsSubscription.Stub.class); + ArgumentCaptor<Control> controlCaptor = + ArgumentCaptor.forClass(Control.class); ArrayList<Control> list = new ArrayList<>(); list.add(control); mControlsProviderService.setControls(list); - mControlsProvider.load(mLoadCallback); + mControlsProvider.load(mSubscriber); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - verify(mLoadCallback).accept(eq(mToken), captor.capture()); - List<Control> l = captor.getValue(); - assertEquals(1, l.size()); - assertFalse(equals(control, l.get(0))); - assertTrue(equals(statelessControl, l.get(0))); - assertEquals(Control.STATUS_UNKNOWN, l.get(0).getStatus()); + verify(mSubscriber).onSubscribe(eq(mToken), subscriptionCaptor.capture()); + subscriptionCaptor.getValue().request(1000); + + verify(mSubscriber).onNext(eq(mToken), controlCaptor.capture()); + Control c = controlCaptor.getValue(); + assertFalse(equals(control, c)); + assertTrue(equals(statelessControl, c)); + assertEquals(Control.STATUS_UNKNOWN, c.getStatus()); + + verify(mSubscriber).onComplete(eq(mToken)); } @Test - public void testLoadSuggested_withMaxNumber() throws RemoteException { + public void testOnLoadSuggested_allStateless() throws RemoteException { Control control1 = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build(); Control control2 = new Control.StatelessBuilder("TEST_ID_2", mPendingIntent) .setDeviceType(DeviceTypes.TYPE_AIR_FRESHENER).build(); - @SuppressWarnings("unchecked") - ArgumentCaptor<List<Control>> captor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor<IControlsSubscription.Stub> subscriptionCaptor = + ArgumentCaptor.forClass(IControlsSubscription.Stub.class); + ArgumentCaptor<Control> controlCaptor = + ArgumentCaptor.forClass(Control.class); ArrayList<Control> list = new ArrayList<>(); list.add(control1); list.add(control2); - final int maxSuggested = 1; - mControlsProviderService.setControls(list); - mControlsProvider.loadSuggested(maxSuggested, mLoadCallback); + mControlsProvider.loadSuggested(mSubscriber); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - verify(mLoadCallback).accept(eq(mToken), captor.capture()); - List<Control> l = captor.getValue(); - assertEquals(maxSuggested, l.size()); + verify(mSubscriber).onSubscribe(eq(mToken), subscriptionCaptor.capture()); + subscriptionCaptor.getValue().request(1); - for (int i = 0; i < maxSuggested; ++i) { - assertTrue(equals(list.get(i), l.get(i))); - } + verify(mSubscriber).onNext(eq(mToken), controlCaptor.capture()); + Control c = controlCaptor.getValue(); + assertTrue(equals(c, list.get(0))); + + verify(mSubscriber).onComplete(eq(mToken)); } @Test @@ -244,22 +254,19 @@ public class ControlProviderServiceTest { } @Override - public void loadSuggestedControls(int maxNumber, Consumer<List<Control>> cb) { - cb.accept(mControls); + public Publisher<Control> publisherFor(List<String> ids) { + return new Publisher<Control>() { + public void subscribe(final Subscriber s) { + s.onSubscribe(createSubscription(s, mControls)); + } + }; } @Override - public Publisher<Control> publisherFor(List<String> ids) { + public Publisher<Control> publisherForSuggested() { return new Publisher<Control>() { public void subscribe(final Subscriber s) { - s.onSubscribe(new Subscription() { - public void request(long n) { - for (Control c : mControls) { - s.onNext(c); - } - } - public void cancel() {} - }); + s.onSubscribe(createSubscription(s, mControls)); } }; } @@ -269,7 +276,19 @@ public class ControlProviderServiceTest { Consumer<Integer> cb) { cb.accept(ControlAction.RESPONSE_OK); } + + private Subscription createSubscription(Subscriber s, List<Control> controls) { + return new Subscription() { + public void request(long n) { + int i = 0; + for (Control c : mControls) { + if (i++ < n) s.onNext(c); + else break; + } + s.onComplete(); + } + public void cancel() {} + }; + } } } - - diff --git a/core/tests/coretests/src/android/util/LongSparseArrayTest.java b/core/tests/coretests/src/android/util/LongSparseArrayTest.java new file mode 100644 index 000000000000..bf3f0f50f4bf --- /dev/null +++ b/core/tests/coretests/src/android/util/LongSparseArrayTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.util; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.internal.util.function.LongObjPredicate; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link LongSparseArray}. + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class LongSparseArrayTest { + @Test + public void testRemoveIf() { + final LongSparseArray<Integer> sparseArray = new LongSparseArray(); + for (int i = 0; i < 10; ++i) { + for (int j = 100; j < 110; ++j) { + sparseArray.put(i, j); + sparseArray.put(-i, j); + sparseArray.put(j, -i); + sparseArray.put(-j, -i); + } + } + + final LongObjPredicate<Integer> predicate = (value, obj) -> (value < 0 && obj < 0); + sparseArray.removeIf(predicate); + + for (int i = 0; i < sparseArray.size(); ++i) { + assertThat(predicate.test(sparseArray.keyAt(i), sparseArray.valueAt(i))) + .isFalse(); + } + } +} diff --git a/core/tests/coretests/src/android/view/CutoutSpecificationTest.java b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java index b41f90c4689e..7872810717b8 100644 --- a/core/tests/coretests/src/android/view/CutoutSpecificationTest.java +++ b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java @@ -21,10 +21,27 @@ import static com.google.common.truth.Truth.assertThat; import static org.testng.Assert.assertThrows; import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +/** + * Tests for {@link CutoutSpecification} used by {@link DisplayCutout}. + * + * <p>Build/Install/Run: + * atest FrameworksCoreTests:CutoutSpecificationTest + * + * <p>This test class is a part of Window Manager Service tests and specified in + * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit public class CutoutSpecificationTest { private static final String WITHOUT_BIND_CUTOUT_SPECIFICATION = "M 0,0\n" + "h 48\n" @@ -344,7 +361,7 @@ public class CutoutSpecificationTest { .parse("@bottom" + "M 0,0\n" + "v -10\n" - + "h 10\n" + + "h -10\n" + "v 10\n" + "z\n" + "@right\n" diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java index a602fa31281f..0a094c61d4d5 100644 --- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java +++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java @@ -25,6 +25,9 @@ import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.replaceText; import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.hamcrest.Matchers.emptyString; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertFalse; @@ -32,11 +35,14 @@ import static org.junit.Assert.assertTrue; import android.app.Activity; import android.app.Instrumentation; +import android.text.Layout; +import android.util.Log; import android.view.InputDevice; import android.view.MotionEvent; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; +import androidx.test.filters.Suppress; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.AndroidJUnit4; @@ -44,20 +50,24 @@ import com.android.frameworks.coretests.R; import com.google.common.base.Strings; -import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.atomic.AtomicLong; + @RunWith(AndroidJUnit4.class) @SmallTest public class EditorCursorDragTest { + private static final String LOG_TAG = EditorCursorDragTest.class.getSimpleName(); + + private static final AtomicLong sTicker = new AtomicLong(1); + @Rule public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>( TextViewActivity.class); - private boolean mOriginalFlagValue; private Instrumentation mInstrumentation; private Activity mActivity; @@ -65,13 +75,6 @@ public class EditorCursorDragTest { public void before() throws Throwable { mInstrumentation = InstrumentationRegistry.getInstrumentation(); mActivity = mActivityRule.getActivity(); - mOriginalFlagValue = Editor.FLAG_ENABLE_CURSOR_DRAG; - Editor.FLAG_ENABLE_CURSOR_DRAG = true; - } - - @After - public void after() throws Throwable { - Editor.FLAG_ENABLE_CURSOR_DRAG = mOriginalFlagValue; } @Test @@ -119,13 +122,11 @@ public class EditorCursorDragTest { onView(withId(R.id.textview)).perform(replaceText(text)); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); - // Swipe along a diagonal path. This should drag the cursor. - onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2"))); - onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("2"))); - - // Swipe along a steeper diagonal path. This should still drag the cursor. + // Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to + // the handle as the touch moves downwards (and because we have some slop to avoid jumping + // across lines), the cursor position will end up higher than the finger position. onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3"))); - onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("3"))); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1"))); // Swipe right-down along a very steep diagonal path. This should not drag the cursor. // Normally this would trigger a scroll, but since the full view fits on the screen there @@ -133,12 +134,15 @@ public class EditorCursorDragTest { onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("7"))); onView(withId(R.id.textview)).check(hasSelection(not(emptyString()))); - // Swipe right-up along a very steep diagonal path. This should not drag the cursor. - // Normally this would trigger a scroll, but since the full view fits on the screen there - // is nothing to scroll and the gesture will trigger a selection drag. + // Tap to clear the selection. int index = text.indexOf("line9"); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index)); + onView(withId(R.id.textview)).check(hasSelection(emptyString())); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index)); + + // Swipe right-up along a very steep diagonal path. This should not drag the cursor. + // Normally this would trigger a scroll, but since the full view fits on the screen there + // is nothing to scroll and the gesture will trigger a selection drag. onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line7"), text.indexOf("1"))); onView(withId(R.id.textview)).check(hasSelection(not(emptyString()))); } @@ -154,13 +158,11 @@ public class EditorCursorDragTest { onView(withId(R.id.textview)).perform(replaceText(text)); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); - // Swipe along a diagonal path. This should drag the cursor. - onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2"))); - onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("2"))); - - // Swipe along a steeper diagonal path. This should still drag the cursor. + // Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to + // the handle as the touch moves downwards (and because we have some slop to avoid jumping + // across lines), the cursor position will end up higher than the finger position. onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3"))); - onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("3"))); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1"))); // Swipe right-down along a very steep diagonal path. This should not drag the cursor. // Normally this would trigger a scroll up, but since the view is already at the top there @@ -168,11 +170,14 @@ public class EditorCursorDragTest { onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("7"))); onView(withId(R.id.textview)).check(hasSelection(not(emptyString()))); - // Swipe right-up along a very steep diagonal path. This should not drag the cursor. This - // will trigger a downward scroll and the cursor position will not change. + // Tap to clear the selection. int index = text.indexOf("line9"); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index)); + onView(withId(R.id.textview)).check(hasSelection(emptyString())); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index)); + + // Swipe right-up along a very steep diagonal path. This should not drag the cursor. This + // will trigger a downward scroll and the cursor position will not change. onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line7"), text.indexOf("1"))); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index)); } @@ -387,12 +392,14 @@ public class EditorCursorDragTest { assertFalse(editor.getSelectionController().isCursorBeingModified()); } + @Suppress // b/149712851 @Test // Reproduces b/147366705 public void testCursorDrag_nonSelectableTextView() throws Throwable { String text = "Hello world!"; TextView tv = mActivity.findViewById(R.id.nonselectable_textview); tv.setText(text); Editor editor = tv.getEditorForTesting(); + assertThat(editor).isNotNull(); // Simulate a tap. No error should be thrown. long event1Time = 1001; @@ -404,6 +411,68 @@ public class EditorCursorDragTest { dragOnText(text.indexOf("llo"), text.indexOf("!"))); } + @Test + public void testCursorDrag_slop() throws Throwable { + String text = "line1: This is the 1st line: A\n" + + "line2: This is the 2nd line: B\n" + + "line3: This is the 3rd line: C\n"; + onView(withId(R.id.textview)).perform(replaceText(text)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); + TextView tv = mActivity.findViewById(R.id.textview); + + // Simulate a drag where the finger moves slightly up and down (above and below the original + // line where the drag started). The cursor should just move along the original line without + // jumping up or down across lines. + MotionEventInfo[] events = new MotionEventInfo[]{ + // Start dragging along the second line + motionEventInfo(text.indexOf("line2"), 1.0f), + motionEventInfo(text.indexOf("This is the 2nd"), 1.0f), + // Move to the bottom of the first line; cursor should remain on second line + motionEventInfo(text.indexOf("he 1st"), 0.0f, text.indexOf("he 2nd")), + // Move to the top of the third line; cursor should remain on second line + motionEventInfo(text.indexOf("e: C"), 1.0f, text.indexOf("e: B")), + motionEventInfo(text.indexOf("B"), 0.0f) + }; + simulateDrag(tv, events, true); + } + + @Test + public void testCursorDrag_snapToHandle() throws Throwable { + String text = "line1: This is the 1st line: A\n" + + "line2: This is the 2nd line: B\n" + + "line3: This is the 3rd line: C\n"; + onView(withId(R.id.textview)).perform(replaceText(text)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); + TextView tv = mActivity.findViewById(R.id.textview); + + // When the drag motion moves downward, we delay jumping to the lower line to allow the + // user's touch to snap to the cursor's handle. Once the finger is over the handle, we + // position the cursor above the user's actual touch (offset such that the finger remains + // over the handle rather than on top of the cursor vertical bar). This improves the + // visibility of the cursor and the text underneath. + MotionEventInfo[] events = new MotionEventInfo[]{ + // Start dragging along the first line + motionEventInfo(text.indexOf("line1"), 1.0f), + motionEventInfo(text.indexOf("This is the 1st"), 1.0f), + // Move to the bottom of the third line; cursor should end up on second line + motionEventInfo(text.indexOf("he 3rd"), 0.0f, text.indexOf("he 2nd")), + // Move to the middle of the second line; cursor should end up on the first line + motionEventInfo(text.indexOf("he 2nd"), 0.5f, text.indexOf("he 1st")) + }; + simulateDrag(tv, events, true); + + // If the drag motion hasn't moved downward (ie, we haven't had a chance to snap to the + // handle), we position the cursor directly at the touch position. + events = new MotionEventInfo[]{ + // Start dragging along the third line + motionEventInfo(text.indexOf("line3"), 1.0f), + motionEventInfo(text.indexOf("This is the 3rd"), 1.0f), + // Move to the middle of the second line; cursor should end up on the second line + motionEventInfo(text.indexOf("he 2nd"), 0.5f, text.indexOf("he 2nd")), + }; + simulateDrag(tv, events, true); + } + private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) { return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0); } @@ -436,4 +505,89 @@ public class EditorCursorDragTest { event.setButtonState(MotionEvent.BUTTON_PRIMARY); return event; } + + public static MotionEventInfo motionEventInfo(int index, float ratioToLineTop) { + return new MotionEventInfo(index, ratioToLineTop, index); + } + + public static MotionEventInfo motionEventInfo(int index, float ratioToLineTop, + int expectedCursorIndex) { + return new MotionEventInfo(index, ratioToLineTop, expectedCursorIndex); + } + + private static class MotionEventInfo { + public final int index; + public final float ratioToLineTop; // 0.0 = bottom of line, 0.5 = middle of line, etc + public final int expectedCursorIndex; + + private MotionEventInfo(int index, float ratioToLineTop, int expectedCursorIndex) { + this.index = index; + this.ratioToLineTop = ratioToLineTop; + this.expectedCursorIndex = expectedCursorIndex; + } + + public float[] getCoordinates(TextView textView) { + Layout layout = textView.getLayout(); + int line = layout.getLineForOffset(index); + float x = layout.getPrimaryHorizontal(index) + textView.getTotalPaddingLeft(); + int bottom = layout.getLineBottom(line); + int top = layout.getLineTop(line); + float y = bottom - ((bottom - top) * ratioToLineTop) + textView.getTotalPaddingTop(); + return new float[]{x, y}; + } + } + + private void simulateDrag(TextView tv, MotionEventInfo[] events, boolean runAssertions) + throws Exception { + Editor editor = tv.getEditorForTesting(); + + float[] downCoords = events[0].getCoordinates(tv); + long downEventTime = sTicker.addAndGet(10_000); + MotionEvent downEvent = downEvent(downEventTime, downEventTime, + downCoords[0], downCoords[1]); + mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(downEvent)); + + for (int i = 1; i < events.length; i++) { + float[] moveCoords = events[i].getCoordinates(tv); + long eventTime = downEventTime + i; + MotionEvent event = moveEvent(downEventTime, eventTime, moveCoords[0], moveCoords[1]); + mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event)); + assertCursorPosition(tv, events[i].expectedCursorIndex, runAssertions); + } + + MotionEventInfo lastEvent = events[events.length - 1]; + float[] upCoords = lastEvent.getCoordinates(tv); + long upEventTime = downEventTime + events.length; + MotionEvent upEvent = upEvent(downEventTime, upEventTime, upCoords[0], upCoords[1]); + mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(upEvent)); + } + + private static void assertCursorPosition(TextView tv, int expectedPosition, + boolean runAssertions) { + String textAfterExpectedPos = getTextAfterIndex(tv, expectedPosition, 15); + String textAfterActualPos = getTextAfterIndex(tv, tv.getSelectionStart(), 15); + String msg = "Expected cursor at " + expectedPosition + ", just before \"" + + textAfterExpectedPos + "\". Cursor is at " + tv.getSelectionStart() + + ", just before \"" + textAfterActualPos + "\"."; + Log.d(LOG_TAG, msg); + if (runAssertions) { + assertWithMessage(msg).that(tv.getSelectionStart()).isEqualTo(expectedPosition); + assertThat(tv.getSelectionEnd()).isEqualTo(expectedPosition); + } + } + + private static String getTextAfterIndex(TextView tv, int position, int maxLength) { + int end = Math.min(position + maxLength, tv.getText().length()); + try { + String afterPosition = tv.getText().subSequence(position, end).toString(); + if (afterPosition.indexOf('\n') > 0) { + afterPosition = afterPosition.substring(0, afterPosition.indexOf('\n')); + } + return afterPosition; + } catch (StringIndexOutOfBoundsException e) { + Log.d(LOG_TAG, "Invalid target position: position=" + position + ", length=" + + tv.getText().length() + ", end=" + end); + return ""; + } + } } diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java index 0c38e7136655..88a6f9e4af4b 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java @@ -31,8 +31,8 @@ import static android.widget.espresso.TextViewActions.doubleTapAndDragHandle; import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText; import static android.widget.espresso.TextViewActions.doubleTapHandle; import static android.widget.espresso.TextViewActions.dragHandle; -import static android.widget.espresso.TextViewActions.longPressAndDragOnText; import static android.widget.espresso.TextViewActions.longPressAndDragHandle; +import static android.widget.espresso.TextViewActions.longPressAndDragOnText; import static android.widget.espresso.TextViewActions.longPressHandle; import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; import static android.widget.espresso.TextViewAssertions.doesNotHaveStyledText; @@ -514,29 +514,26 @@ public class TextViewActivityTest { onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f"))); } - @Test - public void testInsertionHandle_touchThrough() { + private void enableFlagsForInsertionHandleGestures() { final TextView textView = mActivity.findViewById(R.id.textview); - boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled(); - boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG; - textView.getEditorForTesting().setCursorControlEnabled(true); - Editor.FLAG_ENABLE_CURSOR_DRAG = true; + final Editor editor = textView.getEditorForTesting(); + editor.setFlagCursorDragFromAnywhereEnabled(true); + editor.setFlagInsertionHandleGesturesEnabled(true); + // Note: We don't need to reset these flags explicitly at the end of each test, because a + // fresh TextView and Editor will be created for each test. + } + @Test + public void testInsertionHandle_touchThrough() { + enableFlagsForInsertionHandleGestures(); testInsertionHandle(); testInsertionHandle_multiLine(); - - textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled); - Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled; } @Test public void testInsertionHandle_longPressToSelect() { - // This test only makes sense when Cursor Control flag is enabled. + enableFlagsForInsertionHandleGestures(); final TextView textView = mActivity.findViewById(R.id.textview); - boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled(); - boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG; - textView.getEditorForTesting().setCursorControlEnabled(true); - Editor.FLAG_ENABLE_CURSOR_DRAG = true; final String text = "hello the world"; onView(withId(R.id.textview)).perform(replaceText(text)); @@ -546,20 +543,12 @@ public class TextViewActivityTest { onHandleView(com.android.internal.R.id.insertion_handle).perform(longPressHandle(textView)); onView(withId(R.id.textview)).check(hasSelection("world")); - - textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled); - Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled; } @Test public void testInsertionHandle_longPressAndDragToSelect() { - // This test only makes sense when Cursor Control flag is enabled. + enableFlagsForInsertionHandleGestures(); final TextView textView = mActivity.findViewById(R.id.textview); - boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled(); - boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG; - textView.getEditorForTesting().setCursorControlEnabled(true); - Editor.FLAG_ENABLE_CURSOR_DRAG = true; - final String text = "hello the world"; onView(withId(R.id.textview)).perform(replaceText(text)); @@ -569,19 +558,12 @@ public class TextViewActivityTest { onHandleView(com.android.internal.R.id.insertion_handle) .perform(longPressAndDragHandle(textView, Handle.INSERTION, text.indexOf('t'))); onView(withId(R.id.textview)).check(hasSelection("the world")); - - textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled); - Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled; } @Test public void testInsertionHandle_doubleTapToSelect() { - // This test only makes sense when Cursor Control flag is enabled. + enableFlagsForInsertionHandleGestures(); final TextView textView = mActivity.findViewById(R.id.textview); - boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled(); - boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG; - textView.getEditorForTesting().setCursorControlEnabled(true); - Editor.FLAG_ENABLE_CURSOR_DRAG = true; final String text = "hello the world"; onView(withId(R.id.textview)).perform(replaceText(text)); @@ -591,19 +573,12 @@ public class TextViewActivityTest { onHandleView(com.android.internal.R.id.insertion_handle).perform(doubleTapHandle(textView)); onView(withId(R.id.textview)).check(hasSelection("world")); - - textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled); - Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled; } @Test public void testInsertionHandle_doubleTapAndDragToSelect() { - // This test only makes sense when Cursor Control flag is enabled. + enableFlagsForInsertionHandleGestures(); final TextView textView = mActivity.findViewById(R.id.textview); - boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled(); - boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG; - textView.getEditorForTesting().setCursorControlEnabled(true); - Editor.FLAG_ENABLE_CURSOR_DRAG = true; final String text = "hello the world"; onView(withId(R.id.textview)).perform(replaceText(text)); @@ -614,9 +589,6 @@ public class TextViewActivityTest { onHandleView(com.android.internal.R.id.insertion_handle) .perform(doubleTapAndDragHandle(textView, Handle.INSERTION, text.indexOf('t'))); onView(withId(R.id.textview)).check(hasSelection("the world")); - - textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled); - Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled; } @Test diff --git a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java index 23655a08397d..fbf75dfb4979 100644 --- a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java +++ b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java @@ -21,11 +21,11 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; -import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsingPackageRead; import android.os.Build; import android.util.ArrayMap; -import com.android.internal.content.om.OverlayConfig.AndroidPackageProvider; +import com.android.internal.content.om.OverlayConfig.PackageProvider; import com.android.internal.content.om.OverlayScanner; import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo; @@ -39,14 +39,14 @@ import org.mockito.invocation.InvocationOnMock; import java.io.File; import java.io.IOException; import java.util.Map; -import java.util.function.Consumer; +import java.util.function.BiConsumer; import java.util.function.Supplier; /** * A {@link TestRule} that runs a test case twice. First, the test case runs with a non-null * {@link OverlayScanner} as if the zygote process is scanning the overlay packages * and parsing configuration files. The test case then runs with a non-null - * {@link AndroidPackageProvider} as if the system server is parsing configuration files. + * {@link PackageProvider} as if the system server is parsing configuration files. * * This simulates what will happen on device. If an exception would be thrown in the zygote, then * the exception should be thrown in the first run of the test case. @@ -60,7 +60,7 @@ public class OverlayConfigIterationRule implements TestRule { private final ArrayMap<File, ParsedOverlayInfo> mOverlayStubResults = new ArrayMap<>(); private Supplier<OverlayScanner> mOverlayScanner; - private AndroidPackageProvider mAndroidPackageProvider; + private PackageProvider mPkgProvider; private Iteration mIteration; /** @@ -96,9 +96,9 @@ public class OverlayConfigIterationRule implements TestRule { return mOverlayScanner; } - /** Retrieves the {@link AndroidPackageProvider} for the current run of the test. */ - AndroidPackageProvider getPackageProvider() { - return mAndroidPackageProvider; + /** Retrieves the {@link PackageProvider} for the current run of the test. */ + PackageProvider getPackageProvider() { + return mPkgProvider; } /** Retrieves the current iteration of the test. */ @@ -123,7 +123,7 @@ public class OverlayConfigIterationRule implements TestRule { } return scanner; }; - mAndroidPackageProvider = null; + mPkgProvider = null; mIteration = Iteration.ZYGOTE; base.evaluate(); @@ -131,14 +131,15 @@ public class OverlayConfigIterationRule implements TestRule { // the system server is parsing the configuration files and using PackageManager to // retrieving information of overlays. mOverlayScanner = null; - mAndroidPackageProvider = Mockito.mock(AndroidPackageProvider.class); + mPkgProvider = Mockito.mock(PackageProvider.class); mIteration = Iteration.SYSTEM_SERVER; doAnswer((InvocationOnMock invocation) -> { final Object[] args = invocation.getArguments(); - final Consumer<AndroidPackage> f = (Consumer<AndroidPackage>) args[0]; + final BiConsumer<ParsingPackageRead, Boolean> f = + (BiConsumer<ParsingPackageRead, Boolean>) args[0]; for (Map.Entry<File, ParsedOverlayInfo> overlay : mOverlayStubResults.entrySet()) { - final AndroidPackage a = Mockito.mock(AndroidPackage.class); + final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class); final ParsedOverlayInfo info = overlay.getValue(); when(a.getPackageName()).thenReturn(info.packageName); when(a.getOverlayTarget()).thenReturn(info.targetPackageName); @@ -146,12 +147,10 @@ public class OverlayConfigIterationRule implements TestRule { when(a.isOverlayIsStatic()).thenReturn(info.isStatic); when(a.getOverlayPriority()).thenReturn(info.priority); when(a.getBaseCodePath()).thenReturn(info.path.getPath()); - when(a.isSystem()).thenReturn( - !info.path.getPath().contains("data/overlay")); - f.accept(a); + f.accept(a, !info.path.getPath().contains("data/overlay")); } return null; - }).when(mAndroidPackageProvider).forEachPackage(any()); + }).when(mPkgProvider).forEachPackage(any()); base.evaluate(); } diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 08b30f76d312..78c7b76d38da 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -410,6 +410,7 @@ applications that come with the platform <privapp-permissions package="com.android.dynsystem"> <permission name="android.permission.REBOOT"/> <permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/> + <permission name="android.permission.READ_OEM_UNLOCK_STATE"/> </privapp-permissions> <privapp-permissions package="com.android.settings"> <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/> diff --git a/libs/usb/Android.bp b/libs/usb/Android.bp index 027a7488f723..e752b55f5ef7 100644 --- a/libs/usb/Android.bp +++ b/libs/usb/Android.bp @@ -19,5 +19,3 @@ java_sdk_library { srcs: ["src/**/*.java"], api_packages: ["com.android.future.usb"], } - -subdirs = ["tests/*"] diff --git a/libs/usb/tests/AccessoryChat/Android.bp b/libs/usb/tests/AccessoryChat/Android.bp index 63a670c67bfc..19ed3d3ef52e 100644 --- a/libs/usb/tests/AccessoryChat/Android.bp +++ b/libs/usb/tests/AccessoryChat/Android.bp @@ -1,4 +1,3 @@ -subdirs = ["accessorychat"] // // Copyright (C) 2011 The Android Open Source Project // diff --git a/location/java/android/location/GnssAntennaInfo.java b/location/java/android/location/GnssAntennaInfo.java index dfcaf814f9c9..b2f9a0f41b7e 100644 --- a/location/java/android/location/GnssAntennaInfo.java +++ b/location/java/android/location/GnssAntennaInfo.java @@ -16,72 +16,37 @@ package android.location; -import android.annotation.IntDef; +import android.annotation.FloatRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; -import com.android.internal.annotations.VisibleForTesting; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * A class that contains information about a GNSS antenna. GNSS antenna characteristics can change * with device configuration, such as when a device is folded open or closed. Antenna information is - * delivered to registered instances of {@link Callback}. + * delivered to registered instances of {@link Listener}. */ public final class GnssAntennaInfo implements Parcelable { private final double mCarrierFrequencyMHz; - private final PhaseCenterOffsetCoordinates mPhaseCenterOffsetCoordinates; - private final PhaseCenterVariationCorrections mPhaseCenterVariationCorrections; - private final SignalGainCorrections mSignalGainCorrections; + private final PhaseCenterOffset mPhaseCenterOffset; + private final SphericalCorrections mPhaseCenterVariationCorrections; + private final SphericalCorrections mSignalGainCorrections; /** * Used for receiving GNSS antenna info from the GNSS engine. You can implement this interface - * and call {@link LocationManager#registerAntennaInfoCallback}; + * and call {@link LocationManager#registerAntennaInfoListener}; */ - public abstract static class Callback { - /** - * The status of GNSS antenna info. - * - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED}) - public @interface GnssAntennaInfoStatus { - } - - /** - * The system does not support GNSS antenna info. - * - * This status will not change in the future. - */ - public static final int STATUS_NOT_SUPPORTED = 0; - - /** - * GNSS antenna info updates are being successfully tracked. - */ - public static final int STATUS_READY = 1; - - /** - * GNSS provider or Location is disabled, updated will not be received until they are - * enabled. - */ - public static final int STATUS_LOCATION_DISABLED = 2; - + public interface Listener { /** - * Returns the latest GNSS antenna info. This event is triggered when a callback is + * Returns the latest GNSS antenna info. This event is triggered when a listener is * registered, and whenever the antenna info changes (due to a device configuration change). */ - public void onGnssAntennaInfoReceived(@NonNull List<GnssAntennaInfo> gnssAntennaInfos) {} - - /** - * Returns the latest status of the GNSS antenna info sub-system. - */ - public void onStatusChanged(@GnssAntennaInfoStatus int status) {} + void onGnssAntennaInfoReceived(@NonNull List<GnssAntennaInfo> gnssAntennaInfos); } /** @@ -90,37 +55,31 @@ public final class GnssAntennaInfo implements Parcelable { * for mobiles - see sensor or form factor documents for details. Uncertainties are reported * to 1-sigma. */ - public static final class PhaseCenterOffsetCoordinates implements Parcelable { - private final double mPhaseCenterOffsetCoordinateXMillimeters; - private final double mPhaseCenterOffsetCoordinateXUncertaintyMillimeters; - private final double mPhaseCenterOffsetCoordinateYMillimeters; - private final double mPhaseCenterOffsetCoordinateYUncertaintyMillimeters; - private final double mPhaseCenterOffsetCoordinateZMillimeters; - private final double mPhaseCenterOffsetCoordinateZUncertaintyMillimeters; - - @VisibleForTesting - public PhaseCenterOffsetCoordinates(double phaseCenterOffsetCoordinateXMillimeters, - double phaseCenterOffsetCoordinateXUncertaintyMillimeters, - double phaseCenterOffsetCoordinateYMillimeters, - double phaseCenterOffsetCoordinateYUncertaintyMillimeters, - double phaseCenterOffsetCoordinateZMillimeters, - double phaseCenterOffsetCoordinateZUncertaintyMillimeters) { - mPhaseCenterOffsetCoordinateXMillimeters = phaseCenterOffsetCoordinateXMillimeters; - mPhaseCenterOffsetCoordinateYMillimeters = phaseCenterOffsetCoordinateYMillimeters; - mPhaseCenterOffsetCoordinateZMillimeters = phaseCenterOffsetCoordinateZMillimeters; - mPhaseCenterOffsetCoordinateXUncertaintyMillimeters = - phaseCenterOffsetCoordinateXUncertaintyMillimeters; - mPhaseCenterOffsetCoordinateYUncertaintyMillimeters = - phaseCenterOffsetCoordinateYUncertaintyMillimeters; - mPhaseCenterOffsetCoordinateZUncertaintyMillimeters = - phaseCenterOffsetCoordinateZUncertaintyMillimeters; - } - - public static final @NonNull Creator<PhaseCenterOffsetCoordinates> CREATOR = - new Creator<PhaseCenterOffsetCoordinates>() { + public static final class PhaseCenterOffset implements Parcelable { + private final double mOffsetXMm; + private final double mOffsetXUncertaintyMm; + private final double mOffsetYMm; + private final double mOffsetYUncertaintyMm; + private final double mOffsetZMm; + private final double mOffsetZUncertaintyMm; + + public PhaseCenterOffset( + double offsetXMm, double offsetXUncertaintyMm, + double offsetYMm, double offsetYUncertaintyMm, + double offsetZMm, double offsetZUncertaintyMm) { + mOffsetXMm = offsetXMm; + mOffsetYMm = offsetYMm; + mOffsetZMm = offsetZMm; + mOffsetXUncertaintyMm = offsetXUncertaintyMm; + mOffsetYUncertaintyMm = offsetYUncertaintyMm; + mOffsetZUncertaintyMm = offsetZUncertaintyMm; + } + + public static final @NonNull Creator<PhaseCenterOffset> CREATOR = + new Creator<PhaseCenterOffset>() { @Override - public PhaseCenterOffsetCoordinates createFromParcel(Parcel in) { - return new PhaseCenterOffsetCoordinates( + public PhaseCenterOffset createFromParcel(Parcel in) { + return new PhaseCenterOffset( in.readDouble(), in.readDouble(), in.readDouble(), @@ -131,158 +90,41 @@ public final class GnssAntennaInfo implements Parcelable { } @Override - public PhaseCenterOffsetCoordinates[] newArray(int size) { - return new PhaseCenterOffsetCoordinates[size]; + public PhaseCenterOffset[] newArray(int size) { + return new PhaseCenterOffset[size]; } }; - public double getXCoordMillimeters() { - return mPhaseCenterOffsetCoordinateXMillimeters; - } - - public double getXCoordUncertaintyMillimeters() { - return mPhaseCenterOffsetCoordinateXUncertaintyMillimeters; - } - - public double getYCoordMillimeters() { - return mPhaseCenterOffsetCoordinateYMillimeters; - } - - public double getYCoordUncertaintyMillimeters() { - return mPhaseCenterOffsetCoordinateYUncertaintyMillimeters; - } - - public double getZCoordMillimeters() { - return mPhaseCenterOffsetCoordinateZMillimeters; - } - - public double getZCoordUncertaintyMillimeters() { - return mPhaseCenterOffsetCoordinateZUncertaintyMillimeters; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeDouble(mPhaseCenterOffsetCoordinateXMillimeters); - dest.writeDouble(mPhaseCenterOffsetCoordinateXUncertaintyMillimeters); - dest.writeDouble(mPhaseCenterOffsetCoordinateYMillimeters); - dest.writeDouble(mPhaseCenterOffsetCoordinateYUncertaintyMillimeters); - dest.writeDouble(mPhaseCenterOffsetCoordinateZMillimeters); - dest.writeDouble(mPhaseCenterOffsetCoordinateZUncertaintyMillimeters); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("PhaseCenteroffset:\n"); - builder.append("X: " + mPhaseCenterOffsetCoordinateXMillimeters + " +/- " - + mPhaseCenterOffsetCoordinateXUncertaintyMillimeters + "\n"); - builder.append("Y: " + mPhaseCenterOffsetCoordinateYMillimeters + " +/- " - + mPhaseCenterOffsetCoordinateYUncertaintyMillimeters + "\n"); - builder.append("Z: " + mPhaseCenterOffsetCoordinateZMillimeters + " +/- " - + mPhaseCenterOffsetCoordinateZUncertaintyMillimeters + "\n"); - return builder.toString(); - } - } - - /** - * Class containing information about the phase center variation (PCV) corrections. The PCV - * correction is added to the phase measurement to obtain the corrected value. - * - * The corrections and associated (1-sigma) uncertainties are represented by respect 2D arrays. - * - * Each row (major indices) represents a fixed theta. The first row corresponds to a - * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta) - * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., deltaTheta - * = 360 / (number of rows). - * - * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and ending - * at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles, - * i.e., deltaPhi = 180 / (number of columns - 1). - */ - public static final class PhaseCenterVariationCorrections extends SphericalCorrections { - - @VisibleForTesting - public PhaseCenterVariationCorrections( - @NonNull double[][] phaseCenterVariationCorrectionsMillimeters, - @NonNull double[][] phaseCenterVariationCorrectionUncertaintiesMillimeters) { - super(phaseCenterVariationCorrectionsMillimeters, - phaseCenterVariationCorrectionUncertaintiesMillimeters); - } - - private PhaseCenterVariationCorrections(@NonNull Parcel in) { - super(in); - } - - /** - * Get the phase center variation correction in millimeters at the specified row and column - * in the underlying 2D array. - * @param row zero-based major index in the array - * @param column zero-based minor index in the array - * @return phase center correction in millimeters - */ - public double getPhaseCenterVariationCorrectionMillimetersAt(int row, int column) { - return super.getCorrectionAt(row, column); - } - - /** - * Get the phase center variation correction uncertainty in millimeters at the specified row - * and column in the underlying 2D array. - * @param row zero-based major index in the array - * @param column zero-based minor index in the array - * @return 1-sigma phase center correction uncertainty in millimeters - */ - public double getPhaseCenterVariationCorrectionUncertaintyMillimetersAt( - int row, int column) { - return super.getCorrectionUncertaintyAt(row, column); - } - - public @NonNull double[][] getRawCorrectionsArray() { - return super.getRawCorrectionsArray().clone(); + @FloatRange() + public double getXOffsetMm() { + return mOffsetXMm; } - public @NonNull double[][] getRawCorrectionUncertaintiesArray() { - return super.getRawCorrectionUncertaintiesArray().clone(); + @FloatRange() + public double getXOffsetUncertaintyMm() { + return mOffsetXUncertaintyMm; } - public int getNumRows() { - return super.getNumRows(); + @FloatRange() + public double getYOffsetMm() { + return mOffsetYMm; } - public int getNumColumns() { - return super.getNumColumns(); + @FloatRange() + public double getYOffsetUncertaintyMm() { + return mOffsetYUncertaintyMm; } - /** - * The fixed theta angle separation between successive rows. - */ - public double getDeltaTheta() { - return super.getDeltaTheta(); + @FloatRange() + public double getZOffsetMm() { + return mOffsetZMm; } - /** - * The fixed phi angle separation between successive columns. - */ - public double getDeltaPhi() { - return super.getDeltaPhi(); + @FloatRange() + public double getZOffsetUncertaintyMm() { + return mOffsetZUncertaintyMm; } - public static final @NonNull Creator<PhaseCenterVariationCorrections> CREATOR = - new Creator<PhaseCenterVariationCorrections>() { - @Override - public PhaseCenterVariationCorrections createFromParcel(Parcel in) { - return new PhaseCenterVariationCorrections(in); - } - - @Override - public PhaseCenterVariationCorrections[] newArray(int size) { - return new PhaseCenterVariationCorrections[size]; - } - }; - @Override public int describeContents() { return 0; @@ -290,20 +132,27 @@ public final class GnssAntennaInfo implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - super.writeToParcel(dest, flags); + dest.writeDouble(mOffsetXMm); + dest.writeDouble(mOffsetXUncertaintyMm); + dest.writeDouble(mOffsetYMm); + dest.writeDouble(mOffsetYUncertaintyMm); + dest.writeDouble(mOffsetZMm); + dest.writeDouble(mOffsetZUncertaintyMm); } @Override public String toString() { - StringBuilder builder = new StringBuilder("PhaseCenterVariationCorrections:\n"); - builder.append(super.toString()); - return builder.toString(); + return "PhaseCenterOffset{" + + "OffsetXMm=" + mOffsetXMm + " +/-" + mOffsetXUncertaintyMm + + ", OffsetYMm=" + mOffsetYMm + " +/-" + mOffsetYUncertaintyMm + + ", OffsetZMm=" + mOffsetZMm + " +/-" + mOffsetZUncertaintyMm + + '}'; } } /** - * Class containing information about the signal gain (SG) corrections. The SG - * correction is added to the signal gain to obtain the corrected value. + * Represents corrections on a spherical mapping. Corrections are added to measurements to + * obtain the corrected values. * * The corrections and associated (1-sigma) uncertainties are represented by respect 2D arrays. * @@ -316,116 +165,7 @@ public final class GnssAntennaInfo implements Parcelable { * at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles, * i.e., deltaPhi = 180 / (number of columns - 1). */ - public static final class SignalGainCorrections extends SphericalCorrections { - - @VisibleForTesting - public SignalGainCorrections( - @NonNull double[][] signalGainCorrectionsDbi, - @NonNull double[][] signalGainCorrectionUncertaintiesDbi) { - super(signalGainCorrectionsDbi, - signalGainCorrectionUncertaintiesDbi); - } - - private SignalGainCorrections(@NonNull Parcel in) { - super(in); - } - - /** - * Get the signal gain correction in dbi at the specified row and column - * in the underlying 2D array. - * @param row zero-based major index in the array - * @param column zero-based minor index in the array - * @return signal gain correction in dbi - */ - public double getSignalGainCorrectionDbiAt(int row, int column) { - return super.getCorrectionAt(row, column); - } - - /** - * Get the signal gain correction correction uncertainty in dbi at the specified row - * and column in the underlying 2D array. - * @param row zero-based major index in the array - * @param column zero-based minor index in the array - * @return 1-sigma signal gain correction uncertainty in dbi - */ - public double getSignalGainCorrectionUncertaintyDbiAt(int row, int column) { - return super.getCorrectionUncertaintyAt(row, column); - } - - public @NonNull double[][] getRawCorrectionsArray() { - return super.getRawCorrectionsArray().clone(); - } - - public @NonNull double[][] getRawCorrectionUncertaintiesArray() { - return super.getRawCorrectionUncertaintiesArray().clone(); - } - - public int getNumRows() { - return super.getNumRows(); - } - - public int getNumColumns() { - return super.getNumColumns(); - } - - /** - * The fixed theta angle separation between successive rows. - */ - public double getDeltaTheta() { - return super.getDeltaTheta(); - } - - /** - * The fixed phi angle separation between successive columns. - */ - public double getDeltaPhi() { - return super.getDeltaPhi(); - } - - public static final @NonNull Creator<SignalGainCorrections> CREATOR = - new Creator<SignalGainCorrections>() { - @Override - public SignalGainCorrections createFromParcel(Parcel in) { - return new SignalGainCorrections(in); - } - - @Override - public SignalGainCorrections[] newArray(int size) { - return new SignalGainCorrections[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - super.writeToParcel(dest, flags); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("SignalGainCorrections:\n"); - builder.append(super.toString()); - return builder.toString(); - } - } - - /** - * Represents corrections on a spherical mapping. - * - * Each row (major indices) represents a fixed theta. The first row corresponds to a - * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta) - * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., deltaTheta - * = 360 / (number of rows). - * - * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and ending - * at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles, - * i.e., deltaPhi = 180 / (number of columns - 1). - */ - private abstract static class SphericalCorrections implements Parcelable { + public static final class SphericalCorrections implements Parcelable{ private final double[][] mCorrections; private final double[][] mCorrectionUncertainties; private final double mDeltaTheta; @@ -433,7 +173,7 @@ public final class GnssAntennaInfo implements Parcelable { private final int mNumRows; private final int mNumColumns; - SphericalCorrections(@NonNull double[][] corrections, + public SphericalCorrections(@NonNull double[][] corrections, @NonNull double[][] correctionUncertainties) { if (corrections.length != correctionUncertainties.length || corrections[0].length != correctionUncertainties[0].length) { @@ -474,54 +214,84 @@ public final class GnssAntennaInfo implements Parcelable { in.readDoubleArray(correctionUncertainties[row]); } - mNumRows = corrections.length; - mNumColumns = corrections[0].length; + mNumRows = numRows; + mNumColumns = numColumns; mCorrections = corrections; mCorrectionUncertainties = correctionUncertainties; mDeltaTheta = 360.0d / mNumRows; mDeltaPhi = 180.0d / (mNumColumns - 1); } - private double getCorrectionAt(int row, int column) { - return mCorrections[row][column]; - } - - private double getCorrectionUncertaintyAt(int row, int column) { - return mCorrectionUncertainties[row][column]; - } - + /** + * Array representing corrections on a spherical mapping. Corrections are added to + * measurements to obtain the corrected values. + * + * Each row (major indices) represents a fixed theta. The first row corresponds to a + * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta) + * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., + * deltaTheta = 360 / (number of rows). + * + * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and + * ending at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith + * angles, i.e., deltaPhi = 180 / (number of columns - 1). + */ @NonNull - private double[][] getRawCorrectionsArray() { + public double[][] getCorrectionsArray() { return mCorrections; } + /** + * Array representing uncertainty on corrections on a spherical mapping. + * + * Each row (major indices) represents a fixed theta. The first row corresponds to a + * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta) + * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., + * deltaTheta = 360 / (number of rows). + * + * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and + * ending at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith + * angles, i.e., deltaPhi = 180 / (number of columns - 1). + */ @NonNull - private double[][] getRawCorrectionUncertaintiesArray() { + public double[][] getCorrectionUncertaintiesArray() { return mCorrectionUncertainties; } - private int getNumRows() { - return mNumRows; - } - - private int getNumColumns() { - return mNumColumns; - } - /** * The fixed theta angle separation between successive rows. */ - private double getDeltaTheta() { + @FloatRange(from = 0.0f, to = 360.0f) + public double getDeltaTheta() { return mDeltaTheta; } /** * The fixed phi angle separation between successive columns. */ - private double getDeltaPhi() { + @FloatRange(from = 0.0f, to = 180.0f) + public double getDeltaPhi() { return mDeltaPhi; } + + public static final @NonNull Creator<SphericalCorrections> CREATOR = + new Creator<SphericalCorrections>() { + @Override + public SphericalCorrections createFromParcel(Parcel in) { + return new SphericalCorrections(in); + } + + @Override + public SphericalCorrections[] newArray(int size) { + return new SphericalCorrections[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mNumRows); @@ -534,62 +304,114 @@ public final class GnssAntennaInfo implements Parcelable { } } - private String arrayToString(double[][] array) { - StringBuilder builder = new StringBuilder(); - for (int row = 0; row < mNumRows; row++) { - builder.append("[ "); - for (int column = 0; column < mNumColumns - 1; column++) { - builder.append(array[row][column] + ", "); - } - builder.append(array[row][mNumColumns - 1] + " ]\n"); - } - return builder.toString(); - } - @Override public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("DeltaTheta: " + mDeltaTheta + "\n"); - builder.append("DeltaPhi: " + mDeltaPhi + "\n"); - builder.append("CorrectionsArray:\n"); - builder.append(arrayToString(mCorrections)); - builder.append("CorrectionUncertaintiesArray:\n"); - builder.append(arrayToString(mCorrectionUncertainties)); - return builder.toString(); + return "SphericalCorrections{" + + "Corrections=" + Arrays.toString(mCorrections) + + ", CorrectionUncertainties=" + Arrays.toString(mCorrectionUncertainties) + + ", DeltaTheta=" + mDeltaTheta + + ", DeltaPhi=" + mDeltaPhi + + '}'; } } - @VisibleForTesting - public GnssAntennaInfo( + private GnssAntennaInfo( double carrierFrequencyMHz, - @NonNull PhaseCenterOffsetCoordinates phaseCenterOffsetCoordinates, - @Nullable PhaseCenterVariationCorrections phaseCenterVariationCorrections, - @Nullable SignalGainCorrections signalGainCorrectionDbi) { - if (phaseCenterOffsetCoordinates == null) { + @NonNull PhaseCenterOffset phaseCenterOffset, + @Nullable SphericalCorrections phaseCenterVariationCorrections, + @Nullable SphericalCorrections signalGainCorrectionDbi) { + if (phaseCenterOffset == null) { throw new IllegalArgumentException("Phase Center Offset Coordinates cannot be null."); } mCarrierFrequencyMHz = carrierFrequencyMHz; - mPhaseCenterOffsetCoordinates = phaseCenterOffsetCoordinates; + mPhaseCenterOffset = phaseCenterOffset; mPhaseCenterVariationCorrections = phaseCenterVariationCorrections; mSignalGainCorrections = signalGainCorrectionDbi; } + /** + * Builder class for GnssAntennaInfo. + */ + public static class Builder { + private double mCarrierFrequencyMHz; + private PhaseCenterOffset mPhaseCenterOffset; + private SphericalCorrections mPhaseCenterVariationCorrections; + private SphericalCorrections mSignalGainCorrections; + + /** + * Set antenna carrier frequency (MHz). + * @param carrierFrequencyMHz antenna carrier frequency (MHz) + * @return Builder builder object + */ + @NonNull + public Builder setCarrierFrequencyMHz(@FloatRange(from = 0.0f) double carrierFrequencyMHz) { + mCarrierFrequencyMHz = carrierFrequencyMHz; + return this; + } + + /** + * Set antenna phase center offset. + * @param phaseCenterOffset phase center offset object + * @return Builder builder object + */ + @NonNull + public Builder setPhaseCenterOffset(@NonNull PhaseCenterOffset phaseCenterOffset) { + mPhaseCenterOffset = Objects.requireNonNull(phaseCenterOffset); + return this; + } + + /** + * Set phase center variation corrections. + * @param phaseCenterVariationCorrections phase center variation corrections object + * @return Builder builder object + */ + @NonNull + public Builder setPhaseCenterVariationCorrections( + @Nullable SphericalCorrections phaseCenterVariationCorrections) { + mPhaseCenterVariationCorrections = phaseCenterVariationCorrections; + return this; + } + + /** + * Set signal gain corrections. + * @param signalGainCorrections signal gain corrections object + * @return Builder builder object + */ + @NonNull + public Builder setSignalGainCorrections( + @Nullable SphericalCorrections signalGainCorrections) { + mSignalGainCorrections = signalGainCorrections; + return this; + } + + /** + * Build GnssAntennaInfo object. + * @return instance of GnssAntennaInfo + */ + @NonNull + public GnssAntennaInfo build() { + return new GnssAntennaInfo(mCarrierFrequencyMHz, mPhaseCenterOffset, + mPhaseCenterVariationCorrections, mSignalGainCorrections); + } + } + + @FloatRange(from = 0.0f) public double getCarrierFrequencyMHz() { return mCarrierFrequencyMHz; } @NonNull - public PhaseCenterOffsetCoordinates getPhaseCenterOffsetCoordinates() { - return mPhaseCenterOffsetCoordinates; + public PhaseCenterOffset getPhaseCenterOffset() { + return mPhaseCenterOffset; } @Nullable - public PhaseCenterVariationCorrections getPhaseCenterVariationCorrections() { + public SphericalCorrections getPhaseCenterVariationCorrections() { return mPhaseCenterVariationCorrections; } @Nullable - public SignalGainCorrections getSignalGainCorrections() { + public SphericalCorrections getSignalGainCorrections() { return mSignalGainCorrections; } @@ -600,16 +422,18 @@ public final class GnssAntennaInfo implements Parcelable { double carrierFrequencyMHz = in.readDouble(); ClassLoader classLoader = getClass().getClassLoader(); - PhaseCenterOffsetCoordinates phaseCenterOffsetCoordinates = + PhaseCenterOffset phaseCenterOffset = in.readParcelable(classLoader); - PhaseCenterVariationCorrections phaseCenterVariationCorrections = + SphericalCorrections phaseCenterVariationCorrections = in.readParcelable(classLoader); - SignalGainCorrections signalGainCorrections = + SphericalCorrections signalGainCorrections = in.readParcelable(classLoader); - return new GnssAntennaInfo(carrierFrequencyMHz, - phaseCenterOffsetCoordinates, - phaseCenterVariationCorrections, signalGainCorrections); + return new GnssAntennaInfo( + carrierFrequencyMHz, + phaseCenterOffset, + phaseCenterVariationCorrections, + signalGainCorrections); } @Override @@ -626,29 +450,18 @@ public final class GnssAntennaInfo implements Parcelable { @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { parcel.writeDouble(mCarrierFrequencyMHz); - - // Write Phase Center Offset - parcel.writeParcelable(mPhaseCenterOffsetCoordinates, flags); - - // Write Phase Center Variation Corrections + parcel.writeParcelable(mPhaseCenterOffset, flags); parcel.writeParcelable(mPhaseCenterVariationCorrections, flags); - - // Write Signal Gain Corrections parcel.writeParcelable(mSignalGainCorrections, flags); } @Override public String toString() { - StringBuilder builder = new StringBuilder("[ GnssAntennaInfo:\n"); - builder.append("CarrierFrequencyMHz: " + mCarrierFrequencyMHz + "\n"); - builder.append(mPhaseCenterOffsetCoordinates.toString()); - builder.append(mPhaseCenterVariationCorrections == null - ? "PhaseCenterVariationCorrections: null\n" - : mPhaseCenterVariationCorrections.toString()); - builder.append(mSignalGainCorrections == null - ? "SignalGainCorrections: null\n" - : mSignalGainCorrections.toString()); - builder.append("]"); - return builder.toString(); + return "GnssAntennaInfo{" + + "CarrierFrequencyMHz=" + mCarrierFrequencyMHz + + ", PhaseCenterOffset=" + mPhaseCenterOffset + + ", PhaseCenterVariationCorrections=" + mPhaseCenterVariationCorrections + + ", SignalGainCorrections=" + mSignalGainCorrections + + '}'; } } diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java index 930180c6870f..5734bf2e9af6 100644 --- a/location/java/android/location/GnssCapabilities.java +++ b/location/java/android/location/GnssCapabilities.java @@ -16,15 +16,11 @@ package android.location; -import android.annotation.NonNull; import android.annotation.SystemApi; /** * A container of supported GNSS chipset capabilities. - * - * @hide */ -@SystemApi public final class GnssCapabilities { /** * Bit mask indicating GNSS chipset supports low power mode. @@ -105,7 +101,10 @@ public final class GnssCapabilities { /** * Returns {@code true} if GNSS chipset supports low power mode, {@code false} otherwise. + * + * @hide */ + @SystemApi public boolean hasLowPowerMode() { return hasCapability(LOW_POWER_MODE); } @@ -113,28 +112,40 @@ public final class GnssCapabilities { /** * Returns {@code true} if GNSS chipset supports blacklisting satellites, {@code false} * otherwise. + * + * @hide */ + @SystemApi public boolean hasSatelliteBlacklist() { return hasCapability(SATELLITE_BLACKLIST); } /** * Returns {@code true} if GNSS chipset supports geofencing, {@code false} otherwise. + * + * @hide */ + @SystemApi public boolean hasGeofencing() { return hasCapability(GEOFENCING); } /** * Returns {@code true} if GNSS chipset supports measurements, {@code false} otherwise. + * + * @hide */ + @SystemApi public boolean hasMeasurements() { return hasCapability(MEASUREMENTS); } /** * Returns {@code true} if GNSS chipset supports navigation messages, {@code false} otherwise. + * + * @hide */ + @SystemApi public boolean hasNavMessages() { return hasCapability(NAV_MESSAGES); } @@ -142,7 +153,10 @@ public final class GnssCapabilities { /** * Returns {@code true} if GNSS chipset supports measurement corrections, {@code false} * otherwise. + * + * @hide */ + @SystemApi public boolean hasMeasurementCorrections() { return hasCapability(MEASUREMENT_CORRECTIONS); } @@ -150,7 +164,10 @@ public final class GnssCapabilities { /** * Returns {@code true} if GNSS chipset supports line-of-sight satellite identification * measurement corrections, {@code false} otherwise. + * + * @hide */ + @SystemApi public boolean hasMeasurementCorrectionsLosSats() { return hasCapability(MEASUREMENT_CORRECTIONS_LOS_SATS); } @@ -158,7 +175,10 @@ public final class GnssCapabilities { /** * Returns {@code true} if GNSS chipset supports per satellite excess-path-length measurement * corrections, {@code false} otherwise. + * + * @hide */ + @SystemApi public boolean hasMeasurementCorrectionsExcessPathLength() { return hasCapability(MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH); } @@ -166,7 +186,10 @@ public final class GnssCapabilities { /** * Returns {@code true} if GNSS chipset supports reflecting planes measurement corrections, * {@code false} otherwise. + * + * @hide */ + @SystemApi public boolean hasMeasurementCorrectionsReflectingPane() { return hasCapability(MEASUREMENT_CORRECTIONS_REFLECTING_PLANE); } @@ -178,28 +201,6 @@ public final class GnssCapabilities { return hasCapability(ANTENNA_INFO); } - @NonNull - @Override - public String toString() { - StringBuilder sb = new StringBuilder("GnssCapabilities: ( "); - if (hasLowPowerMode()) sb.append("LOW_POWER_MODE "); - if (hasSatelliteBlacklist()) sb.append("SATELLITE_BLACKLIST "); - if (hasGeofencing()) sb.append("GEOFENCING "); - if (hasGnssAntennaInfo()) sb.append("ANTENNA_INFO "); - if (hasMeasurements()) sb.append("MEASUREMENTS "); - if (hasNavMessages()) sb.append("NAV_MESSAGES "); - if (hasMeasurementCorrections()) sb.append("MEASUREMENT_CORRECTIONS "); - if (hasMeasurementCorrectionsLosSats()) sb.append("MEASUREMENT_CORRECTIONS_LOS_SATS "); - if (hasMeasurementCorrectionsExcessPathLength()) { - sb.append("MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH "); - } - if (hasMeasurementCorrectionsReflectingPane()) { - sb.append("MEASUREMENT_CORRECTIONS_REFLECTING_PLANE "); - } - sb.append(")"); - return sb.toString(); - } - private boolean hasCapability(long capability) { return (mGnssCapabilities & capability) == capability; } diff --git a/location/java/android/location/IGnssAntennaInfoListener.aidl b/location/java/android/location/IGnssAntennaInfoListener.aidl index 30bf546759f1..603ed6a2614e 100644 --- a/location/java/android/location/IGnssAntennaInfoListener.aidl +++ b/location/java/android/location/IGnssAntennaInfoListener.aidl @@ -23,5 +23,4 @@ import android.location.GnssAntennaInfo; */ oneway interface IGnssAntennaInfoListener { void onGnssAntennaInfoReceived(in List<GnssAntennaInfo> gnssAntennaInfo); - void onStatusChanged(in int status); }
\ No newline at end of file diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 03e1c758feb3..19085bff0033 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -1813,13 +1813,7 @@ public class LocationManager { /** * Returns the supported capabilities of the GNSS chipset. - * - * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present. - * - * @hide */ - @SystemApi - @RequiresPermission(ACCESS_FINE_LOCATION) public @NonNull GnssCapabilities getGnssCapabilities() { try { long gnssCapabilities = mService.getGnssCapabilities(mContext.getPackageName()); @@ -2264,35 +2258,36 @@ public class LocationManager { } /** - * Registers a Gnss Antenna Info callback. + * Registers a Gnss Antenna Info listener. Only expect results if + * {@link GnssCapabilities#hasGnssAntennaInfo()} shows that antenna info is supported. * - * @param executor the executor that the callback runs on. - * @param callback a {@link GnssAntennaInfo.Callback} object to register. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + * @param executor the executor that the listener runs on. + * @param listener a {@link GnssAntennaInfo.Listener} object to register. + * @return {@code true} if the listener was added successfully, {@code false} otherwise. * * @throws IllegalArgumentException if executor is null - * @throws IllegalArgumentException if callback is null + * @throws IllegalArgumentException if listener is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present */ @RequiresPermission(ACCESS_FINE_LOCATION) - public boolean registerAntennaInfoCallback( + public boolean registerAntennaInfoListener( @NonNull @CallbackExecutor Executor executor, - @NonNull GnssAntennaInfo.Callback callback) { + @NonNull GnssAntennaInfo.Listener listener) { try { - return mGnssAntennaInfoListenerManager.addListener(callback, executor); + return mGnssAntennaInfoListenerManager.addListener(listener, executor); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Unregisters a GNSS Antenna Info callback. + * Unregisters a GNSS Antenna Info listener. * - * @param callback a {@link GnssAntennaInfo.Callback} object to remove. + * @param listener a {@link GnssAntennaInfo.Listener} object to remove. */ - public void unregisterAntennaInfoCallback(@NonNull GnssAntennaInfo.Callback callback) { + public void unregisterAntennaInfoListener(@NonNull GnssAntennaInfo.Listener listener) { try { - mGnssAntennaInfoListenerManager.removeListener(callback); + mGnssAntennaInfoListenerManager.removeListener(listener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3043,7 +3038,7 @@ public class LocationManager { } private class GnssAntennaInfoListenerManager extends - AbstractListenerManager<Void, GnssAntennaInfo.Callback> { + AbstractListenerManager<Void, GnssAntennaInfo.Listener> { @Nullable private IGnssAntennaInfoListener mListenerTransport; @@ -3075,11 +3070,6 @@ public class LocationManager { public void onGnssAntennaInfoReceived(final List<GnssAntennaInfo> gnssAntennaInfos) { execute((callback) -> callback.onGnssAntennaInfoReceived(gnssAntennaInfos)); } - - @Override - public void onStatusChanged(int status) { - execute((listener) -> listener.onStatusChanged(status)); - } } } diff --git a/media/java/android/media/DrmInitData.java b/media/java/android/media/DrmInitData.java index cc35f140dd7e..d803311fdae3 100644 --- a/media/java/android/media/DrmInitData.java +++ b/media/java/android/media/DrmInitData.java @@ -37,7 +37,9 @@ public abstract class DrmInitData { * * @param schemeUuid The DRM scheme's UUID. * @return The initialization data for the scheme, or null if the scheme is not supported. + * @deprecated Use {@link #getSchemeInitDataCount} and {@link #getSchemeInitDataAt} instead. */ + @Deprecated public abstract SchemeInitData get(UUID schemeUuid); /** diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 28bb4c192425..5942a3d05e67 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -21,6 +21,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.content.Context; import android.os.Bundle; import android.os.Handler; @@ -721,8 +722,7 @@ public class MediaRouter2 { RoutingController newController) { for (TransferCallbackRecord record: mTransferCallbackRecords) { record.mExecutor.execute( - () -> record.mTransferCallback.onTransferred(oldController, - newController)); + () -> record.mTransferCallback.onTransferred(oldController, newController)); } } @@ -866,6 +866,20 @@ public class MediaRouter2 { } /** + * Gets the original session id set by + * {@link RoutingSessionInfo.Builder#Builder(String, String)}. + * + * @hide + */ + @NonNull + @TestApi + public String getOriginalId() { + synchronized (mControllerLock) { + return mSessionInfo.getOriginalId(); + } + } + + /** * @return the control hints used to control routing session if available. */ @Nullable diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index d058243a6fcb..8deb0c4451ea 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -512,15 +512,19 @@ public class RingtoneManager { * @return The position of the {@link Uri}, or -1 if it cannot be found. */ public int getRingtonePosition(Uri ringtoneUri) { - if (ringtoneUri == null) return -1; - final long ringtoneId = ContentUris.parseId(ringtoneUri); - - final Cursor cursor = getCursor(); - cursor.moveToPosition(-1); - while (cursor.moveToNext()) { - if (ringtoneId == cursor.getLong(ID_COLUMN_INDEX)) { - return cursor.getPosition(); + try { + if (ringtoneUri == null) return -1; + final long ringtoneId = ContentUris.parseId(ringtoneUri); + + final Cursor cursor = getCursor(); + cursor.moveToPosition(-1); + while (cursor.moveToNext()) { + if (ringtoneId == cursor.getLong(ID_COLUMN_INDEX)) { + return cursor.getPosition(); + } } + } catch (NumberFormatException e) { + Log.e(TAG, "NumberFormatException while getting ringtone position, returning -1", e); } return -1; } diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java index 5ecb8f0288fc..2258ee559ea0 100644 --- a/media/java/android/media/tv/tuner/TunerUtils.java +++ b/media/java/android/media/tv/tuner/TunerUtils.java @@ -16,6 +16,7 @@ package android.media.tv.tuner; +import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.tv.tuner.V1_0.Constants; @@ -165,5 +166,33 @@ public final class TunerUtils { "Invalid filter types. Main type=" + mainType + ", subtype=" + subtype); } + /** + * Gets an throwable instance for the corresponding result. + */ + @Nullable + public static void throwExceptionForResult( + @TunerConstants.Result int r, @Nullable String msg) { + if (msg == null) { + msg = ""; + } + switch (r) { + case TunerConstants.RESULT_INVALID_ARGUMENT: + throw new IllegalArgumentException(msg); + case TunerConstants.RESULT_INVALID_STATE: + throw new IllegalStateException(msg); + case TunerConstants.RESULT_NOT_INITIALIZED: + throw new IllegalStateException("Invalid state: not initialized. " + msg); + case TunerConstants.RESULT_OUT_OF_MEMORY: + throw new OutOfMemoryError(msg); + case TunerConstants.RESULT_UNAVAILABLE: + throw new IllegalStateException("Invalid state: resource unavailable. " + msg); + case TunerConstants.RESULT_UNKNOWN_ERROR: + throw new RuntimeException("Unknown error" + msg); + default: + break; + } + throw new RuntimeException("Unexpected result " + r + ". " + msg); + } + private TunerUtils() {} } diff --git a/media/java/android/media/tv/tuner/filter/TimeFilter.java b/media/java/android/media/tv/tuner/filter/TimeFilter.java index a926d59cdd03..371ccc44337a 100644 --- a/media/java/android/media/tv/tuner/filter/TimeFilter.java +++ b/media/java/android/media/tv/tuner/filter/TimeFilter.java @@ -17,7 +17,9 @@ package android.media.tv.tuner.filter; import android.annotation.SystemApi; +import android.media.tv.tuner.TunerConstants; import android.media.tv.tuner.TunerConstants.Result; +import android.media.tv.tuner.TunerUtils; /** * A timer filter is used to filter data based on timestamps. @@ -51,6 +53,8 @@ public class TimeFilter implements AutoCloseable { private native Long nativeGetSourceTime(); private native int nativeClose(); + private long mNativeContext; + private boolean mEnable = false; // Called by JNI code @@ -139,6 +143,9 @@ public class TimeFilter implements AutoCloseable { */ @Override public void close() { - nativeClose(); + int res = nativeClose(); + if (res != TunerConstants.RESULT_SUCCESS) { + TunerUtils.throwExceptionForResult(res, "Failed to close time filter."); + } } } diff --git a/media/jni/Android.bp b/media/jni/Android.bp index c17b1b773bd5..47ec7e6c5593 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -160,8 +160,3 @@ cc_library_shared { "-Wunreachable-code", ], } - -subdirs = [ - "audioeffect", - "soundpool", -] diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index f4d2d030c6f1..4f31f6c091c9 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -118,10 +118,12 @@ using ::android::hardware::tv::tuner::V1_0::Result; struct fields_t { jfieldID tunerContext; jfieldID filterContext; + jfieldID timeFilterContext; jfieldID descramblerContext; jfieldID dvrContext; jmethodID frontendInitID; jmethodID filterInitID; + jmethodID timeFilterInitID; jmethodID dvrInitID; jmethodID onFrontendEventID; jmethodID onFilterStatusID; @@ -237,6 +239,25 @@ sp<IFilter> Filter::getIFilter() { return mFilterSp; } +/////////////// TimeFilter /////////////////////// + +TimeFilter::TimeFilter(sp<ITimeFilter> sp, jobject obj) : mTimeFilterSp(sp) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + mTimeFilterObj = env->NewWeakGlobalRef(obj); +} + +TimeFilter::~TimeFilter() { + ALOGD("~TimeFilter"); + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + env->DeleteWeakGlobalRef(mTimeFilterObj); + mTimeFilterObj = NULL; +} + +sp<ITimeFilter> TimeFilter::getITimeFilter() { + return mTimeFilterSp; +} + /////////////// FrontendCallback /////////////////////// FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {} @@ -841,6 +862,36 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { return filterObj; } +jobject JTuner::openTimeFilter() { + if (mDemux == NULL) { + if (!openDemux()) { + return NULL; + } + } + sp<ITimeFilter> iTimeFilterSp; + Result res; + mDemux->openTimeFilter( + [&](Result r, const sp<ITimeFilter>& filter) { + iTimeFilterSp = filter; + res = r; + }); + + if (res != Result::SUCCESS || iTimeFilterSp == NULL) { + return NULL; + } + + JNIEnv *env = AndroidRuntime::getJNIEnv(); + jobject timeFilterObj = + env->NewObject( + env->FindClass("android/media/tv/tuner/filter/TimeFilter"), + gFields.timeFilterInitID); + sp<TimeFilter> timeFilterSp = new TimeFilter(iTimeFilterSp, timeFilterObj); + timeFilterSp->incStrong(timeFilterObj); + env->SetLongField(timeFilterObj, gFields.timeFilterContext, (jlong)timeFilterSp.get()); + + return timeFilterObj; +} + jobject JTuner::openDvr(DvrType type, int bufferSize) { ALOGD("JTuner::openDvr"); if (mDemux == NULL) { @@ -1420,6 +1471,10 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { gFields.onFilterStatusID = env->GetMethodID(filterClazz, "onFilterStatus", "(I)V"); + jclass timeFilterClazz = env->FindClass("android/media/tv/tuner/filter/TimeFilter"); + gFields.timeFilterContext = env->GetFieldID(timeFilterClazz, "mNativeContext", "J"); + gFields.timeFilterInitID = env->GetMethodID(timeFilterClazz, "<init>", "()V"); + jclass descramblerClazz = env->FindClass("android/media/tv/tuner/Descrambler"); gFields.descramblerContext = env->GetFieldID(descramblerClazz, "mNativeContext", "J"); gFields.descramblerInitID = @@ -1515,18 +1570,35 @@ static jobject android_media_tv_Tuner_open_lnb_by_id(JNIEnv *env, jobject thiz, static jobject android_media_tv_Tuner_open_filter( JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) { sp<JTuner> tuner = getTuner(env, thiz); + DemuxFilterMainType mainType = static_cast<DemuxFilterMainType>(type); DemuxFilterType filterType { - .mainType = static_cast<DemuxFilterMainType>(type), + .mainType = mainType, }; - // TODO: other sub types - filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType)); + switch(mainType) { + case DemuxFilterMainType::TS: + filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType)); + break; + case DemuxFilterMainType::MMTP: + filterType.subType.mmtpFilterType(static_cast<DemuxMmtpFilterType>(subType)); + break; + case DemuxFilterMainType::IP: + filterType.subType.ipFilterType(static_cast<DemuxIpFilterType>(subType)); + break; + case DemuxFilterMainType::TLV: + filterType.subType.tlvFilterType(static_cast<DemuxTlvFilterType>(subType)); + break; + case DemuxFilterMainType::ALP: + filterType.subType.alpFilterType(static_cast<DemuxAlpFilterType>(subType)); + break; + } return tuner->openFilter(filterType, bufferSize); } -static jobject android_media_tv_Tuner_open_time_filter(JNIEnv, jobject) { - return NULL; +static jobject android_media_tv_Tuner_open_time_filter(JNIEnv *env, jobject thiz) { + sp<JTuner> tuner = getTuner(env, thiz); + return tuner->openTimeFilter(); } static DemuxFilterSectionBits getFilterSectionBits(JNIEnv *env, const jobject& settings) { @@ -1987,26 +2059,98 @@ static int android_media_tv_Tuner_close_filter(JNIEnv*, jobject) { return 0; } -// TODO: implement TimeFilter functions +static sp<TimeFilter> getTimeFilter(JNIEnv *env, jobject filter) { + return (TimeFilter *)env->GetLongField(filter, gFields.timeFilterContext); +} + static int android_media_tv_Tuner_time_filter_set_timestamp( - JNIEnv, jobject, jlong) { - return 0; + JNIEnv *env, jobject filter, jlong timestamp) { + sp<TimeFilter> filterSp = getTimeFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed set timestamp: time filter not found"); + return (int) Result::INVALID_STATE; + } + sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter(); + Result r = iFilterSp->setTimeStamp(static_cast<uint64_t>(timestamp)); + return (int) r; } -static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv, jobject) { - return 0; +static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv *env, jobject filter) { + sp<TimeFilter> filterSp = getTimeFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed clear timestamp: time filter not found"); + return (int) Result::INVALID_STATE; + } + sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter(); + Result r = iFilterSp->clearTimeStamp(); + return (int) r; } -static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv, jobject) { - return NULL; +static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv *env, jobject filter) { + sp<TimeFilter> filterSp = getTimeFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed get timestamp: time filter not found"); + return NULL; + } + + sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter(); + Result res; + uint64_t timestamp; + iFilterSp->getTimeStamp( + [&](Result r, uint64_t t) { + res = r; + timestamp = t; + }); + if (res != Result::SUCCESS) { + return NULL; + } + + jclass longClazz = env->FindClass("java/lang/Long"); + jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V"); + + jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp)); + return longObj; } -static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv, jobject) { - return NULL; +static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv *env, jobject filter) { + sp<TimeFilter> filterSp = getTimeFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed get source time: time filter not found"); + return NULL; + } + + sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter(); + Result res; + uint64_t timestamp; + iFilterSp->getSourceTime( + [&](Result r, uint64_t t) { + res = r; + timestamp = t; + }); + if (res != Result::SUCCESS) { + return NULL; + } + + jclass longClazz = env->FindClass("java/lang/Long"); + jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V"); + + jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp)); + return longObj; } -static int android_media_tv_Tuner_time_filter_close(JNIEnv, jobject) { - return 0; +static int android_media_tv_Tuner_time_filter_close(JNIEnv *env, jobject filter) { + sp<TimeFilter> filterSp = getTimeFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed close time filter: time filter not found"); + return (int) Result::INVALID_STATE; + } + + Result r = filterSp->getITimeFilter()->close(); + if (r == Result::SUCCESS) { + filterSp->decStrong(filter); + env->SetLongField(filter, gFields.timeFilterContext, 0); + } + return (int) r; } static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) { diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index d899bbd6467f..c5590b956eda 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -54,6 +54,7 @@ using ::android::hardware::tv::tuner::V1_0::IFrontend; using ::android::hardware::tv::tuner::V1_0::IFrontendCallback; using ::android::hardware::tv::tuner::V1_0::ILnb; using ::android::hardware::tv::tuner::V1_0::ILnbCallback; +using ::android::hardware::tv::tuner::V1_0::ITimeFilter; using ::android::hardware::tv::tuner::V1_0::ITuner; using ::android::hardware::tv::tuner::V1_0::LnbEventType; using ::android::hardware::tv::tuner::V1_0::LnbId; @@ -127,6 +128,14 @@ struct Filter : public RefBase { jweak mFilterObj; }; +struct TimeFilter : public RefBase { + TimeFilter(sp<ITimeFilter> sp, jweak obj); + ~TimeFilter(); + sp<ITimeFilter> getITimeFilter(); + sp<ITimeFilter> mTimeFilterSp; + jweak mTimeFilterObj; +}; + struct JTuner : public RefBase { JTuner(JNIEnv *env, jobject thiz); sp<ITuner> getTunerService(); @@ -142,6 +151,7 @@ struct JTuner : public RefBase { jobject getLnbIds(); jobject openLnbById(int id); jobject openFilter(DemuxFilterType type, int bufferSize); + jobject openTimeFilter(); jobject openDescrambler(); jobject openDvr(DvrType type, int bufferSize); diff --git a/media/native/Android.bp b/media/native/Android.bp deleted file mode 100644 index b44c2960127f..000000000000 --- a/media/native/Android.bp +++ /dev/null @@ -1 +0,0 @@ -subdirs = ["*"] diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java index c9ac765dfc1d..873d7d7975e0 100644 --- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java @@ -25,8 +25,11 @@ import android.app.Dialog; import android.app.KeyguardManager; import android.car.Car; import android.car.media.CarAudioManager; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.Color; @@ -38,6 +41,7 @@ import android.os.Debug; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -171,6 +175,17 @@ public class CarVolumeDialogImpl implements VolumeDialog { mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback); }; + private final BroadcastReceiver mHomeButtonPressedBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (!intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { + return; + } + + dismissH(Events.DISMISS_REASON_VOLUME_CONTROLLER); + } + }; + public CarVolumeDialogImpl(Context context) { mContext = context; mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); @@ -204,12 +219,18 @@ public class CarVolumeDialogImpl implements VolumeDialog { @Override public void init(int windowType, Callback callback) { initDialog(); + + mContext.registerReceiverAsUser(mHomeButtonPressedBroadcastReceiver, UserHandle.CURRENT, + new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), /* broadcastPermission= */ + null, /* scheduler= */ null); } @Override public void destroy() { mHandler.removeCallbacksAndMessages(/* token= */ null); + mContext.unregisterReceiver(mHomeButtonPressedBroadcastReceiver); + cleanupAudioManager(); } diff --git a/packages/DynamicSystemInstallationService/AndroidManifest.xml b/packages/DynamicSystemInstallationService/AndroidManifest.xml index d718eae9293c..b4d520d7d71a 100644 --- a/packages/DynamicSystemInstallationService/AndroidManifest.xml +++ b/packages/DynamicSystemInstallationService/AndroidManifest.xml @@ -7,6 +7,7 @@ <uses-permission android:name="android.permission.MANAGE_DYNAMIC_SYSTEM" /> <uses-permission android:name="android.permission.REBOOT" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> + <uses-permission android:name="android.permission.READ_OEM_UNLOCK_STATE" /> <application android:allowBackup="false" diff --git a/packages/DynamicSystemInstallationService/res/values/strings.xml b/packages/DynamicSystemInstallationService/res/values/strings.xml index 7595d2b1eea3..e124be605cc7 100644 --- a/packages/DynamicSystemInstallationService/res/values/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values/strings.xml @@ -18,6 +18,8 @@ <string name="notification_install_inprogress">Install in progress</string> <!-- Displayed on notification: Dynamic System installation failed [CHAR LIMIT=128] --> <string name="notification_install_failed">Install failed</string> + <!-- Displayed on notification: Image validation failed [CHAR LIMIT=128] --> + <string name="notification_image_validation_failed">Image validation failed. Abort installation.</string> <!-- Displayed on notification: We are running in Dynamic System [CHAR LIMIT=128] --> <string name="notification_dynsystem_in_use">Currently running a dynamic system. Restart to use the original Android version.</string> @@ -25,10 +27,11 @@ <string name="notification_action_cancel">Cancel</string> <!-- Action on notification: Discard installation [CHAR LIMIT=16] --> <string name="notification_action_discard">Discard</string> - <!-- Action on notification: Uninstall Dynamic System [CHAR LIMIT=16] --> - <string name="notification_action_uninstall">Uninstall</string> <!-- Action on notification: Restart to Dynamic System [CHAR LIMIT=16] --> <string name="notification_action_reboot_to_dynsystem">Restart</string> + <!-- Action on notification: Restart to original Android version [CHAR LIMIT=16] --> + <string name="notification_action_reboot_to_origin">Restart</string> + <!-- Toast when installed Dynamic System is discarded [CHAR LIMIT=64] --> <string name="toast_dynsystem_discarded">Discarded dynamic system</string> diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index 9bae223a0a3e..37a77be52983 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -80,6 +80,7 @@ public class DynamicSystemInstallationService extends Service static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED"; static final String KEY_DSU_SLOT = "KEY_DSU_SLOT"; static final String DEFAULT_DSU_SLOT = "dsu"; + static final String KEY_PUBKEY = "KEY_PUBKEY"; /* * Intent actions @@ -267,6 +268,7 @@ public class DynamicSystemInstallationService extends Service long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0); mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false); String dsuSlot = intent.getStringExtra(KEY_DSU_SLOT); + String publicKey = intent.getStringExtra(KEY_PUBKEY); if (TextUtils.isEmpty(dsuSlot)) { dsuSlot = DEFAULT_DSU_SLOT; @@ -274,7 +276,7 @@ public class DynamicSystemInstallationService extends Service // TODO: better constructor or builder mInstallTask = new InstallationAsyncTask( - url, dsuSlot, systemSize, userdataSize, this, mDynSystem, this); + url, dsuSlot, publicKey, systemSize, userdataSize, this, mDynSystem, this); mInstallTask.execute(); @@ -408,6 +410,10 @@ public class DynamicSystemInstallationService extends Service } private Notification buildNotification(int status, int cause) { + return buildNotification(status, cause, null); + } + + private Notification buildNotification(int status, int cause, Throwable detail) { Notification.Builder builder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID) .setSmallIcon(R.drawable.ic_system_update_googblue_24dp) .setProgress(0, 0, false); @@ -456,14 +462,19 @@ public class DynamicSystemInstallationService extends Service .setStyle(new Notification.BigTextStyle().bigText(msgInUse)); builder.addAction(new Notification.Action.Builder( - null, getString(R.string.notification_action_uninstall), + null, getString(R.string.notification_action_reboot_to_origin), createPendingIntent(ACTION_REBOOT_TO_NORMAL)).build()); break; case STATUS_NOT_STARTED: if (cause != CAUSE_NOT_SPECIFIED && cause != CAUSE_INSTALL_CANCELLED) { - builder.setContentText(getString(R.string.notification_install_failed)); + if (detail instanceof InstallationAsyncTask.ImageValidationException) { + builder.setContentText( + getString(R.string.notification_image_validation_failed)); + } else { + builder.setContentText(getString(R.string.notification_install_failed)); + } } else { // no need to notify the user if the task is not started, or cancelled. } @@ -525,7 +536,7 @@ public class DynamicSystemInstallationService extends Service break; } - Log.d(TAG, "status=" + statusString + ", cause=" + causeString); + Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail); boolean notifyOnNotificationBar = true; @@ -538,7 +549,7 @@ public class DynamicSystemInstallationService extends Service } if (notifyOnNotificationBar) { - mNM.notify(NOTIFICATION_ID, buildNotification(status, cause)); + mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail)); } for (int i = mClients.size() - 1; i >= 0; i--) { diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index 438c435ef0e4..f8952ace3cb3 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -17,11 +17,13 @@ package com.android.dynsystem; import android.content.Context; +import android.gsi.AvbPublicKey; import android.net.Uri; import android.os.AsyncTask; import android.os.MemoryFile; import android.os.ParcelFileDescriptor; import android.os.image.DynamicSystemManager; +import android.service.persistentdata.PersistentDataBlockManager; import android.util.Log; import android.webkit.URLUtil; @@ -51,18 +53,46 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog private static final List<String> UNSUPPORTED_PARTITIONS = Arrays.asList("vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other"); - private class UnsupportedUrlException extends RuntimeException { + private class UnsupportedUrlException extends Exception { private UnsupportedUrlException(String message) { super(message); } } - private class UnsupportedFormatException extends RuntimeException { + private class UnsupportedFormatException extends Exception { private UnsupportedFormatException(String message) { super(message); } } + static class ImageValidationException extends Exception { + ImageValidationException(String message) { + super(message); + } + + ImageValidationException(Throwable cause) { + super(cause); + } + } + + static class RevocationListFetchException extends ImageValidationException { + RevocationListFetchException(Throwable cause) { + super(cause); + } + } + + static class KeyRevokedException extends ImageValidationException { + KeyRevokedException(String message) { + super(message); + } + } + + static class PublicKeyException extends ImageValidationException { + PublicKeyException(String message) { + super(message); + } + } + /** UNSET means the installation is not completed */ static final int RESULT_UNSET = 0; static final int RESULT_OK = 1; @@ -97,12 +127,14 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog private final String mUrl; private final String mDsuSlot; + private final String mPublicKey; private final long mSystemSize; private final long mUserdataSize; private final Context mContext; private final DynamicSystemManager mDynSystem; private final ProgressListener mListener; private final boolean mIsNetworkUrl; + private final boolean mIsDeviceBootloaderUnlocked; private DynamicSystemManager.Session mInstallationSession; private KeyRevocationList mKeyRevocationList; @@ -115,6 +147,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog InstallationAsyncTask( String url, String dsuSlot, + String publicKey, long systemSize, long userdataSize, Context context, @@ -122,12 +155,20 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog ProgressListener listener) { mUrl = url; mDsuSlot = dsuSlot; + mPublicKey = publicKey; mSystemSize = systemSize; mUserdataSize = userdataSize; mContext = context; mDynSystem = dynSystem; mListener = listener; mIsNetworkUrl = URLUtil.isNetworkUrl(mUrl); + PersistentDataBlockManager pdbManager = + (PersistentDataBlockManager) + mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); + mIsDeviceBootloaderUnlocked = + (pdbManager != null) + && (pdbManager.getFlashLockState() + == PersistentDataBlockManager.FLASH_LOCK_UNLOCKED); } @Override @@ -157,8 +198,6 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog return null; } - // TODO(yochiang): do post-install public key check (revocation list / boot-ramdisk) - mDynSystem.finishInstallation(); } catch (Exception e) { Log.e(TAG, e.toString(), e); @@ -242,23 +281,26 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog String.format(Locale.US, "Unsupported URL: %s", mUrl)); } - // TODO(yochiang): Bypass this check if device is unlocked try { String listUrl = mContext.getString(R.string.key_revocation_list_url); mKeyRevocationList = KeyRevocationList.fromUrl(new URL(listUrl)); } catch (IOException | JSONException e) { - Log.d(TAG, "Failed to fetch Dynamic System Key Revocation List"); mKeyRevocationList = new KeyRevocationList(); - keyRevocationThrowOrWarning(e); + imageValidationThrowOrWarning(new RevocationListFetchException(e)); + } + if (mKeyRevocationList.isRevoked(mPublicKey)) { + imageValidationThrowOrWarning(new KeyRevokedException(mPublicKey)); } } - private void keyRevocationThrowOrWarning(Exception e) throws Exception { - if (mIsNetworkUrl) { - throw e; - } else { - // If DSU is being installed from a local file URI, then be permissive + private void imageValidationThrowOrWarning(ImageValidationException e) + throws ImageValidationException { + if (mIsDeviceBootloaderUnlocked || !mIsNetworkUrl) { + // If device is OEM unlocked or DSU is being installed from a local file URI, + // then be permissive. Log.w(TAG, e.toString()); + } else { + throw e; } } @@ -294,7 +336,8 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installImages() throws IOException, InterruptedException { + private void installImages() + throws IOException, InterruptedException, ImageValidationException { if (mStream != null) { if (mIsZip) { installStreamingZipUpdate(); @@ -306,12 +349,14 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installStreamingGzUpdate() throws IOException, InterruptedException { + private void installStreamingGzUpdate() + throws IOException, InterruptedException, ImageValidationException { Log.d(TAG, "To install a streaming GZ update"); installImage("system", mSystemSize, new GZIPInputStream(mStream), 1); } - private void installStreamingZipUpdate() throws IOException, InterruptedException { + private void installStreamingZipUpdate() + throws IOException, InterruptedException, ImageValidationException { Log.d(TAG, "To install a streaming ZIP update"); ZipInputStream zis = new ZipInputStream(mStream); @@ -330,7 +375,8 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installLocalZipUpdate() throws IOException, InterruptedException { + private void installLocalZipUpdate() + throws IOException, InterruptedException, ImageValidationException { Log.d(TAG, "To install a local ZIP update"); Enumeration<? extends ZipEntry> entries = mZipFile.entries(); @@ -349,8 +395,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private boolean installImageFromAnEntry(ZipEntry entry, InputStream is, - int numInstalledPartitions) throws IOException, InterruptedException { + private boolean installImageFromAnEntry( + ZipEntry entry, InputStream is, int numInstalledPartitions) + throws IOException, InterruptedException, ImageValidationException { String name = entry.getName(); Log.d(TAG, "ZipEntry: " + name); @@ -373,8 +420,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog return true; } - private void installImage(String partitionName, long uncompressedSize, InputStream is, - int numInstalledPartitions) throws IOException, InterruptedException { + private void installImage( + String partitionName, long uncompressedSize, InputStream is, int numInstalledPartitions) + throws IOException, InterruptedException, ImageValidationException { SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is)); @@ -445,6 +493,24 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog publishProgress(progress); } } + + AvbPublicKey avbPublicKey = new AvbPublicKey(); + if (!mInstallationSession.getAvbPublicKey(avbPublicKey)) { + imageValidationThrowOrWarning(new PublicKeyException("getAvbPublicKey() failed")); + } else { + String publicKey = toHexString(avbPublicKey.sha1); + if (mKeyRevocationList.isRevoked(publicKey)) { + imageValidationThrowOrWarning(new KeyRevokedException(publicKey)); + } + } + } + + private static String toHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); } private void close() { diff --git a/packages/OsuLogin/AndroidManifest.xml b/packages/OsuLogin/AndroidManifest.xml index 123559adf6fd..a428cb36e97e 100644 --- a/packages/OsuLogin/AndroidManifest.xml +++ b/packages/OsuLogin/AndroidManifest.xml @@ -17,7 +17,7 @@ */ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.hotspot2"> + package="com.android.hotspot2.osulogin"> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.INTERNET"/> @@ -28,7 +28,7 @@ android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize" android:supportsRtl="true"> - <activity android:name="com.android.hotspot2.osu.OsuLoginActivity" + <activity android:name="com.android.hotspot2.osulogin.OsuLoginActivity" android:label="@string/action_bar_label" android:theme="@style/AppTheme" android:configChanges="keyboardHidden|orientation|screenSize"> diff --git a/packages/OsuLogin/res/layout/osu_web_view.xml b/packages/OsuLogin/res/layout/osu_web_view.xml index fb3c06513430..4436aab39e13 100644 --- a/packages/OsuLogin/res/layout/osu_web_view.xml +++ b/packages/OsuLogin/res/layout/osu_web_view.xml @@ -3,7 +3,7 @@ android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="com.android.hotspot2.osu.OsuLoginActivity"> + tools:context="com.android.hotspot2.osulogin.OsuLoginActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java b/packages/OsuLogin/src/com/android/hotspot2/osulogin/OsuLoginActivity.java index 3a994d741956..d554745819e6 100644 --- a/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java +++ b/packages/OsuLogin/src/com/android/hotspot2/osulogin/OsuLoginActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.hotspot2.osu; +package com.android.hotspot2.osulogin; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; @@ -42,8 +42,6 @@ import android.widget.Toast; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import com.android.hotspot2.R; - import java.net.MalformedURLException; import java.net.URL; @@ -194,7 +192,7 @@ public class OsuLoginActivity extends Activity { // Check if the key event was the Back button. if ((keyCode == KeyEvent.KEYCODE_BACK)) { // If there is a history to move back - if (mWebView.canGoBack()){ + if (mWebView.canGoBack()) { mWebView.goBack(); return true; } @@ -278,6 +276,6 @@ public class OsuLoginActivity extends Activity { mPageError = true; Log.e(TAG, "onReceived Error for MainFrame: " + error.getErrorCode()); } - } + } } } diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 59881e7ba13d..d25e3e2ade01 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -886,6 +886,11 @@ <!-- UI debug setting: enable gpu debug layers summary [CHAR LIMIT=50] --> <string name="enable_gpu_debug_layers_summary">Allow loading GPU debug layers for debug apps</string> + <!-- UI debug setting: enable verbose vendor logging [CHAR LIMIT=30] --> + <string name="enable_verbose_vendor_logging">Enable verbose vendor logging</string> + <!-- UI debug setting: enable verbose vendor logging summary [CHAR LIMIT=100] --> + <string name="enable_verbose_vendor_logging_summary">Allow additional vendor logs to be included in bug reports, may contain private information</string> + <!-- UI debug setting: scaling factor for window animations [CHAR LIMIT=25] --> <string name="window_animation_scale_title">Window animation scale</string> @@ -1260,9 +1265,12 @@ <!-- The notice header of Third-party licenses. not translatable --> <string name="notice_header" translatable="false"></string> - <!-- Name of the this device. [CHAR LIMIT=30] --> - <string name="media_transfer_this_device_name">This device</string> + <!-- Name of the phone device. [CHAR LIMIT=30] --> + <string name="media_transfer_this_device_name">Phone speaker</string> <!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] --> <string name="profile_connect_timeout_subtext">Problem connecting. Turn device off & back on</string> + + <!-- Name of the 3.5mm audio device. [CHAR LIMIT=40] --> + <string name="media_transfer_wired_device_name">Wired audio device</string> </resources> diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index de174b13a459..e0662309f571 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -86,7 +86,9 @@ filegroup { android_library { name: "SystemUI-tests", - manifest: "tests/AndroidManifest.xml", + manifest: "tests/AndroidManifest-base.xml", + additional_manifests: ["tests/AndroidManifest.xml"], + resource_dirs: [ "tests/res", "res-product", diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 571c4ae0e386..11bf24d27170 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -72,11 +72,12 @@ public class KeyguardDisplayManager { @Override public void onDisplayChanged(int displayId) { if (displayId == DEFAULT_DISPLAY) return; - final Display display = mDisplayService.getDisplay(displayId); - if (display != null && mShowing) { - final Presentation presentation = mPresentations.get(displayId); - if (presentation != null && !presentation.getDisplay().equals(display)) { - hidePresentation(displayId); + final Presentation presentation = mPresentations.get(displayId); + if (presentation != null && mShowing) { + hidePresentation(displayId); + // update DisplayInfo. + final Display display = mDisplayService.getDisplay(displayId); + if (display != null) { showPresentation(display); } } @@ -266,6 +267,11 @@ public class KeyguardDisplayManager { } @Override + public void cancel() { + // Do not allow anything to cancel KeyguardPresetation except KeyguardDisplayManager. + } + + @Override public void onDetachedFromWindow() { mClock.removeCallbacks(mMoveTextRunnable); } diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index c9104dccce80..6ce6353147fb 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -96,6 +96,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS = SystemProperties.getBoolean("debug.screenshot_rounded_corners", false); private static final boolean VERBOSE = false; + private static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS; private DisplayManager mDisplayManager; private boolean mIsRegistered; @@ -454,6 +455,9 @@ public class ScreenDecorations extends SystemUI implements Tunable { private void updateColorInversion(int colorsInvertedValue) { int tint = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK; + if (DEBUG_COLOR) { + tint = Color.RED; + } ColorStateList tintList = ColorStateList.valueOf(tint); if (mOverlays == null) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java index 8a5aad875979..cf5a4d3840cc 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java @@ -443,11 +443,26 @@ public class BubbleData { mStateChange.orderChanged |= repackAll(); } - if (reason == BubbleController.DISMISS_AGED) { + overflowBubble(reason, bubbleToRemove); + + // Note: If mBubbles.isEmpty(), then mSelectedBubble is now null. + if (Objects.equals(mSelectedBubble, bubbleToRemove)) { + // Move selection to the new bubble at the same position. + int newIndex = Math.min(indexToRemove, mBubbles.size() - 1); + Bubble newSelected = mBubbles.get(newIndex); + setSelectedBubbleInternal(newSelected); + } + maybeSendDeleteIntent(reason, bubbleToRemove.getEntry()); + } + + void overflowBubble(@DismissReason int reason, Bubble bubble) { + if (reason == BubbleController.DISMISS_AGED + || reason == BubbleController.DISMISS_USER_GESTURE) { if (DEBUG_BUBBLE_DATA) { - Log.d(TAG, "overflowing bubble: " + bubbleToRemove); + Log.d(TAG, "overflowing bubble: " + bubble); } - mOverflowBubbles.add(0, bubbleToRemove); + mOverflowBubbles.add(0, bubble); + if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) { // Remove oldest bubble. if (DEBUG_BUBBLE_DATA) { @@ -457,15 +472,6 @@ public class BubbleData { mOverflowBubbles.remove(mOverflowBubbles.size() - 1); } } - - // Note: If mBubbles.isEmpty(), then mSelectedBubble is now null. - if (Objects.equals(mSelectedBubble, bubbleToRemove)) { - // Move selection to the new bubble at the same position. - int newIndex = Math.min(indexToRemove, mBubbles.size() - 1); - Bubble newSelected = mBubbles.get(newIndex); - setSelectedBubbleInternal(newSelected); - } - maybeSendDeleteIntent(reason, bubbleToRemove.getEntry()); } public void dismissAll(@DismissReason int reason) { @@ -478,9 +484,7 @@ public class BubbleData { setExpandedInternal(false); setSelectedBubbleInternal(null); while (!mBubbles.isEmpty()) { - Bubble bubble = mBubbles.remove(0); - maybeSendDeleteIntent(reason, bubble.getEntry()); - mStateChange.bubbleRemoved(bubble, reason); + doRemove(mBubbles.get(0).getKey(), reason); } dispatchPendingChanges(); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java index 756c5981fe38..eb836b1a21f9 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java @@ -55,7 +55,6 @@ public class BubbleOverflowActivity extends Activity { private BubbleOverflowAdapter mAdapter; private RecyclerView mRecyclerView; private List<Bubble> mOverflowBubbles = new ArrayList<>(); - private int mMaxBubbles; @Inject public BubbleOverflowActivity(BubbleController controller) { @@ -68,7 +67,6 @@ public class BubbleOverflowActivity extends Activity { setContentView(R.layout.bubble_overflow_activity); setBackgroundColor(); - mMaxBubbles = getResources().getInteger(R.integer.bubbles_max_rendered); mEmptyState = findViewById(R.id.bubble_overflow_empty_state); mRecyclerView = findViewById(R.id.bubble_overflow_recycler); mRecyclerView.setLayoutManager( @@ -95,11 +93,7 @@ public class BubbleOverflowActivity extends Activity { void onDataChanged(List<Bubble> bubbles) { mOverflowBubbles.clear(); - if (bubbles.size() > mMaxBubbles) { - mOverflowBubbles.addAll(bubbles.subList(mMaxBubbles, bubbles.size())); - } else { - mOverflowBubbles.addAll(bubbles); - } + mOverflowBubbles.addAll(bubbles); mAdapter.notifyDataSetChanged(); if (mOverflowBubbles.isEmpty()) { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java index 7f45cc8f4c56..0329183e6048 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java @@ -38,10 +38,10 @@ import java.util.Locale; class DistanceClassifier extends FalsingClassifier { private static final float HORIZONTAL_FLING_THRESHOLD_DISTANCE_IN = 1; - private static final float VERTICAL_FLING_THRESHOLD_DISTANCE_IN = 1; + private static final float VERTICAL_FLING_THRESHOLD_DISTANCE_IN = 1.5f; private static final float HORIZONTAL_SWIPE_THRESHOLD_DISTANCE_IN = 3; private static final float VERTICAL_SWIPE_THRESHOLD_DISTANCE_IN = 3; - private static final float VELOCITY_TO_DISTANCE = 80f; + private static final float VELOCITY_TO_DISTANCE = 30f; private static final float SCREEN_FRACTION_MAX_DISTANCE = 0.8f; private final float mVerticalFlingThresholdPx; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java index 957ea8d127d2..a796f3c6d547 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java @@ -42,8 +42,8 @@ class ZigZagClassifier extends FalsingClassifier { // most swipes will follow somewhat of a 'C' or 'S' shape, we allow more deviance along the // `SECONDARY` axis. private static final float MAX_X_PRIMARY_DEVIANCE = .05f; - private static final float MAX_Y_PRIMARY_DEVIANCE = .1f; - private static final float MAX_X_SECONDARY_DEVIANCE = .6f; + private static final float MAX_Y_PRIMARY_DEVIANCE = .15f; + private static final float MAX_X_SECONDARY_DEVIANCE = .4f; private static final float MAX_Y_SECONDARY_DEVIANCE = .3f; private final float mMaxXPrimaryDeviance; diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt index 87bdfa8e04ec..6ff1bbce672f 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt @@ -22,7 +22,6 @@ import android.os.IBinder import android.os.UserHandle import android.service.controls.Control import android.service.controls.IControlsActionCallback -import android.service.controls.IControlsLoadCallback import android.service.controls.IControlsSubscriber import android.service.controls.IControlsSubscription import android.service.controls.actions.ControlAction @@ -63,12 +62,6 @@ open class ControlsBindingControllerImpl @Inject constructor( private val componentMap: MutableMap<Key, ControlsProviderLifecycleManager> = ArrayMap<Key, ControlsProviderLifecycleManager>() - private val loadCallbackService = object : IControlsLoadCallback.Stub() { - override fun accept(token: IBinder, controls: MutableList<Control>) { - backgroundExecutor.execute(OnLoadRunnable(token, controls)) - } - } - private val actionCallbackService = object : IControlsActionCallback.Stub() { override fun accept( token: IBinder, @@ -106,7 +99,6 @@ open class ControlsBindingControllerImpl @Inject constructor( return ControlsProviderLifecycleManager( context, backgroundExecutor, - loadCallbackService, actionCallbackService, subscriberService, currentUser, @@ -130,7 +122,7 @@ open class ControlsBindingControllerImpl @Inject constructor( callback: ControlsBindingController.LoadCallback ) { val provider = retrieveLifecycleManager(component) - provider.maybeBindAndLoad(callback) + provider.maybeBindAndLoad(LoadSubscriber(callback)) } override fun subscribe(controls: List<ControlInfo>) { @@ -216,7 +208,8 @@ open class ControlsBindingControllerImpl @Inject constructor( private inner class OnLoadRunnable( token: IBinder, - val list: List<Control> + val list: List<Control>, + val callback: ControlsBindingController.LoadCallback ) : CallbackRunnable(token) { override fun run() { if (provider == null) { @@ -233,9 +226,7 @@ open class ControlsBindingControllerImpl @Inject constructor( return } } - provider.lastLoadCallback?.accept(list) ?: run { - Log.w(TAG, "Null callback") - } + callback.accept(list) provider.unbindService() } } @@ -277,7 +268,7 @@ open class ControlsBindingControllerImpl @Inject constructor( ) : CallbackRunnable(token) { override fun run() { provider?.let { - Log.i(TAG, "onComplete receive from '${provider.componentName}'") + Log.i(TAG, "onComplete receive from '${it.componentName}'") } } } @@ -288,7 +279,7 @@ open class ControlsBindingControllerImpl @Inject constructor( ) : CallbackRunnable(token) { override fun run() { provider?.let { - Log.e(TAG, "onError receive from '${provider.componentName}': $error") + Log.e(TAG, "onError receive from '${it.componentName}': $error") } } } @@ -308,6 +299,44 @@ open class ControlsBindingControllerImpl @Inject constructor( } } } + + private inner class OnLoadErrorRunnable( + token: IBinder, + val error: String, + val callback: ControlsBindingController.LoadCallback + ) : CallbackRunnable(token) { + override fun run() { + callback.error(error) + provider?.let { + Log.e(TAG, "onError receive from '${it.componentName}': $error") + } + } + } + + private inner class LoadSubscriber( + val callback: ControlsBindingController.LoadCallback + ) : IControlsSubscriber.Stub() { + val loadedControls = ArrayList<Control>() + var hasError = false + + override fun onSubscribe(token: IBinder, subs: IControlsSubscription) { + backgroundExecutor.execute(OnSubscribeRunnable(token, subs)) + } + + override fun onNext(token: IBinder, c: Control) { + backgroundExecutor.execute { loadedControls.add(c) } + } + override fun onError(token: IBinder, s: String) { + hasError = true + backgroundExecutor.execute(OnLoadErrorRunnable(token, s, callback)) + } + + override fun onComplete(token: IBinder) { + if (!hasError) { + backgroundExecutor.execute(OnLoadRunnable(token, loadedControls, callback)) + } + } + } } -private data class Key(val component: ComponentName, val user: UserHandle)
\ No newline at end of file +private data class Key(val component: ComponentName, val user: UserHandle) diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt index d7f3c73a0bec..883f8a93d910 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt @@ -135,7 +135,7 @@ class ControlsFavoritePersistenceWrapper( } private fun parseXml(parser: XmlPullParser): List<ControlInfo> { - var type = 0 + var type: Int val infos = mutableListOf<ControlInfo>() while (parser.next().also { type = it } != XmlPullParser.END_DOCUMENT) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt index 9ec71c754bb5..a53fcd498236 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt @@ -29,7 +29,6 @@ import android.service.controls.ControlsProviderService import android.service.controls.ControlsProviderService.CALLBACK_BUNDLE import android.service.controls.ControlsProviderService.CALLBACK_TOKEN import android.service.controls.IControlsActionCallback -import android.service.controls.IControlsLoadCallback import android.service.controls.IControlsProvider import android.service.controls.IControlsSubscriber import android.service.controls.IControlsSubscription @@ -48,8 +47,6 @@ import java.util.concurrent.TimeUnit * * @property context A SystemUI context for binding to the services * @property executor A delayable executor for posting timeouts - * @property loadCallbackService a callback interface to hand the remote service for loading - * controls * @property actionCallbackService a callback interface to hand the remote service for sending * action responses * @property subscriberService an "subscriber" interface for requesting and accepting updates for @@ -60,15 +57,12 @@ import java.util.concurrent.TimeUnit class ControlsProviderLifecycleManager( private val context: Context, private val executor: DelayableExecutor, - private val loadCallbackService: IControlsLoadCallback.Stub, private val actionCallbackService: IControlsActionCallback.Stub, private val subscriberService: IControlsSubscriber.Stub, val user: UserHandle, val componentName: ComponentName ) : IBinder.DeathRecipient { - var lastLoadCallback: ControlsBindingController.LoadCallback? = null - private set val token: IBinder = Binder() @GuardedBy("subscriptions") private val subscriptions = mutableListOf<IControlsSubscription>() @@ -156,9 +150,12 @@ class ControlsProviderLifecycleManager( bindService(false) return } - if (Message.Load in queue) { - load() + + queue.filter { it is Message.Load }.forEach { + val msg = it as Message.Load + load(msg.subscriber) } + queue.filter { it is Message.Subscribe }.flatMap { (it as Message.Subscribe).list }.run { if (this.isNotEmpty()) { subscribe(this) @@ -193,12 +190,12 @@ class ControlsProviderLifecycleManager( } } - private fun load() { + private fun load(subscriber: IControlsSubscriber.Stub) { if (DEBUG) { Log.d(TAG, "load $componentName") } - if (!(wrapper?.load(loadCallbackService) ?: false)) { - queueMessage(Message.Load) + if (!(wrapper?.load(subscriber) ?: false)) { + queueMessage(Message.Load(subscriber)) binderDied() } } @@ -213,27 +210,23 @@ class ControlsProviderLifecycleManager( } /** - * Request a call to [ControlsProviderService.loadAvailableControls]. + * Request a call to [IControlsProvider.load]. * * If the service is not bound, the call will be queued and the service will be bound first. - * The service will be bound after the controls are returned or the call times out. + * The service will be unbound after the controls are returned or the call times out. * - * @param callback a callback in which to return the result back. If the call times out - * [ControlsBindingController.LoadCallback.error] will be called instead. + * @param subscriber the subscriber that manages coordination for loading controls */ - fun maybeBindAndLoad(callback: ControlsBindingController.LoadCallback) { + fun maybeBindAndLoad(subscriber: IControlsSubscriber.Stub) { unqueueMessage(Message.Unbind) - lastLoadCallback = callback onLoadCanceller = executor.executeDelayed({ // Didn't receive a response in time, log and send back error Log.d(TAG, "Timeout waiting onLoad for $componentName") - callback.error("Timeout waiting onLoad") - // Don't accept load callbacks after this - lastLoadCallback = null + subscriber.onError(token, "Timeout waiting onLoad") unbindService() }, LOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS) - invokeOrQueue(::load, Message.Load) + invokeOrQueue({ load(subscriber) }, Message.Load(subscriber)) } /** @@ -324,7 +317,6 @@ class ControlsProviderLifecycleManager( * Request unbind from the service. */ fun unbindService() { - lastLoadCallback = null onLoadCanceller?.run() onLoadCanceller = null @@ -344,7 +336,7 @@ class ControlsProviderLifecycleManager( */ sealed class Message { abstract val type: Int - object Load : Message() { + class Load(val subscriber: IControlsSubscriber.Stub) : Message() { override val type = MSG_LOAD } object Unbind : Message() { diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt index b90f892d5d26..b2afd3c144d1 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt @@ -18,7 +18,6 @@ package com.android.systemui.controls.controller import android.service.controls.actions.ControlAction import android.service.controls.IControlsActionCallback -import android.service.controls.IControlsLoadCallback import android.service.controls.IControlsProvider import android.service.controls.IControlsSubscriber import android.service.controls.IControlsSubscription @@ -45,9 +44,9 @@ class ServiceWrapper(val service: IControlsProvider) { } } - fun load(cb: IControlsLoadCallback): Boolean { + fun load(subscriber: IControlsSubscriber): Boolean { return callThroughService { - service.load(cb) + service.load(subscriber) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt index 89caaceebb5c..ac5e0893b526 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt @@ -58,13 +58,13 @@ class AppAdapter( private var listOfServices = emptyList<CandidateInfo>() private val callback = object : ControlsListingController.ControlsListingCallback { - override fun onServicesUpdated(list: List<CandidateInfo>) { + override fun onServicesUpdated(candidates: List<CandidateInfo>) { backgroundExecutor.execute { - val collator = Collator.getInstance(resources.getConfiguration().locale) + val collator = Collator.getInstance(resources.configuration.locales[0]) val localeComparator = compareBy<CandidateInfo, CharSequence>(collator) { it.loadLabel() } - listOfServices = list.sortedWith(localeComparator) + listOfServices = candidates.sortedWith(localeComparator) uiExecutor.execute(::notifyDataSetChanged) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index 9952b976a254..af4a977022ae 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -70,7 +70,7 @@ class ControlsFavoritingActivity @Inject constructor( target: RecyclerView.ViewHolder ): Boolean { return currentModel?.onMoveItem( - viewHolder.adapterPosition, target.adapterPosition) != null + viewHolder.layoutPosition, target.layoutPosition) != null } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {} diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt index d893caabdb36..8e47f6466955 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt @@ -45,6 +45,6 @@ interface ControlsListingController : @FunctionalInterface interface ControlsListingCallback { - fun onServicesUpdated(list: List<CandidateInfo>) + fun onServicesUpdated(candidates: List<CandidateInfo>) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index 98cdf288f1a1..f4fd37557fa4 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -130,8 +130,7 @@ class ControlsUiControllerImpl @Inject constructor ( private val listingCallback = object : ControlsListingController.ControlsListingCallback { override fun onServicesUpdated(candidates: List<CandidateInfo>) { bgExecutor.execute { - val collator = Collator.getInstance(context.getResources() - .getConfiguration().locale) + val collator = Collator.getInstance(context.resources.configuration.locales[0]) val localeComparator = compareBy<CandidateInfo, CharSequence>(collator) { it.loadLabel() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index 071198bfd263..d3d4287b8707 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -42,7 +42,7 @@ class DetailDialog( val intent: PendingIntent ) : Dialog(parentContext) { - lateinit var activityView: ActivityView + var activityView: ActivityView val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() { override fun onActivityViewReady(view: ActivityView) { @@ -61,24 +61,28 @@ class DetailDialog( override fun onTaskRemovalStarted(taskId: Int) {} } - init { - val window = getWindow() - window.requestFeature(Window.FEATURE_NO_TITLE) + @Suppress("DEPRECATION") + private fun Window.setWindowParams() { + requestFeature(Window.FEATURE_NO_TITLE) // Inflate the decor view, so the attributes below are not overwritten by the theme. - window.getDecorView() - window.getAttributes().systemUiVisibility = - (window.getAttributes().systemUiVisibility - or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - or View.SYSTEM_UI_FLAG_LAYOUT_STABLE) - - window.setLayout(MATCH_PARENT, MATCH_PARENT) - window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) - window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR - or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) - window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) - window.getAttributes().setFitInsetsTypes(0 /* types */) + decorView + attributes.systemUiVisibility = + (attributes.systemUiVisibility + or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE) + + setLayout(MATCH_PARENT, MATCH_PARENT) + clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR + or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) + setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) + getAttributes().setFitInsetsTypes(0 /* types */) + } + + init { + getWindow()?.setWindowParams() setContentView(R.layout.controls_detail_dialog) @@ -89,9 +93,9 @@ class DetailDialog( } override fun show() { - val attrs = getWindow().getAttributes() - attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS - getWindow().setAttributes(attrs) + val attrs = getWindow()?.attributes + attrs?.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS + getWindow()?.attributes = attrs activityView.setCallback(stateCallback) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt index 45d73979dd68..cca56c219972 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt @@ -60,7 +60,7 @@ class ToggleRangeBehavior : Behavior { val gestureListener = ToggleRangeGestureListener(cvh.layout) val gestureDetector = GestureDetector(context, gestureListener) - cvh.layout.setOnTouchListener({ v: View, e: MotionEvent -> + cvh.layout.setOnTouchListener { _: View, e: MotionEvent -> if (gestureDetector.onTouchEvent(e)) { return@setOnTouchListener true } @@ -72,7 +72,7 @@ class ToggleRangeBehavior : Behavior { } return@setOnTouchListener false - }) + } } override fun bind(cws: ControlWithState) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index b1db7dfc5be9..374153ce2409 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -80,7 +80,8 @@ import com.android.keyguard.KeyguardSecurityView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; -import com.android.systemui.Dependency; +import com.android.systemui.DumpController; +import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.SystemUIFactory; @@ -144,7 +145,7 @@ import dagger.Lazy; * directly to the keyguard UI is posted to a {@link android.os.Handler} to ensure it is taken on the UI * thread of the keyguard. */ -public class KeyguardViewMediator extends SystemUI { +public class KeyguardViewMediator extends SystemUI implements Dumpable { private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000; @@ -222,10 +223,10 @@ public class KeyguardViewMediator extends SystemUI { private final FalsingManager mFalsingManager; /** High level access to the power manager for WakeLocks */ - private PowerManager mPM; + private final PowerManager mPM; /** TrustManager for letting it know when we change visibility */ - private TrustManager mTrustManager; + private final TrustManager mTrustManager; /** * Used to keep the device awake while to ensure the keyguard finishes opening before @@ -283,7 +284,7 @@ public class KeyguardViewMediator extends SystemUI { // the properties of the keyguard - private KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardUpdateMonitor mUpdateMonitor; /** * Last SIM state reported by the telephony system. @@ -610,6 +611,7 @@ public class KeyguardViewMediator extends SystemUI { @Override public void keyguardGone() { Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardGone"); + mNotificationShadeWindowController.setKeyguardGoingAway(false); mKeyguardDisplayManager.hide(); Trace.endSection(); } @@ -696,7 +698,9 @@ public class KeyguardViewMediator extends SystemUI { NotificationShadeWindowController notificationShadeWindowController, Lazy<StatusBarKeyguardViewManager> statusBarKeyguardViewManagerLazy, DismissCallbackRegistry dismissCallbackRegistry, - @UiBackground Executor uiBgExecutor) { + KeyguardUpdateMonitor keyguardUpdateMonitor, DumpController dumpController, + @UiBackground Executor uiBgExecutor, PowerManager powerManager, + TrustManager trustManager) { super(context); mFalsingManager = falsingManager; mLockPatternUtils = lockPatternUtils; @@ -705,6 +709,10 @@ public class KeyguardViewMediator extends SystemUI { mStatusBarKeyguardViewManagerLazy = statusBarKeyguardViewManagerLazy; mDismissCallbackRegistry = dismissCallbackRegistry; mUiBgExecutor = uiBgExecutor; + mUpdateMonitor = keyguardUpdateMonitor; + mPM = powerManager; + mTrustManager = trustManager; + dumpController.registerDumpable(this); mShowHomeOverLockscreen = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, @@ -731,9 +739,6 @@ public class KeyguardViewMediator extends SystemUI { } private void setupLocked() { - mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mTrustManager = mContext.getSystemService(TrustManager.class); - mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); mShowKeyguardWakeLock.setReferenceCounted(false); @@ -754,8 +759,6 @@ public class KeyguardViewMediator extends SystemUI { mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); - KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser()); // Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 2c023cadd9ea..2ba0315af252 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -16,9 +16,13 @@ package com.android.systemui.keyguard.dagger; +import android.app.trust.TrustManager; import android.content.Context; +import android.os.PowerManager; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.DumpController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.keyguard.DismissCallbackRegistry; @@ -54,6 +58,10 @@ public class KeyguardModule { NotificationShadeWindowController notificationShadeWindowController, Lazy<StatusBarKeyguardViewManager> statusBarKeyguardViewManagerLazy, DismissCallbackRegistry dismissCallbackRegistry, + KeyguardUpdateMonitor updateMonitor, + DumpController dumpController, + PowerManager powerManager, + TrustManager trustManager, @UiBackground Executor uiBgExecutor) { return new KeyguardViewMediator( context, @@ -63,6 +71,10 @@ public class KeyguardModule { notificationShadeWindowController, statusBarKeyguardViewManagerLazy, dismissCallbackRegistry, - uiBgExecutor); + updateMonitor, + dumpController, + uiBgExecutor, + powerManager, + trustManager); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java index 6c697184f082..011893d65723 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java @@ -244,7 +244,10 @@ public class QSMediaPlayer { ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); mSeamless.setOnClickListener(v -> { final Intent intent = new Intent() - .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT); + .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) + .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, + mController.getPackageName()) + .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, token); mActivityStarter.startActivity(intent, false, true /* dismissShade */, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); }); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java index 84891ec7fcd4..666323766c12 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -108,7 +108,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> Log.d(TAG, "Starting countdown"); // Close QS, otherwise the permission dialog appears beneath it getHost().collapsePanels(); - mController.launchRecordPrompt(this); + mController.launchRecordPrompt(); } private void cancelCountdown() { @@ -129,6 +129,11 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> } @Override + public void onCountdownEnd() { + refreshState(); + } + + @Override public void onRecordingStart() { refreshState(); } diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java index 6ad9c40ccaf4..8dad08e49d80 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java @@ -23,7 +23,6 @@ import android.content.Intent; import android.os.CountDownTimer; import android.util.Log; -import com.android.systemui.qs.tiles.ScreenRecordTile; import com.android.systemui.statusbar.policy.CallbackController; import java.util.ArrayList; @@ -62,7 +61,7 @@ public class RecordingController /** * Show dialog of screen recording options to user. */ - public void launchRecordPrompt(ScreenRecordTile tileToUpdate) { + public void launchRecordPrompt() { final ComponentName launcherComponent = new ComponentName(SYSUI_PACKAGE, SYSUI_SCREENRECORD_LAUNCHER); final Intent intent = new Intent(); @@ -73,15 +72,17 @@ public class RecordingController /** * Start counting down in preparation to start a recording - * @param ms Time in ms to count down + * @param ms Total time in ms to wait before starting + * @param interval Time in ms per countdown step * @param startIntent Intent to start a recording * @param stopIntent Intent to stop a recording */ - public void startCountdown(long ms, PendingIntent startIntent, PendingIntent stopIntent) { + public void startCountdown(long ms, long interval, PendingIntent startIntent, + PendingIntent stopIntent) { mIsStarting = true; mStopIntent = stopIntent; - mCountDownTimer = new CountDownTimer(ms, 1000) { + mCountDownTimer = new CountDownTimer(ms, interval) { @Override public void onTick(long millisUntilFinished) { for (RecordingStateChangeCallback cb : mListeners) { @@ -94,7 +95,7 @@ public class RecordingController mIsStarting = false; mIsRecording = true; for (RecordingStateChangeCallback cb : mListeners) { - cb.onRecordingEnd(); + cb.onCountdownEnd(); } try { startIntent.send(); @@ -120,7 +121,7 @@ public class RecordingController mIsStarting = false; for (RecordingStateChangeCallback cb : mListeners) { - cb.onRecordingEnd(); + cb.onCountdownEnd(); } } @@ -144,16 +145,12 @@ public class RecordingController * Stop the recording */ public void stopRecording() { - updateState(false); try { mStopIntent.send(); + updateState(false); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Error stopping: " + e.getMessage()); } - - for (RecordingStateChangeCallback cb : mListeners) { - cb.onRecordingEnd(); - } } /** @@ -193,6 +190,12 @@ public class RecordingController default void onCountdown(long millisUntilFinished) {} /** + * Called when a countdown to recording has ended. This is a separate method so that if + * needed, listeners can handle cases where recording fails to start + */ + default void onCountdownEnd() {} + + /** * Called when a screen recording has started */ default void onRecordingStart() {} diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java index 566f12b42795..26973d092209 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java @@ -34,6 +34,7 @@ import javax.inject.Inject; */ public class ScreenRecordDialog extends Activity { private static final long DELAY_MS = 3000; + private static final long INTERVAL_MS = 1000; private final RecordingController mController; private Switch mAudioSwitch; @@ -83,6 +84,6 @@ public class ScreenRecordDialog extends Activity { RecordingService.REQUEST_CODE, RecordingService.getStopIntent(this), PendingIntent.FLAG_UPDATE_CURRENT); - mController.startCountdown(DELAY_MS, startIntent, stopIntent); + mController.startCountdown(DELAY_MS, INTERVAL_MS, startIntent, stopIntent); } } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 2daefbde45a8..56cdff43e255 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -137,7 +137,8 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, try { mLastImeTarget = ActivityTaskManager.getTaskOrganizerController() .getImeTarget(displayId); - mShouldAdjustForIme = !mSplitLayout.mDisplayLayout.isLandscape() + mShouldAdjustForIme = mLastImeTarget != null + && !mSplitLayout.mDisplayLayout.isLandscape() && (mLastImeTarget.asBinder() == mSplits.mSecondary.token.asBinder()); } catch (RemoteException e) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt index aaf48490d7b0..711d6a6daeef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt @@ -19,7 +19,6 @@ package com.android.systemui.statusbar import android.content.Context import android.graphics.Bitmap import android.graphics.Canvas -import android.graphics.Point import android.graphics.Rect import android.renderscript.Allocation import android.renderscript.Element @@ -27,9 +26,11 @@ import android.renderscript.RenderScript import android.renderscript.ScriptIntrinsicBlur import android.util.Log import android.util.MathUtils +import android.util.Size +import android.view.WindowManager +import com.android.internal.annotations.VisibleForTesting import com.android.internal.graphics.ColorUtils import com.android.systemui.statusbar.notification.MediaNotificationProcessor - import javax.inject.Inject import javax.inject.Singleton @@ -41,10 +42,9 @@ private const val DOWNSAMPLE = 6 @Singleton class MediaArtworkProcessor @Inject constructor() { - private val mTmpSize = Point() private var mArtworkCache: Bitmap? = null - fun processArtwork(context: Context, artwork: Bitmap): Bitmap? { + fun processArtwork(context: Context, artwork: Bitmap, windowType: Int): Bitmap? { if (mArtworkCache != null) { return mArtworkCache } @@ -54,9 +54,9 @@ class MediaArtworkProcessor @Inject constructor() { var output: Allocation? = null var inBitmap: Bitmap? = null try { - context.display.getSize(mTmpSize) + val size = getWindowSize(context, windowType) val rect = Rect(0, 0, artwork.width, artwork.height) - MathUtils.fitRect(rect, Math.max(mTmpSize.x / DOWNSAMPLE, mTmpSize.y / DOWNSAMPLE)) + MathUtils.fitRect(rect, Math.max(size.width / DOWNSAMPLE, size.height / DOWNSAMPLE)) inBitmap = Bitmap.createScaledBitmap(artwork, rect.width(), rect.height(), true /* filter */) // Render script blurs only support ARGB_8888, we need a conversion if we got a @@ -98,4 +98,15 @@ class MediaArtworkProcessor @Inject constructor() { mArtworkCache?.recycle() mArtworkCache = null } + + @VisibleForTesting + internal fun getWindowSize(context: Context, windowType: Int): Size { + val windowContext = context.display?.let { + context.createDisplayContext(it) + .createWindowContext(windowType, null) + } ?: run { throw NullPointerException("Display is null") } + val windowManager = windowContext.getSystemService(WindowManager::class.java) + ?: run { throw NullPointerException("Null window manager") } + return windowManager.currentWindowMetrics.size + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index d0af106d4a0c..f8db922e8758 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -15,7 +15,6 @@ */ package com.android.systemui.statusbar; -import static com.android.systemui.Dependency.MAIN_HANDLER; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_MEDIA_FAKE_ARTWORK; import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_WALLPAPER; @@ -36,7 +35,6 @@ import android.media.session.MediaSession; import android.media.session.MediaSessionManager; import android.media.session.PlaybackState; import android.os.AsyncTask; -import android.os.Handler; import android.os.Trace; import android.os.UserHandle; import android.provider.DeviceConfig; @@ -44,6 +42,7 @@ import android.provider.DeviceConfig.Properties; import android.util.ArraySet; import android.util.Log; import android.view.View; +import android.view.WindowManager; import android.widget.ImageView; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; @@ -52,6 +51,7 @@ import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.Interpolators; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.dagger.StatusBarModule; import com.android.systemui.statusbar.notification.NotificationEntryListener; @@ -73,6 +73,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.Executor; import dagger.Lazy; @@ -110,7 +111,7 @@ public class NotificationMediaManager implements Dumpable { @Nullable private LockscreenWallpaper mLockscreenWallpaper; - private final Handler mHandler = Dependency.get(MAIN_HANDLER); + private final Executor mMainExecutor; private final Context mContext; private final MediaSessionManager mMediaSessionManager; @@ -181,7 +182,8 @@ public class NotificationMediaManager implements Dumpable { Lazy<NotificationShadeWindowController> notificationShadeWindowController, NotificationEntryManager notificationEntryManager, MediaArtworkProcessor mediaArtworkProcessor, - KeyguardBypassController keyguardBypassController) { + KeyguardBypassController keyguardBypassController, + @Main Executor mainExecutor) { mContext = context; mMediaArtworkProcessor = mediaArtworkProcessor; mKeyguardBypassController = keyguardBypassController; @@ -194,6 +196,7 @@ public class NotificationMediaManager implements Dumpable { mStatusBarLazy = statusBarLazy; mNotificationShadeWindowController = notificationShadeWindowController; mEntryManager = notificationEntryManager; + mMainExecutor = mainExecutor; notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override public void onPendingEntryAdded(NotificationEntry entry) { @@ -623,7 +626,7 @@ public class NotificationMediaManager implements Dumpable { mBackdrop.setVisibility(View.GONE); mBackdropFront.animate().cancel(); mBackdropBack.setImageDrawable(null); - mHandler.post(mHideBackdropFront); + mMainExecutor.execute(mHideBackdropFront); }); if (mKeyguardStateController.isKeyguardFadingAway()) { mBackdrop.animate() @@ -668,7 +671,8 @@ public class NotificationMediaManager implements Dumpable { }; private Bitmap processArtwork(Bitmap artwork) { - return mMediaArtworkProcessor.processArtwork(mContext, artwork); + return mMediaArtworkProcessor.processArtwork(mContext, artwork, + WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE); } @MainThread diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 9c626f7b877d..12add8c8d9cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -159,6 +159,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi private boolean mDismissed; private Runnable mOnDismissListener; private boolean mIncreasedSize; + private boolean mTintIcons = true; public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) { this(context, slot, sbn, false); @@ -612,6 +613,11 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi } private void updateIconColor() { + if (!mTintIcons) { + setColorFilter(null); + return; + } + if (mCurrentSetColor != NO_COLOR) { if (mMatrixColorFilter == null) { mMatrix = new float[4 * 5]; @@ -953,6 +959,19 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi maybeUpdateIconScaleDimens(); } + /** + * Sets whether the icon should be tinted. If the state differs from the supplied setting, this + * will update the icon colors. + * + * @param shouldTint Whether the icon should be tinted. + */ + public void setTintIcons(boolean shouldTint) { + if (mTintIcons != shouldTint) { + mTintIcons = shouldTint; + updateIconColor(); + } + } + public interface OnVisibilityChangedListener { void onVisibilityChanged(int newVisibility); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java index 0b37c229555f..cd5bb775de8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java @@ -43,6 +43,8 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.tracing.ProtoTracer; +import java.util.concurrent.Executor; + import javax.inject.Singleton; import dagger.Lazy; @@ -88,14 +90,16 @@ public interface StatusBarDependenciesModule { Lazy<NotificationShadeWindowController> notificationShadeWindowController, NotificationEntryManager notificationEntryManager, MediaArtworkProcessor mediaArtworkProcessor, - KeyguardBypassController keyguardBypassController) { + KeyguardBypassController keyguardBypassController, + @Main Executor mainExecutor) { return new NotificationMediaManager( context, statusBarLazy, notificationShadeWindowController, notificationEntryManager, mediaArtworkProcessor, - keyguardBypassController); + keyguardBypassController, + mainExecutor); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index f482d37deb55..25a832d8da5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -29,6 +29,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCRE import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; +import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; +import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED; import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING; @@ -42,6 +44,9 @@ import android.app.NotificationManager.Policy; import android.app.Person; import android.app.RemoteInputHistoryItem; import android.content.Context; +import android.content.pm.LauncherApps; +import android.content.pm.LauncherApps.ShortcutQuery; +import android.content.pm.ShortcutInfo; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; @@ -50,6 +55,7 @@ import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; import android.util.ArraySet; +import android.util.Log; import android.view.View; import android.widget.ImageView; @@ -75,6 +81,8 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -94,11 +102,15 @@ import java.util.Objects; * clean this up in the future. */ public final class NotificationEntry extends ListEntry { + private static final String TAG = "NotificationEntry"; private final String mKey; private StatusBarNotification mSbn; private Ranking mRanking; + private StatusBarIcon mSmallIcon; + private StatusBarIcon mPeopleAvatar; + /* * Bookkeeping members */ @@ -459,12 +471,7 @@ public final class NotificationEntry extends ListEntry { */ public void createIcons(Context context, StatusBarNotification sbn) throws InflationException { - Notification n = sbn.getNotification(); - final Icon smallIcon = n.getSmallIcon(); - if (smallIcon == null) { - throw new InflationException("No small icon in notification from " - + sbn.getPackageName()); - } + StatusBarIcon ic = getIcon(context, sbn, false /* redact */); // Construct the icon. icon = new StatusBarIconView(context, @@ -482,21 +489,20 @@ public final class NotificationEntry extends ListEntry { aodIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); aodIcon.setIncreasedSize(true); - final StatusBarIcon ic = new StatusBarIcon( - sbn.getUser(), - sbn.getPackageName(), - smallIcon, - n.iconLevel, - n.number, - StatusBarIconView.contentDescForNotification(context, n)); - - if (!icon.set(ic) || !expandedIcon.set(ic) || !aodIcon.set(ic)) { + try { + setIcons(ic, Collections.singletonList(icon)); + if (isSensitive()) { + ic = getIcon(context, sbn, true /* redact */); + } + setIcons(ic, Arrays.asList(expandedIcon, aodIcon)); + } catch (InflationException e) { icon = null; expandedIcon = null; centeredIcon = null; aodIcon = null; - throw new InflationException("Couldn't create icon: " + ic); + throw e; } + expandedIcon.setVisibility(View.INVISIBLE); expandedIcon.setOnVisibilityChangedListener( newVisibility -> { @@ -510,10 +516,130 @@ public final class NotificationEntry extends ListEntry { centeredIcon = new StatusBarIconView(context, sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); centeredIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - - if (!centeredIcon.set(ic)) { + try { + setIcons(ic, Collections.singletonList(centeredIcon)); + } catch (InflationException e) { centeredIcon = null; - throw new InflationException("Couldn't update centered icon: " + ic); + throw e; + } + } + } + + /** + * Determines if this icon should be tinted based on the sensitivity of the icon, its context + * and the user's indicated sensitivity preference. + * + * @param ic The icon that should/should not be tinted. + * @return + */ + private boolean shouldTintIcon(StatusBarIconView ic) { + boolean usedInSensitiveContext = (ic == expandedIcon || ic == aodIcon); + return !isImportantConversation() || (usedInSensitiveContext && isSensitive()); + } + + + private void setIcons(StatusBarIcon ic, List<StatusBarIconView> icons) + throws InflationException { + for (StatusBarIconView icon: icons) { + if (icon == null) { + continue; + } + icon.setTintIcons(shouldTintIcon(icon)); + if (!icon.set(ic)) { + throw new InflationException("Couldn't create icon" + ic); + } + } + } + + private StatusBarIcon getIcon(Context context, StatusBarNotification sbn, boolean redact) + throws InflationException { + Notification n = sbn.getNotification(); + final boolean showPeopleAvatar = isImportantConversation() && !redact; + + // If cached, return corresponding cached values + if (showPeopleAvatar && mPeopleAvatar != null) { + return mPeopleAvatar; + } else if (!showPeopleAvatar && mSmallIcon != null) { + return mSmallIcon; + } + + Icon icon = showPeopleAvatar ? createPeopleAvatar(context) : n.getSmallIcon(); + if (icon == null) { + throw new InflationException("No icon in notification from " + sbn.getPackageName()); + } + + StatusBarIcon ic = new StatusBarIcon( + sbn.getUser(), + sbn.getPackageName(), + icon, + n.iconLevel, + n.number, + StatusBarIconView.contentDescForNotification(context, n)); + + // Cache if important conversation. + if (isImportantConversation()) { + if (showPeopleAvatar) { + mPeopleAvatar = ic; + } else { + mSmallIcon = ic; + } + } + return ic; + } + + private Icon createPeopleAvatar(Context context) throws InflationException { + // Attempt to extract form shortcut. + String conversationId = getChannel().getConversationId(); + ShortcutQuery query = new ShortcutQuery() + .setPackage(mSbn.getPackageName()) + .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) + .setShortcutIds(Collections.singletonList(conversationId)); + List<ShortcutInfo> shortcuts = context.getSystemService(LauncherApps.class) + .getShortcuts(query, mSbn.getUser()); + Icon ic = null; + if (shortcuts != null && !shortcuts.isEmpty()) { + ic = shortcuts.get(0).getIcon(); + } + + // Fall back to notification large icon if available + if (ic == null) { + ic = mSbn.getNotification().getLargeIcon(); + } + + // Fall back to extract from message + if (ic == null) { + Bundle extras = mSbn.getNotification().extras; + List<Message> messages = Message.getMessagesFromBundleArray( + extras.getParcelableArray(Notification.EXTRA_MESSAGES)); + Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON); + + for (int i = messages.size() - 1; i >= 0; i--) { + Message message = messages.get(i); + Person sender = message.getSenderPerson(); + if (sender != null && sender != user) { + ic = message.getSenderPerson().getIcon(); + break; + } + } + } + + // Revert to small icon if still not available + if (ic == null) { + ic = mSbn.getNotification().getSmallIcon(); + } + if (ic == null) { + throw new InflationException("No icon in notification from " + mSbn.getPackageName()); + } + return ic; + } + + private void updateSensitiveIconState() { + try { + StatusBarIcon ic = getIcon(getRow().getContext(), mSbn, isSensitive()); + setIcons(ic, Arrays.asList(expandedIcon, aodIcon)); + } catch (InflationException e) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Unable to update icon", e); } } } @@ -544,30 +670,32 @@ public final class NotificationEntry extends ListEntry { throws InflationException { if (icon != null) { // Update the icon - Notification n = sbn.getNotification(); - final StatusBarIcon ic = new StatusBarIcon( - mSbn.getUser(), - mSbn.getPackageName(), - n.getSmallIcon(), - n.iconLevel, - n.number, - StatusBarIconView.contentDescForNotification(context, n)); + mSmallIcon = null; + mPeopleAvatar = null; + + StatusBarIcon ic = getIcon(context, sbn, false /* redact */); + icon.setNotification(sbn); expandedIcon.setNotification(sbn); aodIcon.setNotification(sbn); - if (!icon.set(ic) || !expandedIcon.set(ic) || !aodIcon.set(ic)) { - throw new InflationException("Couldn't update icon: " + ic); + setIcons(ic, Arrays.asList(icon, expandedIcon)); + + if (isSensitive()) { + ic = getIcon(context, sbn, true /* redact */); } + setIcons(ic, Collections.singletonList(aodIcon)); if (centeredIcon != null) { centeredIcon.setNotification(sbn); - if (!centeredIcon.set(ic)) { - throw new InflationException("Couldn't update centered icon: " + ic); - } + setIcons(ic, Collections.singletonList(centeredIcon)); } } } + private boolean isImportantConversation() { + return getChannel() != null && getChannel().isImportantConversation(); + } + public int getContrastedColor(Context context, boolean isLowPriority, int backgroundColor) { int rawColor = isLowPriority ? Notification.COLOR_DEFAULT : @@ -996,6 +1124,7 @@ public final class NotificationEntry extends ListEntry { getRow().setSensitive(sensitive, deviceSensitive); if (sensitive != mSensitive) { mSensitive = sensitive; + updateSensitiveIconState(); if (mOnSensitiveChangedListener != null) { mOnSensitiveChangedListener.run(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 234ab936345b..500813318484 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -482,6 +482,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * once per notification as the packageInfo can't technically change for a notification row. */ private void cacheIsSystemNotification() { + //TODO: This probably shouldn't be in ExpandableNotificationRow if (mEntry != null && mEntry.mIsSystemNotification == null) { if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) { // Run async task once, only if it hasn't already been executed. Note this is diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java index d0162172eeef..2dd42c20a78b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java @@ -40,6 +40,7 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; +import com.android.systemui.DumpController; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -101,7 +102,8 @@ public class NotificationShadeWindowController implements Callback, Dumpable, IActivityManager activityManager, DozeParameters dozeParameters, StatusBarStateController statusBarStateController, ConfigurationController configurationController, - KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor) { + KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor, + DumpController dumpController) { mContext = context; mWindowManager = windowManager; mActivityManager = activityManager; @@ -111,6 +113,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable, mLpChanged = new LayoutParams(); mKeyguardBypassController = keyguardBypassController; mColorExtractor = colorExtractor; + dumpController.registerDumpable(this); mLockScreenDisplayTimeout = context.getResources() .getInteger(R.integer.config_lockScreenDisplayTimeout); @@ -594,7 +597,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable, } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("StatusBarWindowController:"); + pw.println(TAG + ":"); pw.println(" mKeyguardDisplayMode=" + mKeyguardDisplayMode); pw.println(mCurrentState); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 260f94cdcfcf..1ab36c5e3760 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -678,6 +678,12 @@ public class PhoneStatusBarPolicy } @Override + public void onCountdownEnd() { + if (DEBUG) Log.d(TAG, "screenrecord: hiding icon during countdown"); + mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false)); + } + + @Override public void onRecordingStart() { if (DEBUG) Log.d(TAG, "screenrecord: showing icon"); mIconController.setIcon(mSlotScreenRecord, @@ -687,7 +693,7 @@ public class PhoneStatusBarPolicy @Override public void onRecordingEnd() { - // Ensure this is on the main thread, since it could be called during countdown + // Ensure this is on the main thread if (DEBUG) Log.d(TAG, "screenrecord: hiding icon"); mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false)); } diff --git a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt index 0487ce6ea6b5..ca4b67db0d46 100644 --- a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt @@ -132,7 +132,6 @@ class FloatingContentCoordinator @Inject constructor() { * * @param content The content that has moved. */ - @JvmOverloads fun onContentMoved(content: FloatingContent) { // Ignore calls when we are currently resolving conflicts, since those calls are from diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index e5f56d43f4d7..38da21e016ec 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -46,6 +46,9 @@ LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui # UI it doesn't own. This is necessary to allow screenshots to be taken LOCAL_CERTIFICATE := platform +LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest.xml +LOCAL_MANIFEST_FILE := AndroidManifest-base.xml + # Provide jack a list of classes to exclude from code coverage. # This is needed because the SystemUITests compile SystemUI source directly, rather than using # LOCAL_INSTRUMENTATION_FOR := SystemUI. diff --git a/packages/SystemUI/tests/AndroidManifest-base.xml b/packages/SystemUI/tests/AndroidManifest-base.xml new file mode 100644 index 000000000000..f08d3d2f48d4 --- /dev/null +++ b/packages/SystemUI/tests/AndroidManifest-base.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:sharedUserId="android.uid.system" + package="com.android.systemui.tests" /> diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index c51624b0994b..12c704881909 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -18,7 +18,7 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:tools="http://schemas.android.com/tools" android:sharedUserId="android.uid.system" - package="com.android.systemui.tests"> + package="com.android.systemui" > <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" /> @@ -55,11 +55,6 @@ <application android:debuggable="true" android:largeHeap="true"> <uses-library android:name="android.test.runner" /> - <activity android:name="com.android.systemui.screenshot.ScreenshotStubActivity" /> - - <service - android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService" - android:process=":killable" /> <receiver android:name="com.android.systemui.SliceBroadcastRelayHandlerTest$Receiver"> <intent-filter> diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index daea7a7a8dc9..5e4f971f71c9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -203,7 +203,8 @@ public class BubbleControllerTest extends SysuiTestCase { // Bubbles get added to status bar window view mNotificationShadeWindowController = new NotificationShadeWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, - mConfigurationController, mKeyguardBypassController, mColorExtractor); + mConfigurationController, mKeyguardBypassController, mColorExtractor, + mDumpController); mNotificationShadeWindowController.setNotificationShadeView( mSuperStatusBarViewFactory.getNotificationShadeWindowView()); mNotificationShadeWindowController.attach(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index b412ca5b47c4..6677b80a2eac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -197,7 +197,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { // Bubbles get added to status bar window view mNotificationShadeWindowController = new NotificationShadeWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, - mConfigurationController, mKeyguardBypassController, mColorExtractor); + mConfigurationController, mKeyguardBypassController, mColorExtractor, + mDumpController); mNotificationShadeWindowController.setNotificationShadeView( mSuperStatusBarViewFactory.getNotificationShadeWindowView()); mNotificationShadeWindowController.attach(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java index 44454d957869..e5ab9be288ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java @@ -60,10 +60,10 @@ public class DistanceClassifierTest extends ClassifierTest { mClassifier.onTouchEvent(appendDownEvent(1, 1)); assertThat(mClassifier.isFalseTouch(), is(true)); - mClassifier.onTouchEvent(appendMoveEvent(1, 2)); + mClassifier.onTouchEvent(appendMoveEvent(1, 40)); assertThat(mClassifier.isFalseTouch(), is(true)); - mClassifier.onTouchEvent(appendUpEvent(1, 40)); + mClassifier.onTouchEvent(appendUpEvent(1, 80)); assertThat(mClassifier.isFalseTouch(), is(false)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt index 40075c8413d2..02bfc19e07d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt @@ -45,7 +45,7 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) -class ControlsBindingControllerTest : SysuiTestCase() { +class ControlsBindingControllerImplTest : SysuiTestCase() { companion object { fun <T> any(): T = Mockito.any<T>() @@ -95,7 +95,7 @@ class ControlsBindingControllerTest : SysuiTestCase() { assertEquals(1, providers.size) val provider = providers.first() - verify(provider).maybeBindAndLoad(callback) + verify(provider).maybeBindAndLoad(any()) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt index ddd6b125dcfa..a3e59e52abe5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.controls.controller import android.content.ComponentName import android.os.UserHandle import android.service.controls.IControlsActionCallback -import android.service.controls.IControlsLoadCallback import android.service.controls.IControlsProvider import android.service.controls.IControlsSubscriber import android.service.controls.actions.ControlAction @@ -32,13 +31,13 @@ import com.android.systemui.util.time.FakeSystemClock import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse -import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers +import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.eq import org.mockito.Captor @@ -54,8 +53,6 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { @Mock private lateinit var actionCallbackService: IControlsActionCallback.Stub @Mock - private lateinit var loadCallbackService: IControlsLoadCallback.Stub - @Mock private lateinit var subscriberService: IControlsSubscriber.Stub @Mock private lateinit var service: IControlsProvider.Stub @@ -85,7 +82,6 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { manager = ControlsProviderLifecycleManager( context, executor, - loadCallbackService, actionCallbackService, subscriberService, UserHandle.of(0), @@ -113,31 +109,29 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { @Test fun testMaybeBindAndLoad() { - manager.maybeBindAndLoad(loadCallback) + manager.maybeBindAndLoad(subscriberService) - verify(service).load(loadCallbackService) + verify(service).load(subscriberService) assertTrue(mContext.isBound(componentName)) - assertEquals(loadCallback, manager.lastLoadCallback) } @Test fun testMaybeUnbind_bindingAndCallback() { - manager.maybeBindAndLoad(loadCallback) + manager.maybeBindAndLoad(subscriberService) manager.unbindService() assertFalse(mContext.isBound(componentName)) - assertNull(manager.lastLoadCallback) } @Test fun testMaybeBindAndLoad_timeout() { - manager.maybeBindAndLoad(loadCallback) + manager.maybeBindAndLoad(subscriberService) executor.advanceClockToLast() executor.runAllReady() - verify(loadCallback).error(anyString()) + verify(subscriberService).onError(any(), anyString()) } @Test @@ -160,4 +154,4 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { eq(actionCallbackService)) assertEquals(action, wrapperCaptor.getValue().getWrappedAction()) } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt index 9e7ce06bb74f..cd82844fcc50 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.controls.controller import android.os.RemoteException import android.service.controls.IControlsActionCallback -import android.service.controls.IControlsLoadCallback import android.service.controls.IControlsProvider import android.service.controls.IControlsSubscriber import android.service.controls.IControlsSubscription @@ -56,9 +55,6 @@ class ServiceWrapperTest : SysuiTestCase() { private lateinit var subscriber: IControlsSubscriber @Mock - private lateinit var loadCallback: IControlsLoadCallback - - @Mock private lateinit var actionCallback: IControlsActionCallback @Captor @@ -81,16 +77,16 @@ class ServiceWrapperTest : SysuiTestCase() { @Test fun testLoad_happyPath() { - val result = wrapper.load(loadCallback) + val result = wrapper.load(subscriber) assertTrue(result) - verify(service).load(loadCallback) + verify(service).load(subscriber) } @Test fun testLoad_error() { `when`(service.load(any())).thenThrow(exception) - val result = wrapper.load(loadCallback) + val result = wrapper.load(subscriber) assertFalse(result) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index acc30d9f8374..9a707caaaece 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -18,24 +18,30 @@ package com.android.systemui.keyguard; import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; +import android.app.trust.TrustManager; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.DumpController; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingManagerFake; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.concurrency.FakeExecutor; @@ -60,6 +66,9 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock NotificationShadeWindowController mNotificationShadeWindowController; private @Mock BroadcastDispatcher mBroadcastDispatcher; private @Mock DismissCallbackRegistry mDismissCallbackRegistry; + private @Mock DumpController mDumpController; + private @Mock PowerManager mPowerManager; + private @Mock TrustManager mTrustManager; private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private FalsingManagerFake mFalsingManager; @@ -69,24 +78,33 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mFalsingManager = new FalsingManagerFake(); - mDependency.injectTestDependency(FalsingManager.class, mFalsingManager); - mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mUpdateMonitor); - when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager); + when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class)); - TestableLooper.get(this).runWithLooper(() -> { - mViewMediator = new KeyguardViewMediator( - mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher, - mNotificationShadeWindowController, () -> mStatusBarKeyguardViewManager, - mDismissCallbackRegistry, mUiBgExecutor); - }); + mViewMediator = new KeyguardViewMediator( + mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher, + mNotificationShadeWindowController, () -> mStatusBarKeyguardViewManager, + mDismissCallbackRegistry, mUpdateMonitor, mDumpController, mUiBgExecutor, + mPowerManager, mTrustManager); + mViewMediator.start(); } @Test public void testOnGoingToSleep_UpdatesKeyguardGoingAway() { - mViewMediator.start(); mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER); verify(mUpdateMonitor).setKeyguardGoingAway(false); verify(mNotificationShadeWindowController, never()).setKeyguardGoingAway(anyBoolean()); } + + @Test + public void testRegisterDumpable() { + verify(mDumpController).registerDumpable(eq(mViewMediator)); + verify(mNotificationShadeWindowController, never()).setKeyguardGoingAway(anyBoolean()); + } + + @Test + public void testKeyguardGone_notGoingaway() { + mViewMediator.mViewMediatorCallback.keyguardGone(); + verify(mNotificationShadeWindowController).setKeyguardGoingAway(eq(false)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java new file mode 100644 index 000000000000..e8e98b49c47f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.service.quicksettings.Tile; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.Dependency; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.qs.QSTileHost; +import com.android.systemui.screenrecord.RecordingController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class ScreenRecordTileTest extends SysuiTestCase { + + @Mock + private RecordingController mController; + @Mock + private QSTileHost mHost; + + private TestableLooper mTestableLooper; + private ScreenRecordTile mTile; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mTestableLooper = TestableLooper.get(this); + mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); + mController = mDependency.injectMockDependency(RecordingController.class); + + when(mHost.getContext()).thenReturn(mContext); + + mTile = new ScreenRecordTile(mHost, mController); + } + + // Test that the tile is inactive and labeled correctly when the controller is neither starting + // or recording, and that clicking on the tile in this state brings up the record prompt + @Test + public void testNotActive() { + when(mController.isStarting()).thenReturn(false); + when(mController.isRecording()).thenReturn(false); + + mTile.refreshState(); + mTestableLooper.processAllMessages(); + + assertEquals(Tile.STATE_INACTIVE, mTile.getState().state); + assertTrue(mTile.getState().secondaryLabel.toString().equals( + mContext.getString(R.string.quick_settings_screen_record_start))); + + mTile.handleClick(); + verify(mController, times(1)).launchRecordPrompt(); + } + + // Test that the tile is active and labeled correctly when the controller is starting + @Test + public void testIsStarting() { + when(mController.isStarting()).thenReturn(true); + when(mController.isRecording()).thenReturn(false); + + mTile.refreshState(); + mTestableLooper.processAllMessages(); + + assertEquals(Tile.STATE_ACTIVE, mTile.getState().state); + assertTrue(mTile.getState().secondaryLabel.toString().endsWith("...")); + } + + // Test that the tile cancels countdown if it is clicked when the controller is starting + @Test + public void testCancelRecording() { + when(mController.isStarting()).thenReturn(true); + when(mController.isRecording()).thenReturn(false); + + mTile.handleClick(); + + verify(mController, times(1)).cancelCountdown(); + } + + // Test that the tile is active and labeled correctly when the controller is recording + @Test + public void testIsRecording() { + when(mController.isStarting()).thenReturn(false); + when(mController.isRecording()).thenReturn(true); + + mTile.refreshState(); + mTestableLooper.processAllMessages(); + + assertEquals(Tile.STATE_ACTIVE, mTile.getState().state); + assertTrue(mTile.getState().secondaryLabel.toString().equals( + mContext.getString(R.string.quick_settings_screen_record_stop))); + } + + // Test that the tile stops the recording if it is clicked when the controller is recording + @Test + public void testStopRecording() { + when(mController.isStarting()).thenReturn(false); + when(mController.isRecording()).thenReturn(true); + + mTile.handleClick(); + + verify(mController, times(1)).stopRecording(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java new file mode 100644 index 000000000000..b877c7fa6859 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.screenrecord; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Mockito.verify; + +import android.app.PendingIntent; +import android.os.Looper; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +/** + * Tests for exception handling and bitmap configuration in adding smart actions to Screenshot + * Notification. + */ +public class RecordingControllerTest extends SysuiTestCase { + + @Mock + RecordingController.RecordingStateChangeCallback mCallback; + + RecordingController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = new RecordingController(mContext); + mController.addCallback(mCallback); + } + + // Test that when a countdown in progress is cancelled, the controller goes from starting to not + // starting, and notifies listeners. + @Test + public void testCancelCountdown() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + mController.startCountdown(100, 10, null, null); + + assertTrue(mController.isStarting()); + assertFalse(mController.isRecording()); + + mController.cancelCountdown(); + + assertFalse(mController.isStarting()); + assertFalse(mController.isRecording()); + + verify(mCallback).onCountdownEnd(); + } + + // Test that when recording is started, the start intent is sent and listeners are notified. + @Test + public void testStartRecording() throws PendingIntent.CanceledException { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + PendingIntent startIntent = Mockito.mock(PendingIntent.class); + mController.startCountdown(0, 0, startIntent, null); + + verify(mCallback).onCountdownEnd(); + verify(startIntent).send(); + } + + // Test that when recording is stopped, the stop intent is sent and listeners are notified. + @Test + public void testStopRecording() throws PendingIntent.CanceledException { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + PendingIntent startIntent = Mockito.mock(PendingIntent.class); + PendingIntent stopIntent = Mockito.mock(PendingIntent.class); + + mController.startCountdown(0, 0, startIntent, stopIntent); + mController.stopRecording(); + + assertFalse(mController.isStarting()); + assertFalse(mController.isRecording()); + verify(stopIntent).send(); + verify(mCallback).onRecordingEnd(); + } + + // Test that updating the controller state works and notifies listeners. + @Test + public void testUpdateState() { + mController.updateState(true); + assertTrue(mController.isRecording()); + verify(mCallback).onRecordingStart(); + + mController.updateState(false); + assertFalse(mController.isRecording()); + verify(mCallback).onRecordingEnd(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt index 72e6df27a254..a27c085e93a9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt @@ -16,15 +16,14 @@ package com.android.systemui.statusbar -import com.google.common.truth.Truth.assertThat - import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color -import android.graphics.Point import android.testing.AndroidTestingRunner +import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before import org.junit.Test @@ -32,6 +31,7 @@ import org.junit.runner.RunWith private const val WIDTH = 200 private const val HEIGHT = 200 +private const val WINDOW_TYPE = TYPE_NOTIFICATION_SHADE @RunWith(AndroidTestingRunner::class) @SmallTest @@ -46,10 +46,10 @@ class MediaArtworkProcessorTest : SysuiTestCase() { fun setUp() { processor = MediaArtworkProcessor() - val point = Point() - context.display.getSize(point) - screenWidth = point.x - screenHeight = point.y + val size = processor.getWindowSize(context, WINDOW_TYPE) + + screenWidth = size.width + screenHeight = size.height } @After @@ -63,7 +63,7 @@ class MediaArtworkProcessorTest : SysuiTestCase() { val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888) Canvas(artwork).drawColor(Color.BLUE) // WHEN the background is created from the artwork - val background = processor.processArtwork(context, artwork)!! + val background = processor.processArtwork(context, artwork, WINDOW_TYPE)!! // THEN the background has the size of the screen that has been downsamples assertThat(background.height).isLessThan(screenHeight) assertThat(background.width).isLessThan(screenWidth) @@ -76,8 +76,8 @@ class MediaArtworkProcessorTest : SysuiTestCase() { val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888) Canvas(artwork).drawColor(Color.BLUE) // WHEN the background is processed twice - val background1 = processor.processArtwork(context, artwork)!! - val background2 = processor.processArtwork(context, artwork)!! + val background1 = processor.processArtwork(context, artwork, WINDOW_TYPE)!! + val background2 = processor.processArtwork(context, artwork, WINDOW_TYPE)!! // THEN the two bitmaps are the same // Note: This is currently broken and trying to use caching causes issues assertThat(background1).isNotSameAs(background2) @@ -89,7 +89,7 @@ class MediaArtworkProcessorTest : SysuiTestCase() { val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ALPHA_8) Canvas(artwork).drawColor(Color.BLUE) // WHEN the background is created from the artwork - val background = processor.processArtwork(context, artwork)!! + val background = processor.processArtwork(context, artwork, WINDOW_TYPE)!! // THEN the background has Config ARGB_8888 assertThat(background.config).isEqualTo(Bitmap.Config.ARGB_8888) } @@ -102,7 +102,7 @@ class MediaArtworkProcessorTest : SysuiTestCase() { // AND the artwork is recycled artwork.recycle() // WHEN the background is created from the artwork - val background = processor.processArtwork(context, artwork) + val background = processor.processArtwork(context, artwork, WINDOW_TYPE) // THEN the processed bitmap is null assertThat(background).isNull() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 6a6e5c897318..98f12ce06e49 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -52,73 +52,55 @@ import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.ArraySet; -import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import com.android.internal.statusbar.NotificationVisibility; -import com.android.internal.util.NotificationMessagingUtil; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLifetimeExtender; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationRemoveInterceptor; import com.android.systemui.statusbar.RankingBuilder; -import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SmartReplyController; -import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; -import com.android.systemui.statusbar.notification.row.NotifBindPipeline; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.notification.row.RowContentBindParams; -import com.android.systemui.statusbar.notification.row.RowContentBindStage; +import com.android.systemui.statusbar.notification.row.NotificationEntryManagerInflationTest; import com.android.systemui.statusbar.notification.row.RowInflaterTask; -import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; -import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; -import com.android.systemui.util.time.FakeSystemClock; -import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; +/** + * Unit tests for {@link NotificationEntryManager}. This test will not test any interactions with + * inflation. Instead, for functional inflation tests, see + * {@link NotificationEntryManagerInflationTest}. + */ @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper() @@ -129,17 +111,11 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private NotificationPresenter mPresenter; @Mock private KeyguardEnvironment mEnvironment; @Mock private ExpandableNotificationRow mRow; - @Mock private NotificationListContainer mListContainer; @Mock private NotificationEntryListener mEntryListener; @Mock private NotificationRemoveInterceptor mRemoveInterceptor; - @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback; @Mock private HeadsUpManager mHeadsUpManager; @Mock private RankingMap mRankingMap; - @Mock private RemoteInputController mRemoteInputController; - @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; - @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private NotificationGroupManager mGroupManager; - @Mock private NotificationGutsManager mGutsManager; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private RowInflaterTask mAsyncInflationTask; @@ -147,18 +123,12 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private FeatureFlags mFeatureFlags; @Mock private LeakDetector mLeakDetector; @Mock private NotificationMediaManager mNotificationMediaManager; - @Mock private ExpandableNotificationRowComponent.Builder - mExpandableNotificationRowComponentBuilder; - @Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent; - @Mock private FalsingManager mFalsingManager; - @Mock private KeyguardBypassController mKeyguardBypassController; - @Mock private StatusBarStateController mStatusBarStateController; + @Mock private NotificationRowBinder mNotificationRowBinder; private int mId; private NotificationEntry mEntry; private StatusBarNotification mSbn; - private TestableNotificationEntryManager mEntryManager; - private CountDownLatch mCountDownLatch; + private NotificationEntryManager mEntryManager; private void setUserSentiment(String key, int sentiment) { doAnswer(invocationOnMock -> { @@ -202,41 +172,16 @@ public class NotificationEntryManagerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mDependency.injectMockDependency(SmartReplyController.class); - mCountDownLatch = new CountDownLatch(1); - allowTestableLooperAsMainThread(); mDependency.injectTestDependency(Dependency.MAIN_HANDLER, Handler.createAsync(TestableLooper.get(this).getLooper())); - when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); - when(mListContainer.getViewParentForNotification(any())).thenReturn( - new FrameLayout(mContext)); mEntry = createNotification(); mSbn = mEntry.getSbn(); - mEntry.expandedIcon = mock(StatusBarIconView.class); - - RowContentBindStage bindStage = mock(RowContentBindStage.class); - when(bindStage.getStageParams(any())).thenReturn(new RowContentBindParams()); - NotificationRowBinderImpl notificationRowBinder = - new NotificationRowBinderImpl(mContext, - new NotificationMessagingUtil(mContext), - mRemoteInputManager, - mLockscreenUserManager, - mock(NotifBindPipeline.class), - bindStage, - true, /* allowLongPress */ - mKeyguardBypassController, - mStatusBarStateController, - mGroupManager, - mGutsManager, - mNotificationInterruptionStateProvider, - RowInflaterTask::new, - mExpandableNotificationRowComponentBuilder); - when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false); when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false); - mEntryManager = new TestableNotificationEntryManager( + mEntryManager = new NotificationEntryManager( mLogger, mGroupManager, new NotificationRankingManager( @@ -250,7 +195,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mock(HighPriorityProvider.class)), mEnvironment, mFeatureFlags, - () -> notificationRowBinder, + () -> mNotificationRowBinder, () -> mRemoteInputManager, mLeakDetector, mock(ForegroundServiceDismissalFeatureController.class) @@ -259,152 +204,45 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntryManager.addNotificationEntryListener(mEntryListener); mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor); - notificationRowBinder.setUpWithPresenter(mPresenter, mListContainer, mBindCallback); - notificationRowBinder.setInflationCallback(mEntryManager); - notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class)); - - setUserSentiment( - mEntry.getKey(), Ranking.USER_SENTIMENT_NEUTRAL); - - ArgumentCaptor<ExpandableNotificationRow> viewCaptor = - ArgumentCaptor.forClass(ExpandableNotificationRow.class); - when(mExpandableNotificationRowComponentBuilder - .expandableNotificationRow(viewCaptor.capture())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder - .notificationEntry(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder - .onDismissRunnable(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder - .inflationCallback(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder - .rowContentBindStage(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder - .onExpandClickListener(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - - when(mExpandableNotificationRowComponentBuilder.build()) - .thenReturn(mExpandableNotificationRowComponent); - when(mExpandableNotificationRowComponent.getExpandableNotificationRowController()) - .thenAnswer((Answer<ExpandableNotificationRowController>) invocation -> - new ExpandableNotificationRowController( - viewCaptor.getValue(), - mock(ActivatableNotificationViewController.class), - mNotificationMediaManager, - mock(PluginManager.class), - new FakeSystemClock(), - "FOOBAR", "FOOBAR", - mKeyguardBypassController, - mGroupManager, - bindStage, - mock(NotificationLogger.class), - mHeadsUpManager, - mPresenter, - mStatusBarStateController, - mEntryManager, - mGutsManager, - true, - null, - mFalsingManager - )); - } - - @After - public void tearDown() { - // CLEAN UP inflation tasks so they don't callback in a future test - mEntry.abortTask(); + setUserSentiment(mSbn.getKey(), Ranking.USER_SENTIMENT_NEUTRAL); } - // TODO: These tests are closer to functional tests and we should move them to their own file. - // and also strip some of the verifies that make the test too complex @Test - @Ignore - public void testAddNotification() throws Exception { - TestableLooper.get(this).processAllMessages(); - - doAnswer(invocation -> { - mCountDownLatch.countDown(); - return null; - }).when(mBindCallback).onBindRow(any(), any(), any(), any()); - - // Post on main thread, otherwise we will be stuck waiting here for the inflation finished - // callback forever, since it won't execute until the tests ends. + public void testAddNotification_setsUserSentiment() { mEntryManager.addNotification(mSbn, mRankingMap); - TestableLooper.get(this).processMessages(1); - assertTrue(mCountDownLatch.await(10, TimeUnit.SECONDS)); - assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS)); - - // Check that no inflation error occurred. - verify(mEntryListener, never()).onInflationError(any(), any()); - // Row inflation: ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass( NotificationEntry.class); - verify(mBindCallback).onBindRow(entryCaptor.capture(), any(), eq(mSbn), any()); + verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture()); NotificationEntry entry = entryCaptor.getValue(); - verify(mRemoteInputManager).bindRow(entry.getRow()); - // Row content inflation: - verify(mEntryListener).onNotificationAdded(entry); - verify(mPresenter).updateNotificationViews(); - - assertEquals(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()), entry); - assertNotNull(entry.getRow()); - assertEquals(mEntry.getUserSentiment(), - Ranking.USER_SENTIMENT_NEUTRAL); + assertEquals(entry.getUserSentiment(), Ranking.USER_SENTIMENT_NEUTRAL); } @Test - @Ignore - public void testUpdateNotification() throws Exception { - TestableLooper.get(this).processAllMessages(); - + public void testUpdateNotification_updatesUserSentiment() { mEntryManager.addActiveNotificationForTest(mEntry); - setUserSentiment( mEntry.getKey(), Ranking.USER_SENTIMENT_NEGATIVE); mEntryManager.updateNotification(mSbn, mRankingMap); - TestableLooper.get(this).processMessages(1); - // Wait for content update. - assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS)); - - verify(mEntryListener, never()).onInflationError(any(), any()); - verify(mEntryListener).onPreEntryUpdated(mEntry); - verify(mPresenter).updateNotificationViews(); - verify(mEntryListener).onPostEntryUpdated(mEntry); - - assertNotNull(mEntry.getRow()); - assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, - mEntry.getUserSentiment()); + assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, mEntry.getUserSentiment()); } @Test - @Ignore public void testUpdateNotification_prePostEntryOrder() throws Exception { TestableLooper.get(this).processAllMessages(); mEntryManager.addActiveNotificationForTest(mEntry); mEntryManager.updateNotification(mSbn, mRankingMap); - TestableLooper.get(this).processMessages(1); - // Wait for content update. - assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS)); - - verify(mEntryListener, never()).onInflationError(any(), any()); // Ensure that update callbacks happen in correct order InOrder order = inOrder(mEntryListener, mPresenter, mEntryListener); order.verify(mEntryListener).onPreEntryUpdated(mEntry); order.verify(mPresenter).updateNotificationViews(); order.verify(mEntryListener).onPostEntryUpdated(mEntry); - - assertNotNull(mEntry.getRow()); } @Test @@ -414,8 +252,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - verify(mEntryListener, never()).onInflationError(any(), any()); - verify(mPresenter).updateNotificationViews(); verify(mEntryListener).onEntryRemoved( eq(mEntry), any(), eq(false) /* removedByUser */); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt index 8e330c6f5049..45c51d42c250 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt @@ -42,6 +42,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) @@ -52,18 +53,20 @@ class NotificationRankingManagerTest : SysuiTestCase() { } private lateinit var personNotificationIdentifier: PeopleNotificationIdentifier private lateinit var rankingManager: TestableNotificationRankingManager + private lateinit var sectionsManager: NotificationSectionsFeatureManager @Before fun setup() { personNotificationIdentifier = mock(PeopleNotificationIdentifier::class.java) + sectionsManager = mock(NotificationSectionsFeatureManager::class.java) rankingManager = TestableNotificationRankingManager( lazyMedia, mock(NotificationGroupManager::class.java), mock(HeadsUpManager::class.java), mock(NotificationFilter::class.java), mock(NotificationEntryManagerLogger::class.java), - mock(NotificationSectionsFeatureManager::class.java), + sectionsManager, personNotificationIdentifier, HighPriorityProvider(personNotificationIdentifier) ) @@ -146,39 +149,42 @@ class NotificationRankingManagerTest : SysuiTestCase() { @Test fun testSort_importantPeople() { + whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) val aN = Notification.Builder(mContext, "test") .setStyle(Notification.MessagingStyle("")) .build() - val aC = NotificationChannel("test", "", IMPORTANCE_DEFAULT) - aC.setConversationId("parent", "convo") val a = NotificationEntryBuilder() .setImportance(IMPORTANCE_HIGH) .setPkg("pkg") .setOpPkg("pkg") .setTag("tag") .setNotification(aN) - .setChannel(aC) + .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) .setUser(mContext.getUser()) .setOverrideGroupKey("") .build() + whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking)) + .thenReturn(false) + whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking)) + .thenReturn(true) val bN = Notification.Builder(mContext, "test") .setStyle(Notification.MessagingStyle("")) .build() - val bC = NotificationChannel("test", "", IMPORTANCE_DEFAULT) - bC.setConversationId("parent", "convo") - bC.setImportantConversation(true) val b = NotificationEntryBuilder() .setImportance(IMPORTANCE_HIGH) .setPkg("pkg2") .setOpPkg("pkg2") .setTag("tag") .setNotification(bN) - .setChannel(bC) + .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) .setUser(mContext.getUser()) .setOverrideGroupKey("") .build() - + whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking)) + .thenReturn(false) + whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking)) + .thenReturn(true) assertEquals( listOf(b, a), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java new file mode 100644 index 000000000000..ac4080868653 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row; + +import static android.app.NotificationManager.IMPORTANCE_DEFAULT; + +import static junit.framework.Assert.assertNotNull; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Notification; +import android.os.Handler; +import android.service.notification.NotificationListenerService; +import android.service.notification.NotificationListenerService.Ranking; +import android.service.notification.StatusBarNotification; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.internal.util.NotificationMessagingUtil; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.SbnBuilder; +import com.android.systemui.statusbar.SmartReplyController; +import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController; +import com.android.systemui.statusbar.notification.NotificationClicker; +import com.android.systemui.statusbar.notification.NotificationEntryListener; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger; +import com.android.systemui.statusbar.notification.NotificationFilter; +import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; +import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; +import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.statusbar.policy.SmartReplyConstants; +import com.android.systemui.util.leak.LeakDetector; +import com.android.systemui.util.time.FakeSystemClock; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; + +/** + * Functional tests for notification inflation from {@link NotificationEntryManager}. + */ +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class NotificationEntryManagerInflationTest extends SysuiTestCase { + + private static final String TEST_TITLE = "Title"; + private static final String TEST_TEXT = "Text"; + private static final long TIMEOUT_TIME = 10000; + private static final Runnable TIMEOUT_RUNNABLE = () -> { + throw new RuntimeException("Timed out waiting to inflate"); + }; + + @Mock private NotificationPresenter mPresenter; + @Mock private NotificationEntryManager.KeyguardEnvironment mEnvironment; + @Mock private NotificationListContainer mListContainer; + @Mock private NotificationEntryListener mEntryListener; + @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback; + @Mock private HeadsUpManager mHeadsUpManager; + @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + @Mock private NotificationLockscreenUserManager mLockscreenUserManager; + @Mock private NotificationGutsManager mGutsManager; + @Mock private NotificationRemoteInputManager mRemoteInputManager; + @Mock private NotificationMediaManager mNotificationMediaManager; + @Mock private ExpandableNotificationRowComponent.Builder + mExpandableNotificationRowComponentBuilder; + @Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent; + @Mock private FalsingManager mFalsingManager; + @Mock private KeyguardBypassController mKeyguardBypassController; + @Mock private StatusBarStateController mStatusBarStateController; + + @Mock private NotificationGroupManager mGroupManager; + @Mock private FeatureFlags mFeatureFlags; + @Mock private LeakDetector mLeakDetector; + + @Mock private ActivatableNotificationViewController mActivatableNotificationViewController; + @Mock private NotificationRowComponent.Builder mNotificationRowComponentBuilder; + + private StatusBarNotification mSbn; + private NotificationListenerService.RankingMap mRankingMap; + private NotificationEntryManager mEntryManager; + private NotificationRowBinderImpl mRowBinder; + private Handler mHandler; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mDependency.injectMockDependency(SmartReplyController.class); + + mHandler = Handler.createAsync(TestableLooper.get(this).getLooper()); + + Notification notification = new Notification.Builder(mContext) + .setSmallIcon(R.drawable.ic_person) + .setContentTitle(TEST_TITLE) + .setContentText(TEST_TEXT) + .build(); + mSbn = new SbnBuilder() + .setNotification(notification) + .build(); + + when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false); + when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false); + + mEntryManager = new NotificationEntryManager( + mock(NotificationEntryManagerLogger.class), + mGroupManager, + new NotificationRankingManager( + () -> mock(NotificationMediaManager.class), + mGroupManager, + mHeadsUpManager, + mock(NotificationFilter.class), + mock(NotificationEntryManagerLogger.class), + mock(NotificationSectionsFeatureManager.class), + mock(PeopleNotificationIdentifier.class), + mock(HighPriorityProvider.class)), + mEnvironment, + mFeatureFlags, + () -> mRowBinder, + () -> mRemoteInputManager, + mLeakDetector, + mock(ForegroundServiceDismissalFeatureController.class) + ); + + NotifRemoteViewCache cache = new NotifRemoteViewCacheImpl(mEntryManager); + NotifBindPipeline pipeline = new NotifBindPipeline( + mEntryManager, + mock(NotifBindPipelineLogger.class)); + NotificationContentInflater binder = new NotificationContentInflater( + cache, + mRemoteInputManager, + () -> mock(SmartReplyConstants.class), + () -> mock(SmartReplyController.class)); + RowContentBindStage stage = new RowContentBindStage( + binder, + mock(NotifInflationErrorManager.class), + mock(RowContentBindStageLogger.class)); + pipeline.setStage(stage); + + ArgumentCaptor<ExpandableNotificationRow> viewCaptor = + ArgumentCaptor.forClass(ExpandableNotificationRow.class); + when(mExpandableNotificationRowComponentBuilder + .expandableNotificationRow(viewCaptor.capture())) + .thenReturn(mExpandableNotificationRowComponentBuilder); + when(mExpandableNotificationRowComponentBuilder + .notificationEntry(any())) + .thenReturn(mExpandableNotificationRowComponentBuilder); + when(mExpandableNotificationRowComponentBuilder + .onDismissRunnable(any())) + .thenReturn(mExpandableNotificationRowComponentBuilder); + when(mExpandableNotificationRowComponentBuilder + .inflationCallback(any())) + .thenReturn(mExpandableNotificationRowComponentBuilder); + when(mExpandableNotificationRowComponentBuilder + .rowContentBindStage(any())) + .thenReturn(mExpandableNotificationRowComponentBuilder); + when(mExpandableNotificationRowComponentBuilder + .onExpandClickListener(any())) + .thenReturn(mExpandableNotificationRowComponentBuilder); + + when(mExpandableNotificationRowComponentBuilder.build()) + .thenReturn(mExpandableNotificationRowComponent); + when(mExpandableNotificationRowComponent.getExpandableNotificationRowController()) + .thenAnswer((Answer<ExpandableNotificationRowController>) invocation -> + new ExpandableNotificationRowController( + viewCaptor.getValue(), + mock(ActivatableNotificationViewController.class), + mNotificationMediaManager, + mock(PluginManager.class), + new FakeSystemClock(), + "FOOBAR", "FOOBAR", + mKeyguardBypassController, + mGroupManager, + stage, + mock(NotificationLogger.class), + mHeadsUpManager, + mPresenter, + mStatusBarStateController, + mEntryManager, + mGutsManager, + true, + null, + mFalsingManager + )); + + when(mNotificationRowComponentBuilder.activatableNotificationView(any())) + .thenReturn(mNotificationRowComponentBuilder); + when(mNotificationRowComponentBuilder.build()).thenReturn( + () -> mActivatableNotificationViewController); + + mRowBinder = new NotificationRowBinderImpl( + mContext, + new NotificationMessagingUtil(mContext), + mRemoteInputManager, + mLockscreenUserManager, + pipeline, + stage, + true, /* allowLongPress */ + mock(KeyguardBypassController.class), + mock(StatusBarStateController.class), + mGroupManager, + mGutsManager, + mNotificationInterruptionStateProvider, + RowInflaterTask::new, + mExpandableNotificationRowComponentBuilder); + + mEntryManager.setUpWithPresenter(mPresenter); + mEntryManager.addNotificationEntryListener(mEntryListener); + + mRowBinder.setUpWithPresenter(mPresenter, mListContainer, mBindCallback); + mRowBinder.setInflationCallback(mEntryManager); + mRowBinder.setNotificationClicker(mock(NotificationClicker.class)); + + Ranking ranking = new Ranking(); + ranking.populate( + mSbn.getKey(), + 0, + false, + 0, + 0, + IMPORTANCE_DEFAULT, + null, + null, + null, + null, + null, + true, + Ranking.USER_SENTIMENT_NEUTRAL, + false, + -1, + false, + null, + null, + false, + false, + false); + mRankingMap = new NotificationListenerService.RankingMap(new Ranking[] {ranking}); + + TestableLooper.get(this).processAllMessages(); + } + + @After + public void cleanUp() { + // Don't leave anything on main thread + TestableLooper.get(this).processAllMessages(); + } + + @Test + public void testAddNotification() { + // WHEN a notification is added + mEntryManager.addNotification(mSbn, mRankingMap); + ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass( + NotificationEntry.class); + verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture()); + NotificationEntry entry = entryCaptor.getValue(); + + // Wait for inflation + // row inflation, system notification, remote views, contracted view + waitForMessages(4); + + // THEN the notification has its row inflated + assertNotNull(entry.getRow()); + assertNotNull(entry.getRow().getPrivateLayout().getContractedChild()); + + // THEN inflation callbacks are called + verify(mBindCallback).onBindRow(eq(entry), any(), eq(mSbn), any()); + verify(mEntryListener, never()).onInflationError(any(), any()); + verify(mEntryListener).onEntryInflated(entry); + verify(mEntryListener).onNotificationAdded(entry); + + // THEN the notification is active + assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); + + // THEN we update the presenter + verify(mPresenter).updateNotificationViews(); + } + + @Test + public void testUpdateNotification() { + // GIVEN a notification already added + mEntryManager.addNotification(mSbn, mRankingMap); + ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass( + NotificationEntry.class); + verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture()); + NotificationEntry entry = entryCaptor.getValue(); + waitForMessages(4); + + Mockito.reset(mEntryListener); + Mockito.reset(mPresenter); + + // WHEN the notification is updated + mEntryManager.updateNotification(mSbn, mRankingMap); + + // Wait for inflation + // remote views, contracted view + waitForMessages(2); + + // THEN the notification has its row and inflated + assertNotNull(entry.getRow()); + + // THEN inflation callbacks are called + verify(mEntryListener, never()).onInflationError(any(), any()); + verify(mEntryListener).onEntryReinflated(entry); + + // THEN we update the presenter + verify(mPresenter).updateNotificationViews(); + } + + /** + * Wait for a certain number of messages to finish before continuing, timing out if they never + * occur. + * + * As part of the inflation pipeline, the main thread is forced to deal with several callbacks + * due to the nature of the API used (generally because they're {@link android.os.AsyncTask} + * callbacks). In order, these are + * + * 1) Callback after row inflation. See {@link RowInflaterTask}. + * 2) Callback checking if row is system notification. See + * {@link ExpandableNotificationRow#setEntry} + * 3) Callback after remote views are created. See + * {@link NotificationContentInflater.AsyncInflationTask}. + * 4-6) Callback after each content view is inflated/rebound from remote view. See + * {@link NotificationContentInflater#applyRemoteView} and {@link InflationFlag}. + * + * Depending on the test, only some of these will be necessary. For example, generally, not + * every content view is inflated or the row may not be inflated if one already exists. + * + * Currently, the burden is on the developer to figure these out until we have a much more + * test-friendly way of executing inflation logic (i.e. pass in an executor). + */ + private void waitForMessages(int numMessages) { + mHandler.postDelayed(TIMEOUT_RUNNABLE, TIMEOUT_TIME); + TestableLooper.get(this).processMessages(numMessages); + mHandler.removeCallbacks(TIMEOUT_RUNNABLE); + } + +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java index 7d52df731efe..2782f3d793a0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java @@ -32,6 +32,7 @@ import android.view.WindowManager; import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; +import com.android.systemui.DumpController; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -58,6 +59,7 @@ public class NotificationShadeWindowControllerTest extends SysuiTestCase { @Mock private KeyguardBypassController mKeyguardBypassController; @Mock private SysuiColorExtractor mColorExtractor; @Mock ColorExtractor.GradientColors mGradientColors; + @Mock private DumpController mDumpController; private NotificationShadeWindowController mNotificationShadeWindowController; @@ -69,7 +71,8 @@ public class NotificationShadeWindowControllerTest extends SysuiTestCase { mNotificationShadeWindowController = new NotificationShadeWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, - mConfigurationController, mKeyguardBypassController, mColorExtractor); + mConfigurationController, mKeyguardBypassController, mColorExtractor, + mDumpController); mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView); mNotificationShadeWindowController.attach(); diff --git a/packages/Tethering/TEST_MAPPING b/packages/Tethering/TEST_MAPPING new file mode 100644 index 000000000000..73254cdc79a9 --- /dev/null +++ b/packages/Tethering/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "postsubmit": [ + { + "name": "TetheringTests" + } + ] +} diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index cb0de7a860ac..1a3d5b659ee3 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -83,7 +83,6 @@ java_library { name: "framework-tethering-stubs", srcs: [":framework-tethering-stubs-sources"], libs: ["framework-all"], - static_libs: ["tethering-aidl-interfaces-java"], sdk_version: "core_platform", } diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index b4d49c02b085..3acc76657731 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -40,12 +40,14 @@ import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.DhcpServingParamsParcelExt; import android.net.dhcp.IDhcpLeaseCallbacks; import android.net.dhcp.IDhcpServer; +import android.net.ip.IpNeighborMonitor.NeighborEvent; import android.net.ip.RouterAdvertisementDaemon.RaParams; import android.net.shared.NetdUtils; import android.net.shared.RouteUtils; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.SharedLog; +import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; @@ -59,14 +61,17 @@ import com.android.internal.util.MessageUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.NetworkInterface; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; import java.util.Random; @@ -149,6 +154,12 @@ public class IpServer extends StateMachine { /** Capture IpServer dependencies, for injection. */ public abstract static class Dependencies { + /** Create an IpNeighborMonitor to be used by this IpServer */ + public IpNeighborMonitor getIpNeighborMonitor(Handler handler, SharedLog log, + IpNeighborMonitor.NeighborEventConsumer consumer) { + return new IpNeighborMonitor(handler, log, consumer); + } + /** Create a RouterAdvertisementDaemon instance to be used by IpServer.*/ public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) { return new RouterAdvertisementDaemon(ifParams); @@ -159,6 +170,15 @@ public class IpServer extends StateMachine { return InterfaceParams.getByName(ifName); } + /** Get |ifName|'s interface index. */ + public int getIfindex(String ifName) { + try { + return NetworkInterface.getByName(ifName).getIndex(); + } catch (IOException | NullPointerException e) { + Log.e(TAG, "Can't determine interface index for interface " + ifName); + return 0; + } + } /** Create a DhcpServer instance to be used by IpServer. */ public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params, DhcpServerCallbacks cb); @@ -184,6 +204,8 @@ public class IpServer extends StateMachine { public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IPSERVER + 9; // new IPv6 tethering parameters need to be processed public static final int CMD_IPV6_TETHER_UPDATE = BASE_IPSERVER + 10; + // new neighbor cache entry on our interface + public static final int CMD_NEIGHBOR_EVENT = BASE_IPSERVER + 11; private final State mInitialState; private final State mLocalHotspotState; @@ -223,6 +245,40 @@ public class IpServer extends StateMachine { @NonNull private List<TetheredClient> mDhcpLeases = Collections.emptyList(); + private int mLastIPv6UpstreamIfindex = 0; + + private class MyNeighborEventConsumer implements IpNeighborMonitor.NeighborEventConsumer { + public void accept(NeighborEvent e) { + sendMessage(CMD_NEIGHBOR_EVENT, e); + } + } + + static class Ipv6ForwardingRule { + public final int upstreamIfindex; + public final int downstreamIfindex; + public final Inet6Address address; + public final MacAddress srcMac; + public final MacAddress dstMac; + + Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, Inet6Address address, + MacAddress srcMac, MacAddress dstMac) { + this.upstreamIfindex = upstreamIfindex; + this.downstreamIfindex = downstreamIfIndex; + this.address = address; + this.srcMac = srcMac; + this.dstMac = dstMac; + } + + public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) { + return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac, + dstMac); + } + } + private final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> mIpv6ForwardingRules = + new LinkedHashMap<>(); + + private final IpNeighborMonitor mIpNeighborMonitor; + public IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, INetd netd, Callback callback, boolean usingLegacyDhcp, Dependencies deps) { @@ -240,6 +296,12 @@ public class IpServer extends StateMachine { mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; mServingMode = STATE_AVAILABLE; + mIpNeighborMonitor = mDeps.getIpNeighborMonitor(getHandler(), mLog, + new MyNeighborEventConsumer()); + if (!mIpNeighborMonitor.start()) { + mLog.e("Failed to create IpNeighborMonitor on " + mIfaceName); + } + mInitialState = new InitialState(); mLocalHotspotState = new LocalHotspotState(); mTetheredState = new TetheredState(); @@ -607,13 +669,21 @@ public class IpServer extends StateMachine { } RaParams params = null; + int upstreamIfindex = 0; if (v6only != null) { + final String upstreamIface = v6only.getInterfaceName(); + params = new RaParams(); - params.mtu = v6only.getMtu(); + // We advertise an mtu lower by 16, which is the closest multiple of 8 >= 14, + // the ethernet header size. This makes kernel ebpf tethering offload happy. + // This hack should be reverted once we have the kernel fixed up. + // Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu) + // see RouterAdvertisementDaemon.java putMtu() + params.mtu = v6only.getMtu() - 16; params.hasDefaultRoute = v6only.hasIpv6DefaultRoute(); - if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName()); + if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface); for (LinkAddress linkAddr : v6only.getLinkAddresses()) { if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue; @@ -627,12 +697,18 @@ public class IpServer extends StateMachine { params.dnses.add(dnsServer); } } + + upstreamIfindex = mDeps.getIfindex(upstreamIface); } + // If v6only is null, we pass in null to setRaParams(), which handles // deprecation of any existing RA data. setRaParams(params); mLastIPv6LinkProperties = v6only; + + updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfindex, null); + mLastIPv6UpstreamIfindex = upstreamIfindex; } private void configureLocalIPv6Routes( @@ -727,6 +803,73 @@ public class IpServer extends StateMachine { } } + private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) { + try { + mNetd.tetherRuleAddDownstreamIpv6(mInterfaceParams.index, rule.upstreamIfindex, + rule.address.getAddress(), mInterfaceParams.macAddr.toByteArray(), + rule.dstMac.toByteArray()); + mIpv6ForwardingRules.put(rule.address, rule); + } catch (RemoteException | ServiceSpecificException e) { + Log.e(TAG, "Could not add IPv6 downstream rule: " + e); + } + } + + private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) { + try { + mNetd.tetherRuleRemoveDownstreamIpv6(rule.upstreamIfindex, rule.address.getAddress()); + if (removeFromMap) { + mIpv6ForwardingRules.remove(rule.address); + } + } catch (RemoteException | ServiceSpecificException e) { + Log.e(TAG, "Could not remove IPv6 downstream rule: " + e); + } + } + + // Convenience method to replace a rule with the same rule on a new upstream interface. + // Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions. + // Relies on the fact that rules are in a map indexed by IP address. + private void updateIpv6ForwardingRule(Ipv6ForwardingRule rule, int newIfindex) { + addIpv6ForwardingRule(rule.onNewUpstream(newIfindex)); + removeIpv6ForwardingRule(rule, false /*removeFromMap*/); + } + + // Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream + // changes or if a neighbor event is received. + private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex, + NeighborEvent e) { + // If the upstream interface has changed, remove all rules and re-add them with the new + // upstream interface. + if (prevUpstreamIfindex != upstreamIfindex) { + for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) { + updateIpv6ForwardingRule(rule, upstreamIfindex); + } + } + + // If we're here to process a NeighborEvent, do so now. + if (e == null) return; + if (!(e.ip instanceof Inet6Address) || e.ip.isMulticastAddress() + || e.ip.isLoopbackAddress() || e.ip.isLinkLocalAddress()) { + return; + } + + Ipv6ForwardingRule rule = new Ipv6ForwardingRule(mLastIPv6UpstreamIfindex, + mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr, + e.macAddr); + if (e.isValid()) { + addIpv6ForwardingRule(rule); + } else { + removeIpv6ForwardingRule(rule, true /*removeFromMap*/); + } + } + + private void handleNeighborEvent(NeighborEvent e) { + if (mInterfaceParams != null + && mInterfaceParams.index == e.ifindex + && mInterfaceParams.hasMacAddress) { + updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, mLastIPv6UpstreamIfindex, e); + } + } + private byte getHopLimit(String upstreamIface) { try { int upstreamHopLimit = Integer.parseUnsignedInt( @@ -1014,6 +1157,9 @@ public class IpServer extends StateMachine { } } break; + case CMD_NEIGHBOR_EVENT: + handleNeighborEvent((NeighborEvent) message.obj); + break; default: return false; } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 6261def6a939..72fe95b227a2 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -314,9 +314,13 @@ public class Tethering { startStateMachineUpdaters(mHandler); startTrackDefaultNetwork(); - getWifiManager().registerSoftApCallback( - mHandler::post /* executor */, - new TetheringSoftApCallback()); + + final WifiManager wifiManager = getWifiManager(); + if (wifiManager != null) { + wifiManager.registerSoftApCallback( + mHandler::post /* executor */, + new TetheringSoftApCallback()); + } } private void startStateMachineUpdaters(Handler handler) { diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index acedfab3b7ab..33b35586eecf 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -29,6 +29,11 @@ import static android.net.ip.IpServer.STATE_AVAILABLE; import static android.net.ip.IpServer.STATE_LOCAL_ONLY; import static android.net.ip.IpServer.STATE_TETHERED; import static android.net.ip.IpServer.STATE_UNAVAILABLE; +import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH; +import static android.net.netlink.NetlinkConstants.RTM_NEWNEIGH; +import static android.net.netlink.StructNdMsg.NUD_FAILED; +import static android.net.netlink.StructNdMsg.NUD_REACHABLE; +import static android.net.netlink.StructNdMsg.NUD_STALE; import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static org.junit.Assert.assertEquals; @@ -41,6 +46,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; @@ -52,6 +58,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.net.INetd; +import android.net.InetAddresses; import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; import android.net.LinkAddress; @@ -61,6 +68,8 @@ import android.net.RouteInfo; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpServer; import android.net.dhcp.IDhcpServerCallbacks; +import android.net.ip.IpNeighborMonitor.NeighborEvent; +import android.net.ip.IpNeighborMonitor.NeighborEventConsumer; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.SharedLog; @@ -81,6 +90,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.net.Inet4Address; +import java.net.InetAddress; @RunWith(AndroidJUnit4.class) @SmallTest @@ -88,6 +98,8 @@ public class IpServerTest { private static final String IFACE_NAME = "testnet1"; private static final String UPSTREAM_IFACE = "upstream0"; private static final String UPSTREAM_IFACE2 = "upstream1"; + private static final int UPSTREAM_IFINDEX = 101; + private static final int UPSTREAM_IFINDEX2 = 102; private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1"; private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; private static final int DHCP_LEASE_TIME_SECS = 3600; @@ -102,6 +114,7 @@ public class IpServerTest { @Mock private SharedLog mSharedLog; @Mock private IDhcpServer mDhcpServer; @Mock private RouterAdvertisementDaemon mRaDaemon; + @Mock private IpNeighborMonitor mIpNeighborMonitor; @Mock private IpServer.Dependencies mDependencies; @Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor; @@ -111,6 +124,7 @@ public class IpServerTest { ArgumentCaptor.forClass(LinkProperties.class); private IpServer mIpServer; private InterfaceConfigurationParcel mInterfaceConfiguration; + private NeighborEventConsumer mNeighborEventConsumer; private void initStateMachine(int interfaceType) throws Exception { initStateMachine(interfaceType, false /* usingLegacyDhcp */); @@ -130,16 +144,28 @@ public class IpServerTest { }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any()); when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon); when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS); + + when(mDependencies.getIfindex(eq(UPSTREAM_IFACE))).thenReturn(UPSTREAM_IFINDEX); + when(mDependencies.getIfindex(eq(UPSTREAM_IFACE2))).thenReturn(UPSTREAM_IFINDEX2); + mInterfaceConfiguration = new InterfaceConfigurationParcel(); mInterfaceConfiguration.flags = new String[0]; if (interfaceType == TETHERING_BLUETOOTH) { mInterfaceConfiguration.ipv4Addr = BLUETOOTH_IFACE_ADDR; mInterfaceConfiguration.prefixLength = BLUETOOTH_DHCP_PREFIX_LENGTH; } + + ArgumentCaptor<NeighborEventConsumer> neighborCaptor = + ArgumentCaptor.forClass(NeighborEventConsumer.class); + doReturn(mIpNeighborMonitor).when(mDependencies).getIpNeighborMonitor(any(), any(), + neighborCaptor.capture()); + mIpServer = new IpServer( IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mCallback, usingLegacyDhcp, mDependencies); mIpServer.start(); + mNeighborEventConsumer = neighborCaptor.getValue(); + // Starting the state machine always puts us in a consistent state and notifies // the rest of the world that we've changed from an unknown to available state. mLooper.dispatchAll(); @@ -158,7 +184,9 @@ public class IpServerTest { initStateMachine(interfaceType, usingLegacyDhcp); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); if (upstreamIface != null) { - dispatchTetherConnectionChanged(upstreamIface); + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(upstreamIface); + dispatchTetherConnectionChanged(upstreamIface, lp); } reset(mNetd, mCallback); } @@ -170,6 +198,8 @@ public class IpServerTest { @Test public void startsOutAvailable() { + when(mDependencies.getIpNeighborMonitor(any(), any(), any())) + .thenReturn(mIpNeighborMonitor); mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog, mNetd, mCallback, false /* usingLegacyDhcp */, mDependencies); mIpServer.start(); @@ -467,6 +497,89 @@ public class IpServerTest { verify(mDependencies, never()).makeDhcpServer(any(), any(), any()); } + private InetAddress addr(String addr) throws Exception { + return InetAddresses.parseNumericAddress(addr); + } + + private void recvNewNeigh(int ifindex, InetAddress addr, short nudState, MacAddress mac) { + mNeighborEventConsumer.accept(new NeighborEvent(0, RTM_NEWNEIGH, ifindex, addr, + nudState, mac)); + mLooper.dispatchAll(); + } + + private void recvDelNeigh(int ifindex, InetAddress addr, short nudState, MacAddress mac) { + mNeighborEventConsumer.accept(new NeighborEvent(0, RTM_DELNEIGH, ifindex, addr, + nudState, mac)); + mLooper.dispatchAll(); + } + + @Test + public void addRemoveipv6ForwardingRules() throws Exception { + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */); + + final int myIfindex = TEST_IFACE_PARAMS.index; + final int notMyIfindex = myIfindex - 1; + + final MacAddress myMac = TEST_IFACE_PARAMS.macAddr; + final InetAddress neighA = InetAddresses.parseNumericAddress("2001:db8::1"); + final InetAddress neighB = InetAddresses.parseNumericAddress("2001:db8::2"); + final InetAddress neighLL = InetAddresses.parseNumericAddress("fe80::1"); + final InetAddress neighMC = InetAddresses.parseNumericAddress("ff02::1234"); + final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a"); + final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b"); + + reset(mNetd); + + // Events on other interfaces are ignored. + recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA); + verifyNoMoreInteractions(mNetd); + + // Events on this interface are received and sent to netd. + recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); + verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), + eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray())); + reset(mNetd); + + recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); + verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), + eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); + reset(mNetd); + + // Link-local and multicast neighbors are ignored. + recvNewNeigh(notMyIfindex, neighLL, NUD_REACHABLE, macA); + verifyNoMoreInteractions(mNetd); + recvNewNeigh(notMyIfindex, neighMC, NUD_REACHABLE, macA); + verifyNoMoreInteractions(mNetd); + + // A neighbor that is no longer valid causes the rule to be removed. + recvNewNeigh(myIfindex, neighA, NUD_FAILED, macA); + verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress())); + reset(mNetd); + + // A neighbor that is deleted causes the rule to be removed. + recvDelNeigh(myIfindex, neighB, NUD_STALE, macB); + verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); + reset(mNetd); + + // Upstream changes result in deleting and re-adding the rules. + recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); + recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); + reset(mNetd); + + InOrder inOrder = inOrder(mNetd); + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(UPSTREAM_IFACE2); + dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp); + inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2), + eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray())); + inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), + eq(neighA.getAddress())); + inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2), + eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); + inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), + eq(neighB.getAddress())); + } + private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception { verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any()); verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks( @@ -508,13 +621,21 @@ public class IpServerTest { * * @see #dispatchCommand(int) * @param upstreamIface String name of upstream interface (or null) + * @param v6lp IPv6 LinkProperties of the upstream interface, or null for an IPv4-only upstream. */ - private void dispatchTetherConnectionChanged(String upstreamIface) { + private void dispatchTetherConnectionChanged(String upstreamIface, LinkProperties v6lp) { mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, new InterfaceSet(upstreamIface)); + if (v6lp != null) { + mIpServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, v6lp); + } mLooper.dispatchAll(); } + private void dispatchTetherConnectionChanged(String upstreamIface) { + dispatchTetherConnectionChanged(upstreamIface, null); + } + private void assertIPv4AddressAndDirectlyConnectedRoute(LinkProperties lp) { // Find the first IPv4 LinkAddress. LinkAddress addr4 = null; diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 8e5aaf265707..f2074bd46886 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -95,6 +95,7 @@ import android.net.TetheringRequestParcel; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpServer; +import android.net.ip.IpNeighborMonitor; import android.net.ip.IpServer; import android.net.ip.RouterAdvertisementDaemon; import android.net.util.InterfaceParams; @@ -173,6 +174,7 @@ public class TetheringTest { @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor; @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator; @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon; + @Mock private IpNeighborMonitor mIpNeighborMonitor; @Mock private IDhcpServer mDhcpServer; @Mock private INetd mNetd; @Mock private UserManager mUserManager; @@ -278,6 +280,11 @@ public class TetheringTest { } }).run(); } + + public IpNeighborMonitor getIpNeighborMonitor(Handler h, SharedLog l, + IpNeighborMonitor.NeighborEventConsumer c) { + return mIpNeighborMonitor; + } } private class MockTetheringConfiguration extends TetheringConfiguration { diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index eda3fb9c8698..cff55046fc2b 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -252,6 +252,9 @@ message SystemMessage { // Package: android NOTE_ID_WIFI_SIM_REQUIRED = 60; + // Inform the user a foreground service while-in-use permission is restricted. + NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION = 61; + // ADD_NEW_IDS_ABOVE_THIS_LINE // Legacy IDs with arbitrary values appear below // Legacy IDs existed as stable non-conflicting constants prior to the O release diff --git a/services/Android.bp b/services/Android.bp index c77e75da66ba..db6e21a62ff3 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -114,9 +114,10 @@ droidstubs { name: "services-stubs.sources", srcs: [":services-all-sources"], installable: false, - // TODO: remove the --hide options below args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\)" + " --hide-annotation android.annotation.Hide" + + " --hide InternalClasses" + // com.android.* classes are okay in this interface + // TODO: remove the --hide options below " --hide-package com.google.android.startop.iorap" + " --hide ReferencesHidden" + " --hide DeprecationMismatch" + diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS index 265674a74b7e..c6f42f719caa 100644 --- a/services/accessibility/OWNERS +++ b/services/accessibility/OWNERS @@ -1,3 +1,4 @@ svetoslavganov@google.com pweaver@google.com rhedjao@google.com +qasid@google.com diff --git a/services/api/current.txt b/services/api/current.txt index 8a82e610c233..26a65f21ed83 100644 --- a/services/api/current.txt +++ b/services/api/current.txt @@ -3,9 +3,9 @@ package com.android.permission.persistence { public interface RuntimePermissionsPersistence { method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance(); - method public void delete(@NonNull android.os.UserHandle); - method @Nullable public com.android.permission.persistence.RuntimePermissionsState read(@NonNull android.os.UserHandle); - method public void write(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle); + method public void deleteAsUser(@NonNull android.os.UserHandle); + method @Nullable public com.android.permission.persistence.RuntimePermissionsState readAsUser(@NonNull android.os.UserHandle); + method public void writeAsUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle); } public final class RuntimePermissionsState { @@ -30,9 +30,9 @@ package com.android.role.persistence { public interface RolesPersistence { method @NonNull public static com.android.role.persistence.RolesPersistence createInstance(); - method public void delete(@NonNull android.os.UserHandle); - method @Nullable public com.android.role.persistence.RolesState read(@NonNull android.os.UserHandle); - method public void write(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle); + method public void deleteAsUser(@NonNull android.os.UserHandle); + method @Nullable public com.android.role.persistence.RolesState readAsUser(@NonNull android.os.UserHandle); + method public void writeAsUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle); } public final class RolesState { diff --git a/services/api/lint-baseline.txt b/services/api/lint-baseline.txt index 0b8658cf469d..e985ddb5352b 100644 --- a/services/api/lint-baseline.txt +++ b/services/api/lint-baseline.txt @@ -1,35 +1,5 @@ // Baseline format: 1.0 -InternalClasses: com.android.permission.persistence.RuntimePermissionsPersistence: - Internal classes must not be exposed -InternalClasses: com.android.permission.persistence.RuntimePermissionsState: - Internal classes must not be exposed -InternalClasses: com.android.permission.persistence.RuntimePermissionsState.PermissionState: - Internal classes must not be exposed -InternalClasses: com.android.role.persistence.RolesPersistence: - Internal classes must not be exposed -InternalClasses: com.android.role.persistence.RolesState: - Internal classes must not be exposed -InternalClasses: com.android.server.SystemService: - Internal classes must not be exposed -InternalClasses: com.android.server.SystemService.TargetUser: - Internal classes must not be exposed - - ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder): Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)} ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean): Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder,boolean)} - - -UserHandleName: com.android.permission.persistence.RuntimePermissionsPersistence#delete(android.os.UserHandle): - Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `delete` -UserHandleName: com.android.permission.persistence.RuntimePermissionsPersistence#read(android.os.UserHandle): - Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `read` -UserHandleName: com.android.permission.persistence.RuntimePermissionsPersistence#write(com.android.permission.persistence.RuntimePermissionsState, android.os.UserHandle): - Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `write` -UserHandleName: com.android.role.persistence.RolesPersistence#delete(android.os.UserHandle): - Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `delete` -UserHandleName: com.android.role.persistence.RolesPersistence#read(android.os.UserHandle): - Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `read` -UserHandleName: com.android.role.persistence.RolesPersistence#write(com.android.role.persistence.RolesState, android.os.UserHandle): - Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `write` diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java index 1fc48d235add..6daa1064c89e 100644 --- a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java +++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java @@ -21,6 +21,7 @@ import static com.android.server.autofill.Helper.sDebug; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; +import android.os.Bundle; import android.os.RemoteException; import android.util.Log; import android.view.autofill.AutofillId; @@ -29,6 +30,7 @@ import android.view.inputmethod.InlineSuggestionsRequest; import com.android.internal.annotations.GuardedBy; import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.IInlineSuggestionsResponseCallback; +import com.android.internal.view.InlineSuggestionsRequestInfo; import com.android.server.inputmethod.InputMethodManagerInternal; import java.util.concurrent.CancellationException; @@ -71,8 +73,10 @@ final class InlineSuggestionSession { synchronized (mLock) { cancelCurrentRequest(); mPendingImeResponse = new CompletableFuture<>(); + // TODO(b/146454892): pipe the uiExtras from the ExtServices. mInputMethodManagerInternal.onCreateInlineSuggestionsRequest( - mUserId, mComponentName, currentViewId, + mUserId, + new InlineSuggestionsRequestInfo(mComponentName, currentViewId, new Bundle()), new InlineSuggestionsRequestCallbackImpl(mPendingImeResponse)); } } diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 3c37f737f8be..e434be648dcb 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -76,9 +76,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; @@ -802,6 +800,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { final int size = in.getDataSize(); if (excludedKeysForPackage != null && excludedKeysForPackage.contains(key)) { + Slog.i(TAG, "Skipping blocked key " + key); in.skipEntityData(); continue; } diff --git a/services/core/Android.bp b/services/core/Android.bp index 6fc6084de181..228d9bebaae6 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -113,6 +113,7 @@ java_library_static { "android.hardware.broadcastradio-V2.0-java", "android.hardware.health-V1.0-java", "android.hardware.health-V2.0-java", + "android.hardware.health-V2.1-java", "android.hardware.light-java", "android.hardware.weaver-V1.0-java", "android.hardware.biometrics.face-V1.1-java", diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 76f6ef63ae7e..0f8d57e3d9e3 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -29,8 +29,7 @@ import android.content.pm.PackageManager.ApplicationInfoFlags; import android.content.pm.PackageManager.ComponentInfoFlags; import android.content.pm.PackageManager.PackageInfoFlags; import android.content.pm.PackageManager.ResolveInfoFlags; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.component.ParsedMainComponent; import android.os.Bundle; import android.os.PersistableBundle; import android.util.ArrayMap; @@ -38,6 +37,8 @@ import android.util.ArraySet; import android.util.SparseArray; import com.android.server.pm.PackageList; +import com.android.server.pm.PackageSetting; +import com.android.server.pm.parsing.pkg.AndroidPackage; import java.io.IOException; import java.lang.annotation.Retention; @@ -586,9 +587,7 @@ public abstract class PackageManagerInternal { */ public abstract @Nullable AndroidPackage getPackage(@NonNull String packageName); - // TODO(b/135203078): PackageSetting can't be referenced directly. Should move to a server side - // internal PM which is aware of PS. - public abstract @Nullable Object getPackageSetting(String packageName); + public abstract @Nullable PackageSetting getPackageSetting(String packageName); /** * Returns a package for the given UID. If the UID is part of a shared user ID, one @@ -625,18 +624,17 @@ public abstract class PackageManagerInternal { */ public abstract void removePackageListObserver(@NonNull PackageListObserver observer); - // TODO(b/135203078): PackageSetting can't be referenced directly /** * Returns a package object for the disabled system package name. */ - public abstract @Nullable Object getDisabledSystemPackage(@NonNull String packageName); + public abstract @Nullable PackageSetting getDisabledSystemPackage(@NonNull String packageName); /** * Returns the package name for the disabled system package. * * This is equivalent to * {@link #getDisabledSystemPackage(String)} - * .{@link com.android.server.pm.PackageSetting#pkg} + * .{@link PackageSetting#pkg} * .{@link AndroidPackage#getPackageName()} */ public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName); @@ -677,7 +675,7 @@ public abstract class PackageManagerInternal { /** * Returns whether or not access to the application should be filtered. * - * @see #filterAppAccess(android.content.pm.PackageParser.Package, int, int) + * @see #filterAppAccess(AndroidPackage, int, int) */ public abstract boolean filterAppAccess( @NonNull String packageName, int callingUid, int userId); @@ -763,21 +761,29 @@ public abstract class PackageManagerInternal { throws IOException; /** Returns {@code true} if the specified component is enabled and matches the given flags. */ - public abstract boolean isEnabledAndMatches( - @NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId); + public abstract boolean isEnabledAndMatches(@NonNull ParsedMainComponent component, int flags, + int userId); /** Returns {@code true} if the given user requires extra badging for icons. */ public abstract boolean userNeedsBadging(int userId); /** * Perform the given action for each package. - * Note that packages lock will be held while performin the actions. + * Note that packages lock will be held while performing the actions. * * @param actionLocked action to be performed */ public abstract void forEachPackage(Consumer<AndroidPackage> actionLocked); /** + * Perform the given action for each {@link PackageSetting}. + * Note that packages lock will be held while performing the actions. + * + * @param actionLocked action to be performed + */ + public abstract void forEachPackageSetting(Consumer<PackageSetting> actionLocked); + + /** * Perform the given action for each installed package for a user. * Note that packages lock will be held while performin the actions. */ diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index c8894e79ac0c..f1f5005b23db 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -27,8 +27,10 @@ import android.content.Intent; import android.database.ContentObserver; import android.hardware.health.V1_0.HealthInfo; import android.hardware.health.V2_0.IHealth; -import android.hardware.health.V2_0.IHealthInfoCallback; import android.hardware.health.V2_0.Result; +import android.hardware.health.V2_1.BatteryCapacityLevel; +import android.hardware.health.V2_1.Constants; +import android.hardware.health.V2_1.IHealthInfoCallback; import android.hidl.manager.V1_0.IServiceManager; import android.hidl.manager.V1_0.IServiceNotification; import android.metrics.LogMaker; @@ -145,6 +147,7 @@ public final class BatteryService extends SystemService { private HealthInfo mHealthInfo; private final HealthInfo mLastHealthInfo = new HealthInfo(); + private android.hardware.health.V2_1.HealthInfo mHealthInfo2p1; private boolean mBatteryLevelCritical; private int mLastBatteryStatus; private int mLastBatteryHealth; @@ -359,6 +362,9 @@ public final class BatteryService extends SystemService { } private boolean shouldShutdownLocked() { + if (mHealthInfo2p1.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) { + return (mHealthInfo2p1.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL); + } if (mHealthInfo.batteryLevel > 0) { return false; } @@ -416,22 +422,23 @@ public final class BatteryService extends SystemService { } } - private void update(android.hardware.health.V2_0.HealthInfo info) { + private void update(android.hardware.health.V2_1.HealthInfo info) { traceBegin("HealthInfoUpdate"); Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryChargeCounter", - info.legacy.batteryChargeCounter); + info.legacy.legacy.batteryChargeCounter); Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent", - info.legacy.batteryCurrent); + info.legacy.legacy.batteryCurrent); synchronized (mLock) { if (!mUpdatesStopped) { - mHealthInfo = info.legacy; + mHealthInfo = info.legacy.legacy; + mHealthInfo2p1 = info; // Process the new values. processValuesLocked(false); mLock.notifyAll(); // for any waiters on new info } else { - copy(mLastHealthInfo, info.legacy); + copy(mLastHealthInfo, info.legacy.legacy); } } traceEnd(); @@ -485,7 +492,8 @@ public final class BatteryService extends SystemService { mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature, mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter, - mHealthInfo.batteryFullCharge); + mHealthInfo.batteryFullCharge, + mHealthInfo2p1.batteryChargeTimeToFullNowSeconds); } catch (RemoteException e) { // Should never happen. } @@ -1123,8 +1131,21 @@ public final class BatteryService extends SystemService { private final class HealthHalCallback extends IHealthInfoCallback.Stub implements HealthServiceWrapper.Callback { @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) { + android.hardware.health.V2_1.HealthInfo propsLatest = + new android.hardware.health.V2_1.HealthInfo(); + propsLatest.legacy = props; + + propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED; + propsLatest.batteryChargeTimeToFullNowSeconds = + Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED; + + BatteryService.this.update(propsLatest); + } + + @Override public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) { BatteryService.this.update(props); } + // on new service registered @Override public void onRegistration(IHealth oldService, IHealth newService, String instance) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f7eabac3b21f..e48ef5a528be 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1534,7 +1534,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { + public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser( + int userId, String callingPackageName) { // The basic principle is: if an app's traffic could possibly go over a // network, without the app doing anything multinetwork-specific, // (hence, by "default"), then include that network's capabilities in @@ -1556,7 +1557,10 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkAgentInfo nai = getDefaultNetwork(); NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai); if (nc != null) { - result.put(nai.network, nc); + result.put( + nai.network, + maybeSanitizeLocationInfoForCaller( + nc, Binder.getCallingUid(), callingPackageName)); } synchronized (mVpns) { @@ -1566,10 +1570,12 @@ public class ConnectivityService extends IConnectivityManager.Stub Network[] networks = vpn.getUnderlyingNetworks(); if (networks != null) { for (Network network : networks) { - nai = getNetworkAgentInfoForNetwork(network); - nc = getNetworkCapabilitiesInternal(nai); + nc = getNetworkCapabilitiesInternal(network); if (nc != null) { - result.put(network, nc); + result.put( + network, + maybeSanitizeLocationInfoForCaller( + nc, Binder.getCallingUid(), callingPackageName)); } } } @@ -1636,20 +1642,26 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private NetworkCapabilities getNetworkCapabilitiesInternal(Network network) { + return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network)); + } + private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) { if (nai == null) return null; synchronized (nai) { if (nai.networkCapabilities == null) return null; return networkCapabilitiesRestrictedForCallerPermissions( - nai.networkCapabilities, - Binder.getCallingPid(), Binder.getCallingUid()); + nai.networkCapabilities, Binder.getCallingPid(), Binder.getCallingUid()); } } @Override - public NetworkCapabilities getNetworkCapabilities(Network network) { + public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) { + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName); enforceAccessPermission(); - return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network)); + return maybeSanitizeLocationInfoForCaller( + getNetworkCapabilitiesInternal(network), + Binder.getCallingUid(), callingPackageName); } @VisibleForTesting @@ -1665,20 +1677,34 @@ public class ConnectivityService extends IConnectivityManager.Stub } newNc.setAdministratorUids(Collections.EMPTY_LIST); - maybeSanitizeLocationInfoForCaller(newNc, callerUid); - return newNc; } - private void maybeSanitizeLocationInfoForCaller( - NetworkCapabilities nc, int callerUid) { - // TODO(b/142072839): Conditionally reset the owner UID if the following - // conditions are not met: - // 1. The destination app is the network owner - // 2. The destination app has the ACCESS_COARSE_LOCATION permission granted - // if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted - // 3. The user's location toggle is on - nc.setOwnerUid(INVALID_UID); + @VisibleForTesting + @Nullable + NetworkCapabilities maybeSanitizeLocationInfoForCaller( + @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) { + if (nc == null) { + return null; + } + final NetworkCapabilities newNc = new NetworkCapabilities(nc); + if (callerUid != newNc.getOwnerUid()) { + newNc.setOwnerUid(INVALID_UID); + return newNc; + } + + Binder.withCleanCallingIdentity( + () -> { + if (!mLocationPermissionChecker.checkLocationPermission( + callerPkgName, null /* featureId */, callerUid, null /* message */)) { + // Caller does not have the requisite location permissions. Reset the + // owner's UID in the NetworkCapabilities. + newNc.setOwnerUid(INVALID_UID); + } + } + ); + + return newNc; } private LinkProperties linkPropertiesRestrictedForCallerPermissions( @@ -1753,7 +1779,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public boolean isActiveNetworkMetered() { enforceAccessPermission(); - final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork()); + final NetworkCapabilities caps = getNetworkCapabilitiesInternal(getActiveNetwork()); if (caps != null) { return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } else { @@ -5330,8 +5356,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } public String toString() { - return "uid/pid:" + mUid + "/" + mPid + " " + request + - (mPendingIntent == null ? "" : " to trigger " + mPendingIntent); + return "uid/pid:" + mUid + "/" + mPid + " " + request + + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent); } } @@ -6408,8 +6434,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } switch (notificationType) { case ConnectivityManager.CALLBACK_AVAILABLE: { - putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions( - networkAgent.networkCapabilities, nri.mPid, nri.mUid)); + final NetworkCapabilities nc = + networkCapabilitiesRestrictedForCallerPermissions( + networkAgent.networkCapabilities, nri.mPid, nri.mUid); + putParcelable( + bundle, + maybeSanitizeLocationInfoForCaller( + nc, nri.mUid, nri.request.getRequestorPackageName())); putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions( networkAgent.linkProperties, nri.mPid, nri.mUid)); // For this notification, arg1 contains the blocked status. @@ -6422,9 +6453,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } case ConnectivityManager.CALLBACK_CAP_CHANGED: { // networkAgent can't be null as it has been accessed a few lines above. - final NetworkCapabilities nc = networkCapabilitiesRestrictedForCallerPermissions( - networkAgent.networkCapabilities, nri.mPid, nri.mUid); - putParcelable(bundle, nc); + final NetworkCapabilities netCap = + networkCapabilitiesRestrictedForCallerPermissions( + networkAgent.networkCapabilities, nri.mPid, nri.mUid); + putParcelable( + bundle, + maybeSanitizeLocationInfoForCaller( + netCap, nri.mUid, nri.request.getRequestorPackageName())); break; } case ConnectivityManager.CALLBACK_IP_CHANGED: { diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java index 05820d25c423..7ec2a34604ca 100644 --- a/services/core/java/com/android/server/IntentResolver.java +++ b/services/core/java/com/android/server/IntentResolver.java @@ -16,6 +16,7 @@ package com.android.server; +import android.annotation.NonNull; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; @@ -44,29 +45,30 @@ import java.util.Set; /** * {@hide} */ -public abstract class IntentResolver<F extends IntentFilter, R extends Object> { +public abstract class IntentResolver<F, R extends Object> { final private static String TAG = "IntentResolver"; final private static boolean DEBUG = false; final private static boolean localLOGV = DEBUG || false; final private static boolean localVerificationLOGV = DEBUG || false; public void addFilter(F f) { + IntentFilter intentFilter = getIntentFilter(f); if (localLOGV) { Slog.v(TAG, "Adding filter: " + f); - f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); Slog.v(TAG, " Building Lookup Maps:"); } mFilters.add(f); - int numS = register_intent_filter(f, f.schemesIterator(), + int numS = register_intent_filter(f, intentFilter.schemesIterator(), mSchemeToFilter, " Scheme: "); int numT = register_mime_types(f, " Type: "); if (numS == 0 && numT == 0) { - register_intent_filter(f, f.actionsIterator(), + register_intent_filter(f, intentFilter.actionsIterator(), mActionToFilter, " Action: "); } if (numT != 0) { - register_intent_filter(f, f.actionsIterator(), + register_intent_filter(f, intentFilter.actionsIterator(), mTypedActionToFilter, " TypedAction: "); } } @@ -153,7 +155,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { if (cur == null) { break; } - if (filterEquals(cur, matching)) { + if (filterEquals(getIntentFilter(cur), matching)) { if (res == null) { res = new ArrayList<>(); } @@ -178,7 +180,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { } else { ArrayList<F> res = null; for (F cur : mFilters) { - if (filterEquals(cur, matching)) { + if (filterEquals(getIntentFilter(cur), matching)) { if (res == null) { res = new ArrayList<>(); } @@ -195,21 +197,22 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { } protected void removeFilterInternal(F f) { + IntentFilter intentFilter = getIntentFilter(f); if (localLOGV) { Slog.v(TAG, "Removing filter: " + f); - f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); Slog.v(TAG, " Cleaning Lookup Maps:"); } - int numS = unregister_intent_filter(f, f.schemesIterator(), + int numS = unregister_intent_filter(f, intentFilter.schemesIterator(), mSchemeToFilter, " Scheme: "); int numT = unregister_mime_types(f, " Type: "); if (numS == 0 && numT == 0) { - unregister_intent_filter(f, f.actionsIterator(), + unregister_intent_filter(f, intentFilter.actionsIterator(), mActionToFilter, " Action: "); } if (numT != 0) { - unregister_intent_filter(f, f.actionsIterator(), + unregister_intent_filter(f, intentFilter.actionsIterator(), mTypedActionToFilter, " TypedAction: "); } } @@ -272,7 +275,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { if (printer == null) { printer = new PrintWriterPrinter(out); } - filter.dump(printer, fprefix + " "); + getIntentFilter(filter).dump(printer, fprefix + " "); } } } @@ -527,7 +530,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { * @see android.content.IntentFilter#getAutoVerify() */ protected boolean isFilterVerified(F filter) { - return filter.isVerified(); + return getIntentFilter(filter).isVerified(); } /** @@ -591,7 +594,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { } private final int register_mime_types(F filter, String prefix) { - final Iterator<String> i = filter.typesIterator(); + final Iterator<String> i = getIntentFilter(filter).typesIterator(); if (i == null) { return 0; } @@ -622,7 +625,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { } private final int unregister_mime_types(F filter, String prefix) { - final Iterator<String> i = filter.typesIterator(); + final Iterator<String> i = getIntentFilter(filter).typesIterator(); if (i == null) { return 0; } @@ -762,12 +765,14 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { } // Are we verified ? - if (filter.getAutoVerify()) { + IntentFilter intentFilter = getIntentFilter(filter); + if (intentFilter.getAutoVerify()) { if (localVerificationLOGV || debug) { Slog.v(TAG, " Filter verified: " + isFilterVerified(filter)); - int authorities = filter.countDataAuthorities(); + int authorities = intentFilter.countDataAuthorities(); for (int z = 0; z < authorities; z++) { - Slog.v(TAG, " " + filter.getDataAuthority(z).getHost()); + Slog.v(TAG, " " + intentFilter.getDataAuthority(z) + .getHost()); } } } @@ -780,12 +785,12 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { continue; } - match = filter.match(action, resolvedType, scheme, data, categories, TAG); + match = intentFilter.match(action, resolvedType, scheme, data, categories, TAG); if (match >= 0) { if (debug) Slog.v(TAG, " Filter matched! match=0x" + Integer.toHexString(match) + " hasDefault=" - + filter.hasCategory(Intent.CATEGORY_DEFAULT)); - if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) { + + intentFilter.hasCategory(Intent.CATEGORY_DEFAULT)); + if (!defaultOnly || intentFilter.hasCategory(Intent.CATEGORY_DEFAULT)) { final R oneResult = newResult(filter, match, userId); if (debug) Slog.v(TAG, " Created result: " + oneResult); if (oneResult != null) { @@ -793,7 +798,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { if (debug) { dumpFilter(logPrintWriter, " ", filter); logPrintWriter.flush(); - filter.dump(logPrinter, " "); + intentFilter.dump(logPrinter, " "); } } } else { @@ -875,4 +880,11 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { * All of the actions that have been registered and specified a MIME type. */ private final ArrayMap<String, F[]> mTypedActionToFilter = new ArrayMap<String, F[]>(); + + /** + * Rather than refactoring the entire class, this allows the input {@link F} to be a type + * other than {@link IntentFilter}, transforming it whenever necessary. It is valid to use + * {@link IntentFilter} directly as {@link F} and just return {@param input}. + */ + protected abstract IntentFilter getIntentFilter(@NonNull F input); } diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java index 6fb7b267c285..93859b35fbe0 100644 --- a/services/core/java/com/android/server/PinnerService.java +++ b/services/core/java/com/android/server/PinnerService.java @@ -103,7 +103,7 @@ public final class PinnerService extends SystemService { private static boolean PROP_PIN_CAMERA = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, "pin_camera", - SystemProperties.getBoolean("pinner.pin_camera", true)); + SystemProperties.getBoolean("pinner.pin_camera", false)); // Pin using pinlist.meta when pinning apps. private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean( "pinner.use_pinlist", true); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 3b0a1a3ead0a..d86b2230ee7a 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -2120,8 +2120,6 @@ class StorageManagerService extends IStorageManager.Stub private void unmount(VolumeInfo vol) { try { - mVold.unmount(vol.id); - mStorageSessionController.onVolumeUnmount(vol); try { if (vol.type == VolumeInfo.TYPE_PRIVATE) { mInstaller.onPrivateVolumeRemoved(vol.getFsUuid()); @@ -2129,6 +2127,8 @@ class StorageManagerService extends IStorageManager.Stub } catch (Installer.InstallerException e) { Slog.e(TAG, "Failed unmount mirror data", e); } + mVold.unmount(vol.id); + mStorageSessionController.onVolumeUnmount(vol); } catch (Exception e) { Slog.wtf(TAG, e); } @@ -4346,6 +4346,42 @@ class StorageManagerService extends IStorageManager.Stub mPolicies.add(policy); } + /** + * Check if fuse is running in target user, if it's running then setup its obb directories. + * TODO: System server should store a list of active pids that obb is not mounted and use it. + */ + @Override + public void prepareObbDirs(int userId, Set<String> packageList, String processName) { + String fuseRunningUsersList = SystemProperties.get("vold.fuse_running_users", ""); + String[] fuseRunningUsers = fuseRunningUsersList.split(","); + boolean fuseReady = false; + String targetUserId = String.valueOf(userId); + for (String user : fuseRunningUsers) { + if (targetUserId.equals(user)) { + fuseReady = true; + } + } + if (fuseReady) { + try { + final IVold vold = IVold.Stub.asInterface( + ServiceManager.getServiceOrThrow("vold")); + for (String pkg : packageList) { + final String obbDir = + String.format("/storage/emulated/%d/Android/obb", userId); + final String packageObbDir = String.format("%s/%s/", obbDir, pkg); + + // Create package obb dir if it doesn't exist. + File file = new File(packageObbDir); + if (!file.exists()) { + vold.setupAppDir(packageObbDir, mPmInternal.getPackage(pkg).getUid()); + } + } + } catch (ServiceManager.ServiceNotFoundException | RemoteException e) { + Slog.e(TAG, "Unable to create obb directories for " + processName, e); + } + } + } + @Override public void onExternalStoragePolicyChanged(int uid, String packageName) { final int mountMode = getExternalStorageMountMode(uid, packageName); diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index a1ccd8459c69..8900eee6f50f 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -100,7 +100,7 @@ public class Watchdog extends Thread { "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service "media.swcodec", // /apex/com.android.media.swcodec/bin/mediaswcodec "com.android.bluetooth", // Bluetooth service - "/system/bin/statsd", // Stats daemon + "/apex/com.android.os.statsd/bin/statsd", // Stats daemon }; public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList( diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index 10994133e265..f16e3ce11622 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -29,6 +29,7 @@ import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; import android.debug.AdbProtoEnums; +import android.debug.AdbTransportType; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.net.Uri; @@ -722,13 +723,21 @@ public class AdbDebuggingManager { } /** - * When {@code enabled} is {@code true}, this allows ADB debugging and starts the ADB hanler - * thread. When {@code enabled} is {@code false}, this disallows ADB debugging and shuts - * down the handler thread. + * When {@code enabled} is {@code true}, this allows ADB debugging and starts the ADB handler + * thread. When {@code enabled} is {@code false}, this disallows ADB debugging for the given + * @{code transportType}. See {@link IAdbTransport} for all available transport types. + * If all transport types are disabled, the ADB handler thread will shut down. */ - public void setAdbEnabled(boolean enabled) { - mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MESSAGE_ADB_ENABLED - : AdbDebuggingHandler.MESSAGE_ADB_DISABLED); + public void setAdbEnabled(boolean enabled, byte transportType) { + if (transportType == AdbTransportType.USB) { + mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MESSAGE_ADB_ENABLED + : AdbDebuggingHandler.MESSAGE_ADB_DISABLED); + } else if (transportType == AdbTransportType.WIFI) { + // TODO(joshuaduong): Not implemented + } else { + throw new IllegalArgumentException( + "setAdbEnabled called with unimplemented transport type=" + transportType); + } } /** diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java index c125b1baf860..f2a8615dca88 100644 --- a/services/core/java/com/android/server/adb/AdbService.java +++ b/services/core/java/com/android/server/adb/AdbService.java @@ -15,19 +15,23 @@ */ package com.android.server.adb; +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.annotation.NonNull; +import android.annotation.UserIdInt; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; import android.database.ContentObserver; import android.debug.AdbManagerInternal; +import android.debug.AdbTransportType; import android.debug.IAdbManager; import android.debug.IAdbTransport; +import android.debug.PairDevice; import android.hardware.usb.UsbManager; +import android.net.Uri; import android.os.Binder; -import android.os.Handler; import android.os.IBinder; -import android.os.Looper; -import android.os.Message; import android.os.RemoteException; import android.os.SystemProperties; import android.provider.Settings; @@ -38,7 +42,6 @@ import android.util.ArraySet; import android.util.Slog; import android.util.proto.ProtoOutputStream; - import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.dump.DualDumpOutputStream; @@ -50,6 +53,7 @@ import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collections; +import java.util.Map; /** * The Android Debug Bridge (ADB) service. This controls the availability of ADB and authorization @@ -77,7 +81,8 @@ public class AdbService extends IAdbManager.Stub { if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mAdbService.systemReady(); } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { - mAdbService.bootCompleted(); + FgThread.getHandler().sendMessage(obtainMessage( + AdbService::bootCompleted, mAdbService)); } } } @@ -94,8 +99,14 @@ public class AdbService extends IAdbManager.Stub { } @Override - public boolean isAdbEnabled() { - return mAdbEnabled; + public boolean isAdbEnabled(byte transportType) { + if (transportType == AdbTransportType.USB) { + return mIsAdbUsbEnabled; + } else if (transportType == AdbTransportType.WIFI) { + return mIsAdbWifiEnabled; + } + throw new IllegalArgumentException( + "isAdbEnabled called with unimplemented transport type=" + transportType); } @Override @@ -109,77 +120,60 @@ public class AdbService extends IAdbManager.Stub { } } - private final class AdbHandler extends Handler { - AdbHandler(Looper looper) { - super(looper); - try { - /* - * Use the normal bootmode persistent prop to maintain state of adb across - * all boot modes. - */ - mAdbEnabled = containsFunction( - SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""), - UsbManager.USB_FUNCTION_ADB); - - // register observer to listen for settings changes - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), - false, new AdbSettingsObserver()); - } catch (Exception e) { - Slog.e(TAG, "Error initializing AdbHandler", e); - } - } - - private boolean containsFunction(String functions, String function) { - int index = functions.indexOf(function); - if (index < 0) return false; - if (index > 0 && functions.charAt(index - 1) != ',') return false; - int charAfter = index + function.length(); - if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false; - return true; - } - - public void sendMessage(int what, boolean arg) { - removeMessages(what); - Message m = Message.obtain(this, what); - m.arg1 = (arg ? 1 : 0); - sendMessage(m); + private void initAdbState() { + try { + /* + * Use the normal bootmode persistent prop to maintain state of adb across + * all boot modes. + */ + mIsAdbUsbEnabled = containsFunction( + SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""), + UsbManager.USB_FUNCTION_ADB); + // TODO(joshuaduong): Read the adb wifi state from a persistent system + // property (persist.sys.adb.wifi). + mIsAdbWifiEnabled = false; + + // register observer to listen for settings changes + mContentResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), + false, new AdbSettingsObserver()); + } catch (Exception e) { + Slog.e(TAG, "Error in initAdbState", e); } + } - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_ENABLE_ADB: - setAdbEnabled(msg.arg1 == 1); - break; - case MSG_BOOT_COMPLETED: - if (mDebuggingManager != null) { - mDebuggingManager.setAdbEnabled(mAdbEnabled); - } - break; - } - } + private static boolean containsFunction(String functions, String function) { + int index = functions.indexOf(function); + if (index < 0) return false; + if (index > 0 && functions.charAt(index - 1) != ',') return false; + int charAfter = index + function.length(); + if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false; + return true; } private class AdbSettingsObserver extends ContentObserver { + private final Uri mAdbUsbUri = Settings.Global.getUriFor(Settings.Global.ADB_ENABLED); + AdbSettingsObserver() { super(null); } @Override - public void onChange(boolean selfChange) { - boolean enable = (Settings.Global.getInt(mContentResolver, - Settings.Global.ADB_ENABLED, 0) > 0); - mHandler.sendMessage(MSG_ENABLE_ADB, enable); + public void onChange(boolean selfChange, @NonNull Uri uri, @UserIdInt int userId) { + if (mAdbUsbUri.equals(uri)) { + boolean shouldEnable = (Settings.Global.getInt(mContentResolver, + Settings.Global.ADB_ENABLED, 0) > 0); + FgThread.getHandler().sendMessage(obtainMessage( + AdbService::setAdbEnabled, AdbService.this, shouldEnable, + AdbTransportType.USB)); + } + // TODO(joshuaduong): Add condition for WIFI transport } } private static final String TAG = "AdbService"; private static final boolean DEBUG = false; - private static final int MSG_ENABLE_ADB = 1; - private static final int MSG_BOOT_COMPLETED = 2; - /** * The persistent property which stores whether adb is enabled or not. * May also contain vendor-specific default functions for testing purposes. @@ -188,10 +182,10 @@ public class AdbService extends IAdbManager.Stub { private final Context mContext; private final ContentResolver mContentResolver; - private final AdbService.AdbHandler mHandler; private final ArrayMap<IBinder, IAdbTransport> mTransports = new ArrayMap<>(); - private boolean mAdbEnabled; + private boolean mIsAdbUsbEnabled; + private boolean mIsAdbWifiEnabled; private AdbDebuggingManager mDebuggingManager; private AdbService(Context context) { @@ -204,8 +198,7 @@ public class AdbService extends IAdbManager.Stub { mDebuggingManager = new AdbDebuggingManager(context); } - mHandler = new AdbHandler(FgThread.get().getLooper()); - + initAdbState(); LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl()); } @@ -219,7 +212,7 @@ public class AdbService extends IAdbManager.Stub { // make sure the ADB_ENABLED setting value matches the current state try { Settings.Global.putInt(mContentResolver, - Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0); + Settings.Global.ADB_ENABLED, mIsAdbUsbEnabled ? 1 : 0); } catch (SecurityException e) { // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed. Slog.d(TAG, "ADB_ENABLED is restricted."); @@ -231,7 +224,10 @@ public class AdbService extends IAdbManager.Stub { */ public void bootCompleted() { if (DEBUG) Slog.d(TAG, "boot completed"); - mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); + if (mDebuggingManager != null) { + mDebuggingManager.setAdbEnabled(mIsAdbUsbEnabled, AdbTransportType.USB); + mDebuggingManager.setAdbEnabled(mIsAdbWifiEnabled, AdbTransportType.WIFI); + } } @Override @@ -285,24 +281,82 @@ public class AdbService extends IAdbManager.Stub { PackageManager.FEATURE_CAMERA_ANY); } - private void setAdbEnabled(boolean enable) { - if (DEBUG) Slog.d(TAG, "setAdbEnabled(" + enable + "), mAdbEnabled=" + mAdbEnabled); + @Override + public void allowWirelessDebugging(boolean alwaysAllow, String bssid) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); + // TODO(joshuaduong): NOT IMPLEMENTED + } + + @Override + public void denyWirelessDebugging() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); + // TODO(joshuaduong): NOT IMPLEMENTED + } + + @Override + public Map<String, PairDevice> getPairedDevices() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); + // TODO(joshuaduong): NOT IMPLEMENTED + return null; + } + + @Override + public void unpairDevice(String fingerprint) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); + // TODO(joshuaduong): NOT IMPLEMENTED + } + + @Override + public void enablePairingByPairingCode() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); + // TODO(joshuaduong): NOT IMPLEMENTED + } - if (enable == mAdbEnabled) { + @Override + public void enablePairingByQrCode(String serviceName, String password) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); + // TODO(joshuaduong): NOT IMPLEMENTED + } + + @Override + public void disablePairing() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); + // TODO(joshuaduong): NOT IMPLEMENTED + } + + @Override + public int getAdbWirelessPort() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); + // TODO(joshuaduong): NOT IMPLEMENTED + return 0; + } + + private void setAdbEnabled(boolean enable, byte transportType) { + if (DEBUG) { + Slog.d(TAG, "setAdbEnabled(" + enable + "), mIsAdbUsbEnabled=" + mIsAdbUsbEnabled + + ", mIsAdbWifiEnabled=" + mIsAdbWifiEnabled + ", transportType=" + + transportType); + } + + if (transportType == AdbTransportType.USB && enable != mIsAdbUsbEnabled) { + mIsAdbUsbEnabled = enable; + } else if (transportType == AdbTransportType.WIFI && enable != mIsAdbWifiEnabled) { + mIsAdbWifiEnabled = enable; + } else { + // No change return; } - mAdbEnabled = enable; for (IAdbTransport transport : mTransports.values()) { try { - transport.onAdbEnabled(enable); + transport.onAdbEnabled(enable, transportType); } catch (RemoteException e) { Slog.w(TAG, "Unable to send onAdbEnabled to transport " + transport.toString()); } } if (mDebuggingManager != null) { - mDebuggingManager.setAdbEnabled(enable); + mDebuggingManager.setAdbEnabled(enable, transportType); } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 50f43b5c1bae..2bcb28de5d9c 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -62,7 +62,6 @@ import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.res.Resources; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -91,7 +90,6 @@ import android.util.SparseArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.webkit.WebViewZygote; -import android.widget.Toast; import com.android.internal.R; import com.android.internal.app.procstats.ServiceState; @@ -4687,20 +4685,35 @@ public final class ActiveServices { } // TODO: remove this toast after feature development is done - private void showWhileInUsePermissionInFgsBlockedToastLocked(String callingPackage) { - final Resources res = mAm.mContext.getResources(); - final String toastMsg = res.getString( - R.string.allow_while_in_use_permission_in_fgs, callingPackage); - mAm.mUiHandler.post(() -> { - Toast.makeText(mAm.mContext, toastMsg, Toast.LENGTH_LONG).show(); - }); + private void showWhileInUsePermissionInFgsBlockedNotificationLocked(String callingPackage, + String detailInfo) { + final Context context = mAm.mContext; + final String title = "Foreground Service While-in-use Permission Restricted"; + final String content = "App affected:" + callingPackage + ", please file a bug report"; + Notification.Builder n = + new Notification.Builder(context, + SystemNotificationChannels.ALERTS) + .setSmallIcon(R.drawable.stat_sys_vitals) + .setWhen(0) + .setColor(context.getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setTicker(title) + .setContentTitle(title) + .setContentText(content) + .setStyle(new Notification.BigTextStyle().bigText(detailInfo)); + final NotificationManager notificationManager = + (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + notificationManager.notifyAsUser(null, + SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION, + n.build(), UserHandle.ALL); } // TODO: remove this toast after feature development is done // show a toast message to ask user to file a bugreport so we know how many apps are impacted by // the new background started foreground service while-in-use permission restriction. - void showWhileInUseDebugToastLocked(int uid, int op, int mode) { - StringBuilder sb = new StringBuilder(); + void showWhileInUseDebugNotificationLocked(int uid, int op, int mode) { + StringBuilder packageNameBuilder = new StringBuilder(); + StringBuilder detailInfoBuilder = new StringBuilder(); for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i); if (pr.uid != uid) { @@ -4713,17 +4726,22 @@ public final class ActiveServices { } if (!r.mAllowWhileInUsePermissionInFgs && r.mInfoDenyWhileInUsePermissionInFgs != null) { - Slog.wtf(TAG, r.mInfoDenyWhileInUsePermissionInFgs - + " affected while-use-permission:" + AppOpsManager.opToPublicName(op)); - sb.append(r.mRecentCallingPackage + " "); + final String msg = r.mInfoDenyWhileInUsePermissionInFgs + + " affected while-in-use permission:" + + AppOpsManager.opToPublicName(op); + Slog.wtf(TAG, msg); + packageNameBuilder.append(r.mRecentCallingPackage + " "); + detailInfoBuilder.append(msg); + detailInfoBuilder.append("\n"); } } } - final String callingPackageStr = sb.toString(); + final String callingPackageStr = packageNameBuilder.toString(); if (mAm.mConstants.mFlagForegroundServiceStartsLoggingEnabled && !callingPackageStr.isEmpty()) { - showWhileInUsePermissionInFgsBlockedToastLocked(callingPackageStr); + showWhileInUsePermissionInFgsBlockedNotificationLocked(callingPackageStr, + detailInfoBuilder.toString()); } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9082807f6bbc..0d8eff5c11cc 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1045,6 +1045,11 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + protected IntentFilter getIntentFilter(@NonNull BroadcastFilter input) { + return input; + } + + @Override protected BroadcastFilter[] newArray(int size) { return new BroadcastFilter[size]; } @@ -14605,6 +14610,11 @@ public class ActivityManagerService extends IActivityManager.Stub if (index < 0) { ProcessList.remove(app.pid); } + + // Remove provider publish timeout because we will start a new timeout when the + // restarted process is attaching (if the process contains launching providers). + mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, app); + mProcessList.addProcessNameLocked(app); app.pendingStart = false; mProcessList.startProcessLocked(app, @@ -19333,7 +19343,8 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void showWhileInUseDebugToast(int uid, int op, int mode) { synchronized (ActivityManagerService.this) { - ActivityManagerService.this.mServices.showWhileInUseDebugToastLocked(uid, op, mode); + ActivityManagerService.this.mServices.showWhileInUseDebugNotificationLocked( + uid, op, mode); } } } diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index ed6ace3335f5..119394fdadb8 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -1135,7 +1135,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub @Override public void setBatteryState(final int status, final int health, final int plugType, final int level, final int temp, final int volt, final int chargeUAh, - final int chargeFullUAh) { + final int chargeFullUAh, final long chargeTimeToFullSeconds) { enforceCallingPermission(); // BatteryService calls us here and we may update external state. It would be wrong @@ -1147,7 +1147,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub // The battery state has not changed, so we don't need to sync external // stats immediately. mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt, - chargeUAh, chargeFullUAh); + chargeUAh, chargeFullUAh, chargeTimeToFullSeconds); return; } } @@ -1160,7 +1160,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub mWorker.scheduleRunnable(() -> { synchronized (mStats) { mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt, - chargeUAh, chargeFullUAh); + chargeUAh, chargeFullUAh, chargeTimeToFullSeconds); } }); }); diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java index a03f0bb4e399..48ceba976502 100644 --- a/services/core/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.annotation.NonNull; import android.app.ActivityThread; import android.content.Context; import android.database.ContentObserver; @@ -32,6 +33,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Helper class for watching a set of core settings which the framework @@ -42,16 +44,20 @@ import java.util.Map; final class CoreSettingsObserver extends ContentObserver { private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName(); - private static class DeviceConfigEntry { + private static class DeviceConfigEntry<T> { String namespace; String flag; String coreSettingKey; - Class<?> type; - DeviceConfigEntry(String namespace, String flag, String coreSettingKey, Class<?> type) { + Class<T> type; + T defaultValue; + + DeviceConfigEntry(String namespace, String flag, String coreSettingKey, Class<T> type, + @NonNull T defaultValue) { this.namespace = namespace; this.flag = flag; this.coreSettingKey = coreSettingKey; this.type = type; + this.defaultValue = Objects.requireNonNull(defaultValue); } } @@ -105,24 +111,34 @@ final class CoreSettingsObserver extends ContentObserver { sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, String.class); // add other global settings here... - sDeviceConfigEntries.add(new DeviceConfigEntry( - DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_CONTROL, - WidgetFlags.KEY_ENABLE_CURSOR_CONTROL, boolean.class)); - sDeviceConfigEntries.add(new DeviceConfigEntry( + sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>( + DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE, + WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, boolean.class, + WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT)); + sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>( + DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES, + WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES, boolean.class, + WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT)); + sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>( DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT, - WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, int.class)); - sDeviceConfigEntries.add(new DeviceConfigEntry( + WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, int.class, + WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT)); + sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>( DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_OPACITY, - WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, int.class)); - sDeviceConfigEntries.add(new DeviceConfigEntry( + WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, int.class, + WidgetFlags.INSERTION_HANDLE_OPACITY_DEFAULT)); + sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>( DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_NEW_MAGNIFIER, - WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, boolean.class)); - sDeviceConfigEntries.add(new DeviceConfigEntry( + WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, boolean.class, + WidgetFlags.ENABLE_NEW_MAGNIFIER_DEFAULT)); + sDeviceConfigEntries.add(new DeviceConfigEntry<Float>( DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ZOOM_FACTOR, - WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, float.class)); - sDeviceConfigEntries.add(new DeviceConfigEntry( + WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, float.class, + WidgetFlags.MAGNIFIER_ZOOM_FACTOR_DEFAULT)); + sDeviceConfigEntries.add(new DeviceConfigEntry<Float>( DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ASPECT_RATIO, - WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class)); + WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class, + WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT)); // add other device configs here... } @@ -216,23 +232,29 @@ final class CoreSettingsObserver extends ContentObserver { } } + @SuppressWarnings("unchecked") private void populateSettingsFromDeviceConfig() { - for (DeviceConfigEntry entry : sDeviceConfigEntries) { + for (DeviceConfigEntry<?> entry : sDeviceConfigEntries) { if (entry.type == String.class) { + String defaultValue = ((DeviceConfigEntry<String>) entry).defaultValue; mCoreSettings.putString(entry.coreSettingKey, - DeviceConfig.getString(entry.namespace, entry.flag, "")); + DeviceConfig.getString(entry.namespace, entry.flag, defaultValue)); } else if (entry.type == int.class) { + int defaultValue = ((DeviceConfigEntry<Integer>) entry).defaultValue; mCoreSettings.putInt(entry.coreSettingKey, - DeviceConfig.getInt(entry.namespace, entry.flag, 0)); + DeviceConfig.getInt(entry.namespace, entry.flag, defaultValue)); } else if (entry.type == float.class) { + float defaultValue = ((DeviceConfigEntry<Float>) entry).defaultValue; mCoreSettings.putFloat(entry.coreSettingKey, - DeviceConfig.getFloat(entry.namespace, entry.flag, 0)); + DeviceConfig.getFloat(entry.namespace, entry.flag, defaultValue)); } else if (entry.type == long.class) { + long defaultValue = ((DeviceConfigEntry<Long>) entry).defaultValue; mCoreSettings.putLong(entry.coreSettingKey, - DeviceConfig.getLong(entry.namespace, entry.flag, 0)); + DeviceConfig.getLong(entry.namespace, entry.flag, defaultValue)); } else if (entry.type == boolean.class) { + boolean defaultValue = ((DeviceConfigEntry<Boolean>) entry).defaultValue; mCoreSettings.putInt(entry.coreSettingKey, - DeviceConfig.getBoolean(entry.namespace, entry.flag, false) ? 1 : 0); + DeviceConfig.getBoolean(entry.namespace, entry.flag, defaultValue) ? 1 : 0); } } } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index ffa7d9202371..22559c426348 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -80,11 +80,13 @@ import android.os.Bundle; import android.os.DropBoxManager; import android.os.Handler; import android.os.IBinder; +import android.os.IVold; import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; @@ -142,10 +144,14 @@ import java.util.Map; public final class ProcessList { static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM; - // A device config to control the minimum target SDK to enable app data isolation + // A system property to control if app data isolation is enabled. static final String ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY = "persist.zygote.app_data_isolation"; + // A system property to control if obb app data isolation is enabled in vold. + static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY = + "persist.sys.vold_app_data_isolation_enabled"; + // A device config to control the minimum target SDK to enable app data isolation static final String ANDROID_APP_DATA_ISOLATION_MIN_SDK = "android_app_data_isolation_min_sdk"; @@ -339,6 +345,14 @@ public final class ProcessList { @EnabledAfter(targetSdkVersion = VersionCodes.Q) private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id. + /** + * Apps have no access to the private data directories of any other app, even if the other + * app has made them world-readable. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = VersionCodes.Q) + private static final long APP_DATA_DIRECTORY_ISOLATION = 143937733; // See b/143937733 + ActivityManagerService mService = null; // To kill process groups asynchronously @@ -379,6 +393,8 @@ public final class ProcessList { private boolean mAppDataIsolationEnabled = false; + private boolean mVoldAppDataIsolationEnabled = false; + private ArrayList<String> mAppDataIsolationWhitelistedApps; /** @@ -691,6 +707,8 @@ public final class ProcessList { // want some apps enabled while some apps disabled mAppDataIsolationEnabled = SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true); + mVoldAppDataIsolationEnabled = SystemProperties.getBoolean( + ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false); mAppDataIsolationWhitelistedApps = new ArrayList<>( SystemConfig.getInstance().getAppDataIsolationWhitelistedApps()); @@ -2060,7 +2078,14 @@ public final class ProcessList { } final int minTargetSdk = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, ANDROID_APP_DATA_ISOLATION_MIN_SDK, Build.VERSION_CODES.R); - return app.info.targetSdkVersion >= minTargetSdk; + if (app.info.targetSdkVersion < minTargetSdk) { + return false; + } + + // TODO(b/147266020): Remove non-standard gating above & switch to isChangeEnabled. + mPlatformCompat.reportChange(APP_DATA_DIRECTORY_ISOLATION, app.info); + + return true; } private Map<String, Pair<String, Long>> getPackageAppDataInfoMap(PackageManagerInternal pmInt, @@ -2113,6 +2138,13 @@ public final class ProcessList { app.info.packageName, app.userId); pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0 ? new String[]{app.info.packageName} : sharedPackages, uid); + + if (mVoldAppDataIsolationEnabled) { + StorageManagerInternal storageManagerInternal = LocalServices.getService( + StorageManagerInternal.class); + storageManagerInternal.prepareObbDirs(UserHandle.getUserId(uid), + pkgDataInfoMap.keySet(), app.processName); + } } else { pkgDataInfoMap = null; } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 40acfe1a57e3..7462f7fb8014 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -98,8 +98,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PermissionInfo; import android.content.pm.UserInfo; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils.ParsedFeature; +import android.content.pm.parsing.component.ParsedFeature; import android.database.ContentObserver; import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION; import android.net.Uri; @@ -156,6 +155,7 @@ import com.android.server.LocalServices; import com.android.server.LockGuard; import com.android.server.SystemServerInitThreadPool; import com.android.server.pm.PackageList; +import com.android.server.pm.parsing.pkg.AndroidPackage; import libcore.util.EmptyArray; diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 3138639c4a2b..e484ca0a2487 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -690,13 +690,14 @@ public class Vpn { // Prefer VPN profiles, if any exist. VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage, keyStore); if (profile != null) { - startVpnProfilePrivileged(profile, alwaysOnPackage); + startVpnProfilePrivileged(profile, alwaysOnPackage, + null /* keyStore for private key retrieval - unneeded */); // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was // correctly parsed, and the VPN has started running in a different thread. The only // other possibility is that the above call threw an exception, which will be // caught below, and returns false (clearing the always-on VPN). Once started, the - // Platform VPN cannot permanantly fail, and is resiliant to temporary failures. It + // Platform VPN cannot permanently fail, and is resilient to temporary failures. It // will continue retrying until shut down by the user, or always-on is toggled off. return true; } @@ -818,6 +819,7 @@ public class Vpn { } /** Prepare the VPN for the given package. Does not perform permission checks. */ + @GuardedBy("this") private void prepareInternal(String newPackage) { long token = Binder.clearCallingIdentity(); try { @@ -1943,6 +1945,27 @@ public class Vpn { // Prepare arguments for racoon. String[] racoon = null; switch (profile.type) { + case VpnProfile.TYPE_IKEV2_IPSEC_RSA: + // Secret key is still just the alias (not the actual private key). The private key + // is retrieved from the KeyStore during conversion of the VpnProfile to an + // Ikev2VpnProfile. + profile.ipsecSecret = Ikev2VpnProfile.PREFIX_KEYSTORE_ALIAS + privateKey; + profile.ipsecUserCert = userCert; + // Fallthrough + case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: + profile.ipsecCaCert = caCert; + + // Start VPN profile + startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore); + return; + case VpnProfile.TYPE_IKEV2_IPSEC_PSK: + // Ikev2VpnProfiles expect a base64-encoded preshared key. + profile.ipsecSecret = + Ikev2VpnProfile.encodeForIpsecSecret(profile.ipsecSecret.getBytes()); + + // Start VPN profile + startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore); + return; case VpnProfile.TYPE_L2TP_IPSEC_PSK: racoon = new String[] { iface, profile.server, "udppsk", profile.ipsecIdentifier, @@ -2949,24 +2972,35 @@ public class Vpn { throw new IllegalArgumentException("No profile found for " + packageName); } - startVpnProfilePrivileged(profile, packageName); + startVpnProfilePrivileged(profile, packageName, + null /* keyStore for private key retrieval - unneeded */); }); } - private void startVpnProfilePrivileged( - @NonNull VpnProfile profile, @NonNull String packageName) { - // Ensure that no other previous instance is running. - if (mVpnRunner != null) { - mVpnRunner.exit(); - mVpnRunner = null; - } + private synchronized void startVpnProfilePrivileged( + @NonNull VpnProfile profile, @NonNull String packageName, @Nullable KeyStore keyStore) { + // Make sure VPN is prepared. This method can be called by user apps via startVpnProfile(), + // by the Setting app via startLegacyVpn(), or by ConnectivityService via + // startAlwaysOnVpn(), so this is the common place to prepare the VPN. This also has the + // nice property of ensuring there are no other VpnRunner instances running. + prepareInternal(packageName); updateState(DetailedState.CONNECTING, "startPlatformVpn"); try { // Build basic config mConfig = new VpnConfig(); - mConfig.user = packageName; - mConfig.isMetered = profile.isMetered; + if (VpnConfig.LEGACY_VPN.equals(packageName)) { + mConfig.legacy = true; + mConfig.session = profile.name; + mConfig.user = profile.key; + + // TODO: Add support for configuring meteredness via Settings. Until then, use a + // safe default. + mConfig.isMetered = true; + } else { + mConfig.user = packageName; + mConfig.isMetered = profile.isMetered; + } mConfig.startTime = SystemClock.elapsedRealtime(); mConfig.proxyInfo = profile.proxy; @@ -2974,7 +3008,8 @@ public class Vpn { case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: case VpnProfile.TYPE_IKEV2_IPSEC_PSK: case VpnProfile.TYPE_IKEV2_IPSEC_RSA: - mVpnRunner = new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile)); + mVpnRunner = + new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile, keyStore)); mVpnRunner.start(); break; default: diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java index c2af29ca500b..1139d287be43 100644 --- a/services/core/java/com/android/server/firewall/IntentFirewall.java +++ b/services/core/java/com/android/server/firewall/IntentFirewall.java @@ -16,6 +16,7 @@ package com.android.server.firewall; +import android.annotation.NonNull; import android.app.AppGlobals; import android.content.ComponentName; import android.content.Intent; @@ -521,6 +522,11 @@ public class IntentFirewall { return; } + @Override + protected IntentFilter getIntentFilter(@NonNull FirewallIntentFilter input) { + return input; + } + public void queryByComponent(ComponentName componentName, List<Rule> candidateRules) { Rule[] rules = mRulesByComponent.get(componentName); if (rules != null) { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index 9f76e1ed113d..eac2d24c3dab 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -18,12 +18,11 @@ package com.android.server.inputmethod; import android.annotation.NonNull; import android.annotation.UserIdInt; -import android.content.ComponentName; -import android.view.autofill.AutofillId; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputMethodInfo; import com.android.internal.view.IInlineSuggestionsRequestCallback; +import com.android.internal.view.InlineSuggestionsRequestInfo; import com.android.server.LocalServices; import java.util.Collections; @@ -74,13 +73,11 @@ public abstract class InputMethodManagerInternal { * Called by the Autofill Frameworks to request an {@link InlineSuggestionsRequest} from * the input method. * - * @param componentName {@link ComponentName} of current app/activity. - * @param autofillId {@link AutofillId} of currently focused field. + * @param requestInfo information needed to create an {@link InlineSuggestionsRequest}. * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object. */ public abstract void onCreateInlineSuggestionsRequest(@UserIdInt int userId, - ComponentName componentName, AutofillId autofillId, - IInlineSuggestionsRequestCallback cb); + InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb); /** * Force switch to the enabled input method by {@code imeId} for current user. If the input @@ -124,7 +121,7 @@ public abstract class InputMethodManagerInternal { @Override public void onCreateInlineSuggestionsRequest(int userId, - ComponentName componentName, AutofillId autofillId, + InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) { } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 47622f38f3f2..87262a844b18 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -109,7 +109,6 @@ import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; -import android.view.autofill.AutofillId; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputBinding; @@ -150,6 +149,7 @@ import com.android.internal.view.IInputMethodClient; import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.IInputSessionCallback; +import com.android.internal.view.InlineSuggestionsRequestInfo; import com.android.internal.view.InputBindResult; import com.android.server.EventLogTags; import com.android.server.LocalServices; @@ -1388,6 +1388,44 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + private static final class UserSwitchHandlerTask implements Runnable { + final InputMethodManagerService mService; + + @UserIdInt + final int mToUserId; + + @Nullable + IInputMethodClient mClientToBeReset; + + UserSwitchHandlerTask(InputMethodManagerService service, @UserIdInt int toUserId, + @Nullable IInputMethodClient clientToBeReset) { + mService = service; + mToUserId = toUserId; + mClientToBeReset = clientToBeReset; + } + + @Override + public void run() { + synchronized (mService.mMethodMap) { + if (mService.mUserSwitchHandlerTask != this) { + // This task was already canceled before it is handled here. So do nothing. + return; + } + mService.switchUserOnHandlerLocked(mService.mUserSwitchHandlerTask.mToUserId, + mClientToBeReset); + mService.mUserSwitchHandlerTask = null; + } + } + } + + /** + * When non-{@code null}, this represents pending user-switch task, which is to be executed as + * a handler callback. This needs to be set and unset only within the lock. + */ + @Nullable + @GuardedBy("mMethodMap") + private UserSwitchHandlerTask mUserSwitchHandlerTask; + public static final class Lifecycle extends SystemService { private InputMethodManagerService mService; @@ -1406,8 +1444,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void onSwitchUser(@UserIdInt int userHandle) { // Called on ActivityManager thread. - // TODO: Dispatch this to a worker thread as needed. - mService.onSwitchUser(userHandle); + synchronized (mService.mMethodMap) { + mService.scheduleSwitchUserTaskLocked(userHandle, null /* clientToBeReset */); + } } @Override @@ -1447,10 +1486,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - void onSwitchUser(@UserIdInt int userId) { - synchronized (mMethodMap) { - switchUserLocked(userId); + @GuardedBy("mMethodMap") + void scheduleSwitchUserTaskLocked(@UserIdInt int userId, + @Nullable IInputMethodClient clientToBeReset) { + if (mUserSwitchHandlerTask != null) { + if (mUserSwitchHandlerTask.mToUserId == userId) { + mUserSwitchHandlerTask.mClientToBeReset = clientToBeReset; + return; + } + mHandler.removeCallbacks(mUserSwitchHandlerTask); } + final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId, + clientToBeReset); + mUserSwitchHandlerTask = task; + mHandler.post(task); } public InputMethodManagerService(Context context) { @@ -1538,7 +1587,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") - private void switchUserLocked(int newUserId) { + private void switchUserOnHandlerLocked(@UserIdInt int newUserId, + IInputMethodClient clientToBeReset) { if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId + " currentUserId=" + mSettings.getCurrentUserId()); @@ -1589,6 +1639,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + " selectedIme=" + mSettings.getSelectedInputMethod()); mLastSwitchUserId = newUserId; + + if (mIsInteractive && clientToBeReset != null) { + final ClientState cs = mClients.get(clientToBeReset.asBinder()); + if (cs == null) { + // The client is already gone. + return; + } + try { + cs.client.scheduleStartInputIfNecessary(mInFullscreenMode); + } catch (RemoteException e) { + } + } } void updateCurrentProfileIds() { @@ -1812,16 +1874,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId, - ComponentName componentName, AutofillId autofillId, - IInlineSuggestionsRequestCallback callback) { + InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) { final InputMethodInfo imi = mMethodMap.get(mCurMethodId); try { if (userId == mSettings.getCurrentUserId() && imi != null && imi.isInlineSuggestionsEnabled() && mCurMethod != null) { executeOrSendMessage(mCurMethod, - mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod, - componentName, autofillId, - new InlineSuggestionsRequestCallbackDecorator(callback, + mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod, + requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback, imi.getPackageName()))); } else { callback.onInlineSuggestionsUnsupported(); @@ -3074,6 +3134,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return InputBindResult.NOT_IME_TARGET_WINDOW; } + if (mUserSwitchHandlerTask != null) { + // There is already an on-going pending user switch task. + final int nextUserId = mUserSwitchHandlerTask.mToUserId; + if (userId == nextUserId) { + scheduleSwitchUserTaskLocked(userId, cs.client); + return InputBindResult.USER_SWITCHING; + } + for (int profileId : mUserManager.getProfileIdsWithDisabled(nextUserId)) { + if (profileId == userId) { + scheduleSwitchUserTaskLocked(userId, cs.client); + return InputBindResult.USER_SWITCHING; + } + } + return InputBindResult.INVALID_USER; + } + // cross-profile access is always allowed here to allow profile-switching. if (!mSettings.isCurrentProfile(userId)) { Slog.w(TAG, "A background user is requesting window. Hiding IME."); @@ -3085,8 +3161,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (userId != mSettings.getCurrentUserId()) { - switchUserLocked(userId); + scheduleSwitchUserTaskLocked(userId, cs.client); + return InputBindResult.USER_SWITCHING; } + // Master feature flag that overrides other conditions and forces IME preRendering. if (DEBUG) { Slog.v(TAG, "IME PreRendering MASTER flag: " @@ -3972,13 +4050,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // --------------------------------------------------------------- case MSG_INLINE_SUGGESTIONS_REQUEST: args = (SomeArgs) msg.obj; - final ComponentName componentName = (ComponentName) args.arg2; - final AutofillId autofillId = (AutofillId) args.arg3; + final InlineSuggestionsRequestInfo requestInfo = + (InlineSuggestionsRequestInfo) args.arg2; final IInlineSuggestionsRequestCallback callback = - (IInlineSuggestionsRequestCallback) args.arg4; + (IInlineSuggestionsRequestCallback) args.arg3; try { - ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(componentName, - autofillId, callback); + ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(requestInfo, + callback); } catch (RemoteException e) { Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e); } @@ -4549,10 +4627,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } private void onCreateInlineSuggestionsRequest(@UserIdInt int userId, - ComponentName componentName, AutofillId autofillId, + InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) { synchronized (mMethodMap) { - onCreateInlineSuggestionsRequestLocked(userId, componentName, autofillId, callback); + onCreateInlineSuggestionsRequestLocked(userId, requestInfo, callback); } } @@ -4620,9 +4698,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override - public void onCreateInlineSuggestionsRequest(int userId, ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { - mService.onCreateInlineSuggestionsRequest(userId, componentName, autofillId, cb); + public void onCreateInlineSuggestionsRequest(int userId, + InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) { + mService.onCreateInlineSuggestionsRequest(userId, requestInfo, cb); } @Override diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 54af69432ee0..4904061ec1af 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -63,7 +63,6 @@ import android.util.Slog; import android.util.SparseArray; import android.view.InputChannel; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; -import android.view.autofill.AutofillId; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags; import android.view.inputmethod.InputMethodInfo; @@ -88,6 +87,7 @@ import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodClient; import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; +import com.android.internal.view.InlineSuggestionsRequestInfo; import com.android.internal.view.InputBindResult; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -192,7 +192,7 @@ public final class MultiClientInputMethodManagerService { @Override public void onCreateInlineSuggestionsRequest(int userId, - ComponentName componentName, AutofillId autofillId, + InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) { try { //TODO(b/137800469): support multi client IMEs. diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index b9a30bb21edb..63054cf0c516 100644 --- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -45,9 +45,7 @@ import android.content.pm.PackageUserState; import android.content.pm.ParceledListSlice; import android.content.pm.Signature; import android.content.pm.SigningInfo; -import android.content.pm.parsing.ApkParseUtils; -import android.content.pm.parsing.PackageInfoUtils; -import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackageUtils; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -64,6 +62,9 @@ import com.android.server.LocalServices; import com.android.server.integrity.engine.RuleEvaluationEngine; import com.android.server.integrity.model.IntegrityCheckResult; import com.android.server.integrity.model.RuleMetadata; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.parsing.pkg.ParsedPackage; import java.io.ByteArrayInputStream; import java.io.File; @@ -508,13 +509,13 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { throw new IllegalArgumentException("Installation path is null, package not found"); } - PackageParser parser = new PackageParser(); + PackageParser2 parser = new PackageParser2(null, false, null, null, null); try { - ParsedPackage pkg = parser.parseParsedPackage(installationPath, 0, false); + ParsedPackage pkg = parser.parsePackage(installationPath, 0, false); int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA; - ApkParseUtils.collectCertificates(pkg, false); + pkg.setSigningDetails(ParsingPackageUtils.collectCertificates(pkg, false)); return PackageInfoUtils.generate(pkg, null, flags, 0, 0, null, new PackageUserState(), - UserHandle.getCallingUserId()); + UserHandle.getCallingUserId(), null); } catch (Exception e) { throw new IllegalArgumentException("Exception reading " + dataUri, e); } diff --git a/services/core/java/com/android/server/integrity/engine/RuleLoader.java b/services/core/java/com/android/server/integrity/engine/RuleLoader.java deleted file mode 100644 index 4ba2bfb00d05..000000000000 --- a/services/core/java/com/android/server/integrity/engine/RuleLoader.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.integrity.engine; - -import android.content.integrity.Rule; - -import java.util.ArrayList; -import java.util.List; - -/** - * A helper class for loading rules to the rule evaluation engine. - * - * <p>Expose fine-grained APIs for loading rules to be passed to the rule evaluation engine. - * - * <p>It supports: - * <ul> - * <li>Loading rules based on some keys, such as PACKAGE_NAME and APP_CERT.</li> - * </ul> - * - * <p>It does NOT support: - * <ul> - * <li>Loading the list of all rules.</li> - * <li>Merging rules resulting from different APIs.</li> - * </ul> - */ -final class RuleLoader { - - List<Rule> loadRulesByPackageName(String packageName) { - // TODO: Add logic based on rule storage. - return new ArrayList<>(); - } - - List<Rule> loadRulesByAppCertificate(String appCertificate) { - // TODO: Add logic based on rule storage. - return new ArrayList<>(); - } - - List<Rule> loadRulesByInstallerName(String installerName) { - // TODO: Add logic based on rule storage. - return new ArrayList<>(); - } - - List<Rule> loadRulesByInstallerCertificate(String installerCertificate) { - // TODO: Add logic based on rule storage. - return new ArrayList<>(); - } -} diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java index 11e8d91dde12..a290eb3a3e2f 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java @@ -68,8 +68,7 @@ public class RuleBinaryParser implements RuleParser { } private List<Rule> parseRules( - RandomAccessInputStream randomAccessInputStream, - List<RuleIndexRange> indexRanges) + RandomAccessInputStream randomAccessInputStream, List<RuleIndexRange> indexRanges) throws IOException { // Read the rule binary file format version. @@ -96,8 +95,7 @@ public class RuleBinaryParser implements RuleParser { } private List<Rule> parseIndexedRules( - RandomAccessInputStream randomAccessInputStream, - List<RuleIndexRange> indexRanges) + RandomAccessInputStream randomAccessInputStream, List<RuleIndexRange> indexRanges) throws IOException { List<Rule> parsedRules = new ArrayList<>(); @@ -172,6 +170,7 @@ public class RuleBinaryParser implements RuleParser { case AtomicFormula.APP_CERTIFICATE: case AtomicFormula.INSTALLER_NAME: case AtomicFormula.INSTALLER_CERTIFICATE: + case AtomicFormula.STAMP_CERTIFICATE_HASH: boolean isHashedValue = bitInputStream.getNext(IS_HASHED_BITS) == 1; int valueSize = bitInputStream.getNext(VALUE_SIZE_BITS); String stringValue = getStringValue(bitInputStream, valueSize, isHashedValue); @@ -183,6 +182,7 @@ public class RuleBinaryParser implements RuleParser { long longValue = (upper << 32) | lower; return new AtomicFormula.LongAtomicFormula(key, operator, longValue); case AtomicFormula.PRE_INSTALLED: + case AtomicFormula.STAMP_TRUSTED: boolean booleanValue = getBooleanValue(bitInputStream); return new AtomicFormula.BooleanAtomicFormula(key, booleanValue); default: diff --git a/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java index 09af655e1735..bc50ebc2c5c3 100644 --- a/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java +++ b/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java @@ -20,7 +20,6 @@ import android.content.Context; import android.location.GnssAntennaInfo; import android.location.IGnssAntennaInfoListener; import android.os.Handler; -import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -100,41 +99,10 @@ public abstract class GnssAntennaInfoProvider @Override protected ListenerOperation<IGnssAntennaInfoListener> getHandlerOperation(int result) { - int status; - switch (result) { - case RESULT_SUCCESS: - status = GnssAntennaInfo.Callback.STATUS_READY; - break; - case RESULT_NOT_AVAILABLE: - case RESULT_NOT_SUPPORTED: - case RESULT_INTERNAL_ERROR: - status = GnssAntennaInfo.Callback.STATUS_NOT_SUPPORTED; - break; - case RESULT_GPS_LOCATION_DISABLED: - status = GnssAntennaInfo.Callback.STATUS_LOCATION_DISABLED; - break; - case RESULT_UNKNOWN: - return null; - default: - Log.v(TAG, "Unhandled addListener result: " + result); - return null; - } - return new StatusChangedOperation(status); - } - - private static class StatusChangedOperation - implements ListenerOperation<IGnssAntennaInfoListener> { - private final int mStatus; - - StatusChangedOperation(int status) { - mStatus = status; - } - - @Override - public void execute(IGnssAntennaInfoListener listener, - CallerIdentity callerIdentity) throws RemoteException { - listener.onStatusChanged(mStatus); - } + return (IGnssAntennaInfoListener listener, + CallerIdentity callerIdentity) -> { + // Do nothing, as GnssAntennaInfo.Callback does not have an onStatusChanged method. + }; } /** Handle Gnss Antenna Info report. */ diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 36136f49dc42..5f44e042b5e9 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -2244,6 +2244,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) { s.append("MEASUREMENT_CORRECTIONS "); } + if (hasCapability(GPS_CAPABILITY_ANTENNA_INFO)) s.append("ANTENNA_INFO "); s.append(")\n"); if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) { s.append("SubHal=MEASUREMENT_CORRECTIONS["); diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index 1039cf6694cc..b57c261931f8 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -216,9 +216,6 @@ public class GnssManagerService { * {@link android.location.GnssCapabilities}. */ public long getGnssCapabilities(String packageName) { - mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null); - mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - if (!checkLocationAppOp(packageName)) { return GnssCapabilities.INVALID_CAPABILITIES; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 0662400dbb69..ee5a4fe248e7 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1253,7 +1253,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt"); - final NetworkStats xtSnapshot = getNetworkStatsXt(); + final NetworkStats xtSnapshot = readNetworkStatsSummaryXt(); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev"); final NetworkStats devSnapshot = readNetworkStatsSummaryDev(); @@ -1742,18 +1742,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUseBpfTrafficStats); uidSnapshot.combineAllValues(tetherSnapshot); - final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( - Context.TELEPHONY_SERVICE); - - // fold video calling data usage stats into uid snapshot - final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); - if (vtStats != null) { - vtStats.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats, - mUseBpfTrafficStats); - uidSnapshot.combineAllValues(vtStats); - } - // get a stale copy of uid stats snapshot provided by providers. final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); providerStats.filter(UID_ALL, ifaces, TAG_ALL); @@ -1766,24 +1754,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Return snapshot of current XT statistics with video calling data usage statistics. - */ - private NetworkStats getNetworkStatsXt() throws RemoteException { - final NetworkStats xtSnapshot = readNetworkStatsSummaryXt(); - - final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( - Context.TELEPHONY_SERVICE); - - // Merge video calling data usage into XT - final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(STATS_PER_IFACE); - if (vtSnapshot != null) { - xtSnapshot.combineAllValues(vtSnapshot); - } - - return xtSnapshot; - } - - /** * Return snapshot of current tethering statistics. Will return empty * {@link NetworkStats} if any problems are encountered. */ diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 3b564c3a2459..f45e66e79c76 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -19,6 +19,7 @@ package com.android.server.notification; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED; +import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY; import android.app.AppOpsManager; import android.app.AutomaticZenRule; @@ -1011,21 +1012,23 @@ public class ZenModeHelper { @VisibleForTesting protected void applyRestrictions() { + final boolean zenOn = mZenMode != Global.ZEN_MODE_OFF; final boolean zenPriorityOnly = mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; final boolean zenSilence = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; final boolean zenAlarmsOnly = mZenMode == Global.ZEN_MODE_ALARMS; - final boolean allowCalls = mConsolidatedPolicy.allowCalls(); + final boolean allowCalls = mConsolidatedPolicy.allowCalls() + && mConsolidatedPolicy.allowCallsFrom() == PRIORITY_SENDERS_ANY; final boolean allowRepeatCallers = mConsolidatedPolicy.allowRepeatCallers(); final boolean allowSystem = mConsolidatedPolicy.allowSystem(); final boolean allowMedia = mConsolidatedPolicy.allowMedia(); final boolean allowAlarms = mConsolidatedPolicy.allowAlarms(); // notification restrictions - final boolean muteNotifications = - (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0; + final boolean muteNotifications = zenOn + || (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0; // call restrictions final boolean muteCalls = zenAlarmsOnly - || (zenPriorityOnly && !allowCalls && !allowRepeatCallers) + || (zenPriorityOnly && !(allowCalls || allowRepeatCallers)) || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0; // alarm restrictions final boolean muteAlarms = zenPriorityOnly && !allowAlarms; diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java index 8bea119f3490..cadb8e4746f3 100644 --- a/services/core/java/com/android/server/om/OverlayReferenceMapper.java +++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java @@ -18,16 +18,14 @@ package com.android.server.om; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.pm.parsing.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackage; import android.text.TextUtils; -import android.util.ArraySet; import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; import com.android.server.SystemConfig; -import com.android.server.pm.PackageSetting; import java.util.Collections; import java.util.HashMap; diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index a440c62a5f3c..d12e03d32080 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -32,7 +32,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.parsing.AndroidPackage; import android.os.Environment; import android.os.RemoteException; import android.os.ServiceManager; @@ -47,6 +46,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.utils.TimingsTraceAndSlog; import com.google.android.collect.Lists; diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index a1250cb8849f..1205a33979c4 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -26,13 +26,12 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; -import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; -import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; -import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedComponent; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; import android.os.Binder; import android.os.Process; import android.os.Trace; @@ -50,6 +49,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.FgThread; import com.android.server.om.OverlayReferenceMapper; +import com.android.server.pm.parsing.pkg.AndroidPackage; import java.io.PrintWriter; import java.util.List; @@ -207,14 +207,14 @@ public class AppsFilter { /** Returns true if the querying package may query for the potential target package */ private static boolean canQueryViaComponents(AndroidPackage querying, AndroidPackage potentialTarget) { - if (querying.getQueriesIntents() != null) { + if (!querying.getQueriesIntents().isEmpty()) { for (Intent intent : querying.getQueriesIntents()) { if (matchesIntentFilters(intent, potentialTarget)) { return true; } } } - if (querying.getQueriesProviders() != null + if (!querying.getQueriesProviders().isEmpty() && matchesProviders(querying.getQueriesProviders(), potentialTarget)) { return true; } @@ -223,7 +223,7 @@ public class AppsFilter { private static boolean canQueryViaPackage(AndroidPackage querying, AndroidPackage potentialTarget) { - return querying.getQueriesPackages() != null + return !querying.getQueriesPackages().isEmpty() && querying.getQueriesPackages().contains(potentialTarget.getPackageName()); } @@ -261,7 +261,7 @@ public class AppsFilter { private static boolean matchesIntentFilters(Intent intent, AndroidPackage potentialTarget) { for (int s = ArrayUtils.size(potentialTarget.getServices()) - 1; s >= 0; s--) { ParsedService service = potentialTarget.getServices().get(s); - if (!service.exported) { + if (!service.isExported()) { continue; } if (matchesAnyFilter(intent, service)) { @@ -270,7 +270,7 @@ public class AppsFilter { } for (int a = ArrayUtils.size(potentialTarget.getActivities()) - 1; a >= 0; a--) { ParsedActivity activity = potentialTarget.getActivities().get(a); - if (!activity.exported) { + if (!activity.isExported()) { continue; } if (matchesAnyFilter(intent, activity)) { @@ -279,7 +279,7 @@ public class AppsFilter { } for (int r = ArrayUtils.size(potentialTarget.getReceivers()) - 1; r >= 0; r--) { ParsedActivity receiver = potentialTarget.getReceivers().get(r); - if (!receiver.exported) { + if (!receiver.isExported()) { continue; } if (matchesAnyFilter(intent, receiver)) { @@ -289,9 +289,8 @@ public class AppsFilter { return false; } - private static boolean matchesAnyFilter( - Intent intent, ParsedComponent<? extends ParsedIntentInfo> component) { - List<? extends ParsedIntentInfo> intents = component.intents; + private static boolean matchesAnyFilter(Intent intent, ParsedComponent component) { + List<ParsedIntentInfo> intents = component.getIntents(); for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) { IntentFilter intentFilter = intents.get(i); if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(), @@ -673,8 +672,7 @@ public class AppsFilter { String targetName) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingPkgInstruments"); - final List<ComponentParseUtils.ParsedInstrumentation> inst = - callingPkgSetting.pkg.getInstrumentations(); + final List<ParsedInstrumentation> inst = callingPkgSetting.pkg.getInstrumentations(); for (int i = ArrayUtils.size(inst) - 1; i >= 0; i--) { if (Objects.equals(inst.get(i).getTargetPackage(), targetName)) { if (DEBUG_LOGGING) { diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java index 0dacadc244f0..85810e3a9954 100644 --- a/services/core/java/com/android/server/pm/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/ComponentResolver.java @@ -22,12 +22,12 @@ import static android.content.pm.PackageManagerInternal.PACKAGE_SETUP_WIZARD; import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; import android.content.pm.AuxiliaryResolveInfo; import android.content.pm.InstantAppResolveInfo; import android.content.pm.PackageManager; @@ -37,15 +37,12 @@ import android.content.pm.PackageUserState; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; -import android.content.pm.parsing.ComponentParseUtils.ParsedProviderIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedService; -import android.content.pm.parsing.ComponentParseUtils.ParsedServiceIntentInfo; -import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedComponent; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedMainComponent; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; @@ -58,6 +55,8 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.server.IntentResolver; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; import java.io.PrintWriter; import java.util.ArrayList; @@ -191,8 +190,11 @@ public class ComponentResolver { * of these during boot as we need to inspect at all of the intent filters on the * /system partition in order to know which component is the setup wizard. This can * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}. + * + * This is a pair of component package name to actual filter, because we don't store the + * name inside the filter. It's technically independent of the component it's contained in. */ - private List<ParsedActivityIntentInfo> mProtectedFilters; + private List<Pair<ParsedMainComponent, ParsedIntentInfo>> mProtectedFilters; ComponentResolver(UserManagerService userManager, PackageManagerInternal packageManagerInternal, @@ -299,7 +301,7 @@ public class ComponentResolver { continue; } final ProviderInfo info = PackageInfoUtils.generateProviderInfo( - pkg, p, flags, ps.readUserState(userId), userId); + pkg, p, flags, ps.readUserState(userId), userId, ps); if (info == null) { continue; } @@ -329,7 +331,7 @@ public class ComponentResolver { return null; } return PackageInfoUtils.generateProviderInfo(pkg, p, flags, - ps.readUserState(userId), userId); + ps.readUserState(userId), userId, ps); } } @@ -354,12 +356,12 @@ public class ComponentResolver { continue; } - if (safeMode && (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) == 0) { + if (safeMode && !pkg.isSystem()) { continue; } final ProviderInfo info = PackageInfoUtils.generateProviderInfo(pkg, p, 0, - ps.readUserState(userId), userId); + ps.readUserState(userId), userId, ps); if (info == null) { continue; } @@ -415,7 +417,7 @@ public class ComponentResolver { /** Add all components defined in the given package to the internal structures. */ void addAllComponents(AndroidPackage pkg, boolean chatty) { - final ArrayList<ParsedActivityIntentInfo> newIntents = new ArrayList<>(); + final ArrayList<Pair<ParsedActivity, ParsedIntentInfo>> newIntents = new ArrayList<>(); synchronized (mLock) { addActivitiesLocked(pkg, newIntents, chatty); addReceiversLocked(pkg, chatty); @@ -428,14 +430,14 @@ public class ComponentResolver { PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)); for (int i = newIntents.size() - 1; i >= 0; --i) { - final ParsedActivityIntentInfo intentInfo = newIntents.get(i); + final Pair<ParsedActivity, ParsedIntentInfo> pair = newIntents.get(i); final PackageSetting disabledPkgSetting = (PackageSetting) sPackageManagerInternal - .getDisabledSystemPackage(intentInfo.getPackageName()); + .getDisabledSystemPackage(pair.first.getPackageName()); final AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg; final List<ParsedActivity> systemActivities = disabledPkg != null ? disabledPkg.getActivities() : null; - adjustPriority(systemActivities, intentInfo, setupWizardPackage); + adjustPriority(systemActivities, pair.first, pair.second, setupWizardPackage); } } @@ -459,7 +461,8 @@ public class ComponentResolver { if (mProtectedFilters == null || mProtectedFilters.size() == 0) { return; } - final List<ParsedActivityIntentInfo> protectedFilters = mProtectedFilters; + final List<Pair<ParsedMainComponent, ParsedIntentInfo>> protectedFilters = + mProtectedFilters; mProtectedFilters = null; // expect single setupwizard package @@ -472,13 +475,17 @@ public class ComponentResolver { + " All protected intents capped to priority 0"); } for (int i = protectedFilters.size() - 1; i >= 0; --i) { - final ParsedActivityIntentInfo filter = protectedFilters.get(i); - if (filter.getPackageName().equals(setupWizardPackage)) { + final Pair<ParsedMainComponent, ParsedIntentInfo> pair = protectedFilters.get(i); + ParsedMainComponent component = pair.first; + ParsedIntentInfo filter = pair.second; + String packageName = component.getPackageName(); + String className = component.getClassName(); + if (packageName.equals(setupWizardPackage)) { if (DEBUG_FILTERS) { Slog.i(TAG, "Found setup wizard;" + " allow priority " + filter.getPriority() + ";" - + " package: " + filter.getPackageName() - + " activity: " + filter.getClassName() + + " package: " + packageName + + " activity: " + className + " priority: " + filter.getPriority()); } // skip setup wizard; allow it to keep the high priority filter @@ -486,8 +493,8 @@ public class ComponentResolver { } if (DEBUG_FILTERS) { Slog.i(TAG, "Protected action; cap priority to 0;" - + " package: " + filter.getPackageName() - + " activity: " + filter.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + filter.getPriority()); } filter.setPriority(0); @@ -540,7 +547,7 @@ public class ComponentResolver { printedSomething = true; } pw.print(" "); - ComponentName.printShortString(pw, p.getPackageName(), p.className); + ComponentName.printShortString(pw, p.getPackageName(), p.getName()); pw.println(":"); pw.print(" "); pw.println(p.toString()); @@ -575,24 +582,11 @@ public class ComponentResolver { if (dumpState.onTitlePrinted()) pw.println(); pw.println("Service permissions:"); - final Iterator<ParsedServiceIntentInfo> filterIterator = mServices.filterIterator(); + final Iterator<Pair<ParsedService, ParsedIntentInfo>> filterIterator = + mServices.filterIterator(); while (filterIterator.hasNext()) { - final ParsedServiceIntentInfo info = filterIterator.next(); - - ParsedService service = null; - - AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName()); - if (pkg != null && pkg.getServices() != null) { - for (ParsedService parsedService : pkg.getServices()) { - if (Objects.equals(parsedService.className, info.getClassName())) { - service = parsedService; - } - } - } - - if (service == null) { - continue; - } + final Pair<ParsedService, ParsedIntentInfo> pair = filterIterator.next(); + ParsedService service = pair.first; final String permission = service.getPermission(); if (permission != null) { @@ -606,7 +600,7 @@ public class ComponentResolver { @GuardedBy("mLock") private void addActivitiesLocked(AndroidPackage pkg, - List<ParsedActivityIntentInfo> newIntents, boolean chatty) { + List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty) { final int activitiesSize = ArrayUtils.size(pkg.getActivities()); StringBuilder r = null; for (int i = 0; i < activitiesSize; i++) { @@ -671,7 +665,7 @@ public class ComponentResolver { final String packageName = component != null ? component.getPackageName() : "?"; Slog.w(TAG, "Skipping provider name " + names[j] - + " (in package " + pkg.getAppInfoPackageName() + ")" + + " (in package " + pkg.getPackageName() + ")" + ": name already used by " + packageName); } } @@ -736,8 +730,8 @@ public class ComponentResolver { * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE * MODIFIED. Do not pass in a list that should not be changed. */ - private static <T> void getIntentListSubset(List<ParsedActivityIntentInfo> intentList, - Function<ParsedActivityIntentInfo, Iterator<T>> generator, Iterator<T> searchIterator) { + private static <T> void getIntentListSubset(List<ParsedIntentInfo> intentList, + Function<ParsedIntentInfo, Iterator<T>> generator, Iterator<T> searchIterator) { // loop through the set of actions; every one must be found in the intent filter while (searchIterator.hasNext()) { // we must have at least one filter in the list to consider a match @@ -748,9 +742,9 @@ public class ComponentResolver { final T searchAction = searchIterator.next(); // loop through the set of intent filters - final Iterator<ParsedActivityIntentInfo> intentIter = intentList.iterator(); + final Iterator<ParsedIntentInfo> intentIter = intentList.iterator(); while (intentIter.hasNext()) { - final ParsedActivityIntentInfo intentInfo = intentIter.next(); + final ParsedIntentInfo intentInfo = intentIter.next(); boolean selectionFound = false; // loop through the intent filter's selection criteria; at least one @@ -773,7 +767,7 @@ public class ComponentResolver { } } - private static boolean isProtectedAction(ParsedActivityIntentInfo filter) { + private static boolean isProtectedAction(ParsedIntentInfo filter) { final Iterator<String> actionsIter = filter.actionsIterator(); while (actionsIter != null && actionsIter.hasNext()) { final String filterAction = actionsIter.next(); @@ -793,14 +787,14 @@ public class ComponentResolver { if (sysActivity.getName().equals(activityInfo.getName())) { return sysActivity; } - if (sysActivity.getName().equals(activityInfo.targetActivity)) { + if (sysActivity.getName().equals(activityInfo.getTargetActivity())) { return sysActivity; } - if (sysActivity.targetActivity != null) { - if (sysActivity.targetActivity.equals(activityInfo.getName())) { + if (sysActivity.getTargetActivity() != null) { + if (sysActivity.getTargetActivity().equals(activityInfo.getName())) { return sysActivity; } - if (sysActivity.targetActivity.equals(activityInfo.targetActivity)) { + if (sysActivity.getTargetActivity().equals(activityInfo.getTargetActivity())) { return sysActivity; } } @@ -821,23 +815,24 @@ public class ComponentResolver { * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is * allowed to obtain any priority on any action. */ - private void adjustPriority(List<ParsedActivity> systemActivities, - ParsedActivityIntentInfo intent, String setupWizardPackage) { + private void adjustPriority(List<ParsedActivity> systemActivities, ParsedActivity activity, + ParsedIntentInfo intent, String setupWizardPackage) { // nothing to do; priority is fine as-is if (intent.getPriority() <= 0) { return; } - AndroidPackage pkg = sPackageManagerInternal.getPackage(intent.getPackageName()); + String packageName = activity.getPackageName(); + AndroidPackage pkg = sPackageManagerInternal.getPackage(packageName); - final boolean privilegedApp = - ((pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0); + final boolean privilegedApp = pkg.isPrivileged(); + String className = activity.getClassName(); if (!privilegedApp) { // non-privileged applications can never define a priority >0 if (DEBUG_FILTERS) { Slog.i(TAG, "Non-privileged app; cap priority to 0;" - + " package: " + pkg.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -858,11 +853,11 @@ public class ComponentResolver { if (mProtectedFilters == null) { mProtectedFilters = new ArrayList<>(); } - mProtectedFilters.add(intent); + mProtectedFilters.add(Pair.create(activity, intent)); if (DEBUG_FILTERS) { Slog.i(TAG, "Protected action; save for later;" - + " package: " + pkg.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + intent.getPriority()); } return; @@ -871,12 +866,12 @@ public class ComponentResolver { Slog.i(TAG, "No setup wizard;" + " All protected intents capped to priority 0"); } - if (intent.getPackageName().equals(setupWizardPackage)) { + if (packageName.equals(setupWizardPackage)) { if (DEBUG_FILTERS) { Slog.i(TAG, "Found setup wizard;" + " allow priority " + intent.getPriority() + ";" - + " package: " + intent.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " priority: " + intent.getPriority()); } // setup wizard gets whatever it wants @@ -884,8 +879,8 @@ public class ComponentResolver { } if (DEBUG_FILTERS) { Slog.i(TAG, "Protected action; cap priority to 0;" - + " package: " + intent.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -898,27 +893,13 @@ public class ComponentResolver { // privileged app unbundled update ... try to find the same activity - ParsedActivity foundActivity = null; - ParsedActivity activity = null; - - if (pkg.getActivities() != null) { - for (ParsedActivity parsedProvider : pkg.getActivities()) { - if (Objects.equals(parsedProvider.className, intent.getClassName())) { - activity = parsedProvider; - } - } - } - - if (activity != null) { - foundActivity = findMatchingActivity(systemActivities, activity); - } - + ParsedActivity foundActivity = findMatchingActivity(systemActivities, activity); if (foundActivity == null) { // this is a new activity; it cannot obtain >0 priority if (DEBUG_FILTERS) { Slog.i(TAG, "New activity; cap priority to 0;" - + " package: " + pkg.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -928,8 +909,8 @@ public class ComponentResolver { // found activity, now check for filter equivalence // a shallow copy is enough; we modify the list, not its contents - final List<ParsedActivityIntentInfo> intentListCopy = - new ArrayList<>(foundActivity.intents); + final List<ParsedIntentInfo> intentListCopy = + new ArrayList<>(foundActivity.getIntents()); // find matching action subsets final Iterator<String> actionsIterator = intent.actionsIterator(); @@ -939,8 +920,8 @@ public class ComponentResolver { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched action; cap priority to 0;" - + " package: " + pkg.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -957,8 +938,8 @@ public class ComponentResolver { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched category; cap priority to 0;" - + " package: " + pkg.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -974,8 +955,8 @@ public class ComponentResolver { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched scheme; cap priority to 0;" - + " package: " + pkg.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -993,8 +974,8 @@ public class ComponentResolver { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched authority; cap priority to 0;" - + " package: " + pkg.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -1011,8 +992,8 @@ public class ComponentResolver { if (DEBUG_FILTERS) { Slog.i(TAG, "Found matching filter(s);" + " cap priority to " + cappedPriority + ";" - + " package: " + pkg.getPackageName() - + " activity: " + intent.getClassName() + + " package: " + packageName + + " activity: " + className + " origPrio: " + intent.getPriority()); } intent.setPriority(cappedPriority); @@ -1146,31 +1127,34 @@ public class ComponentResolver { } } - private abstract static class MimeGroupsAwareIntentResolver<F extends ParsedIntentInfo, R> + private abstract static class MimeGroupsAwareIntentResolver<F extends Pair<? + extends ParsedComponent, ParsedIntentInfo>, R> extends IntentResolver<F, R> { private ArrayMap<String, F[]> mMimeGroupToFilter = new ArrayMap<>(); private boolean mIsUpdatingMimeGroup = false; @Override public void addFilter(F f) { + IntentFilter intentFilter = getIntentFilter(f); applyMimeGroups(f); super.addFilter(f); if (!mIsUpdatingMimeGroup) { - register_intent_filter(f, f.mimeGroupsIterator(), mMimeGroupToFilter, + register_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter, " MimeGroup: "); } } @Override protected void removeFilterInternal(F f) { + IntentFilter intentFilter = getIntentFilter(f); if (!mIsUpdatingMimeGroup) { - unregister_intent_filter(f, f.mimeGroupsIterator(), mMimeGroupToFilter, + unregister_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter, " MimeGroup: "); } super.removeFilterInternal(f); - f.clearDynamicDataTypes(); + intentFilter.clearDynamicDataTypes(); } /** @@ -1197,10 +1181,11 @@ public class ComponentResolver { return hasChanges; } - private boolean updateFilter(F filter) { + private boolean updateFilter(F f) { + IntentFilter filter = getIntentFilter(f); List<String> oldTypes = filter.dataTypes(); - removeFilter(filter); - addFilter(filter); + removeFilter(f); + addFilter(f); List<String> newTypes = filter.dataTypes(); return !equalLists(oldTypes, newTypes); } @@ -1221,12 +1206,12 @@ public class ComponentResolver { return first.equals(second); } - private void applyMimeGroups(F filter) { - String packageName = filter.getPackageName(); + private void applyMimeGroups(F f) { + IntentFilter filter = getIntentFilter(f); for (int i = filter.countMimeGroups() - 1; i >= 0; i--) { - List<String> mimeTypes = sPackageManagerInternal.getMimeGroup(packageName, - filter.getMimeGroup(i)); + List<String> mimeTypes = sPackageManagerInternal.getMimeGroup( + f.first.getPackageName(), filter.getMimeGroup(i)); for (int typeIndex = mimeTypes.size() - 1; typeIndex >= 0; typeIndex--) { String mimeType = mimeTypes.get(typeIndex); @@ -1244,7 +1229,7 @@ public class ComponentResolver { } private static class ActivityIntentResolver - extends MimeGroupsAwareIntentResolver<ParsedActivityIntentInfo, ResolveInfo> { + extends MimeGroupsAwareIntentResolver<Pair<ParsedActivity, ParsedIntentInfo>, ResolveInfo> { @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, @@ -1277,15 +1262,18 @@ public class ComponentResolver { mFlags = flags; final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; final int activitiesSize = packageActivities.size(); - ArrayList<ParsedActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize); + ArrayList<Pair<ParsedActivity, ParsedIntentInfo>[]> listCut = + new ArrayList<>(activitiesSize); - List<ParsedActivityIntentInfo> intentFilters; + List<ParsedIntentInfo> intentFilters; for (int i = 0; i < activitiesSize; ++i) { - intentFilters = packageActivities.get(i).intents; - if (intentFilters != null && intentFilters.size() > 0) { - ParsedActivityIntentInfo[] array = - new ParsedActivityIntentInfo[intentFilters.size()]; - intentFilters.toArray(array); + ParsedActivity activity = packageActivities.get(i); + intentFilters = activity.getIntents(); + if (!intentFilters.isEmpty()) { + Pair<ParsedActivity, ParsedIntentInfo>[] array = newArray(intentFilters.size()); + for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) { + array[arrayIndex] = Pair.create(activity, intentFilters.get(arrayIndex)); + } listCut.add(array); } } @@ -1293,22 +1281,17 @@ public class ComponentResolver { } private void addActivity(ParsedActivity a, String type, - List<ParsedActivityIntentInfo> newIntents) { + List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) { mActivities.put(a.getComponentName(), a); if (DEBUG_SHOW_INFO) { - final CharSequence label = a.nonLocalizedLabel != null - ? a.nonLocalizedLabel - : a.getName(); - Log.v(TAG, " " + type + " " + label + ":"); - } - if (DEBUG_SHOW_INFO) { + Log.v(TAG, " " + type + ":"); Log.v(TAG, " Class=" + a.getName()); } - final int intentsSize = a.intents.size(); + final int intentsSize = a.getIntents().size(); for (int j = 0; j < intentsSize; j++) { - ParsedActivityIntentInfo intent = a.intents.get(j); + ParsedIntentInfo intent = a.getIntents().get(j); if (newIntents != null && "activity".equals(type)) { - newIntents.add(intent); + newIntents.add(Pair.create(a, intent)); } if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); @@ -1317,36 +1300,34 @@ public class ComponentResolver { if (!intent.debugCheck()) { Log.w(TAG, "==> For Activity " + a.getName()); } - addFilter(intent); + addFilter(Pair.create(a, intent)); } } private void removeActivity(ParsedActivity a, String type) { mActivities.remove(a.getComponentName()); if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + type + " " - + (a.nonLocalizedLabel != null ? a.nonLocalizedLabel - : a.getName()) + ":"); + Log.v(TAG, " " + type + ":"); Log.v(TAG, " Class=" + a.getName()); } - final int intentsSize = a.intents.size(); + final int intentsSize = a.getIntents().size(); for (int j = 0; j < intentsSize; j++) { - ParsedActivityIntentInfo intent = a.intents.get(j); + ParsedIntentInfo intent = a.getIntents().get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } - removeFilter(intent); + removeFilter(Pair.create(a, intent)); } } @Override - protected boolean allowFilterResult( - ParsedActivityIntentInfo filter, List<ResolveInfo> dest) { + protected boolean allowFilterResult(Pair<ParsedActivity, ParsedIntentInfo> filter, + List<ResolveInfo> dest) { for (int i = dest.size() - 1; i >= 0; --i) { ActivityInfo destAi = dest.get(i).activityInfo; - if (Objects.equals(destAi.name, filter.getClassName()) - && Objects.equals(destAi.packageName, filter.getPackageName())) { + if (Objects.equals(destAi.name, filter.first.getName()) + && Objects.equals(destAi.packageName, filter.first.getPackageName())) { return false; } } @@ -1354,39 +1335,23 @@ public class ComponentResolver { } @Override - protected ParsedActivityIntentInfo[] newArray(int size) { - return new ParsedActivityIntentInfo[size]; + protected Pair<ParsedActivity, ParsedIntentInfo>[] newArray(int size) { + //noinspection unchecked + return (Pair<ParsedActivity, ParsedIntentInfo>[]) new Pair<?, ?>[size]; } @Override - protected boolean isFilterStopped(ParsedActivityIntentInfo filter, int userId) { - if (!sUserManager.exists(userId)) return true; - - AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); - if (pkg == null) { - return false; - } - - PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( - filter.getPackageName()); - if (ps == null) { - return false; - } - - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); + protected boolean isFilterStopped(Pair<ParsedActivity, ParsedIntentInfo> filter, int userId) { + return ComponentResolver.isFilterStopped(filter, userId); } @Override protected boolean isPackageForFilter(String packageName, - ParsedActivityIntentInfo info) { - return packageName.equals(info.getPackageName()); + Pair<ParsedActivity, ParsedIntentInfo> info) { + return packageName.equals(info.first.getPackageName()); } - private void log(String reason, ParsedActivityIntentInfo info, int match, + private void log(String reason, ParsedIntentInfo info, int match, int userId) { Slog.w(TAG, reason + "; match: " @@ -1396,8 +1361,11 @@ public class ComponentResolver { } @Override - protected ResolveInfo newResult(ParsedActivityIntentInfo info, + protected ResolveInfo newResult(Pair<ParsedActivity, ParsedIntentInfo> pair, int match, int userId) { + ParsedActivity activity = pair.first; + ParsedIntentInfo info = pair.second; + if (!sUserManager.exists(userId)) { if (DEBUG) { log("User doesn't exist", info, match, userId); @@ -1405,27 +1373,11 @@ public class ComponentResolver { return null; } - ParsedActivity activity = null; - - AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName()); + AndroidPackage pkg = sPackageManagerInternal.getPackage(activity.getPackageName()); if (pkg == null) { return null; } - // TODO(b/135203078): Consider more efficient ways of doing this. - List<ParsedActivity> activities = getResolveList(pkg); - if (activities != null) { - for (ParsedActivity parsedActivity : activities) { - if (Objects.equals(parsedActivity.className, info.getClassName())) { - activity = parsedActivity; - } - } - } - - if (activity == null) { - return null; - } - if (!sPackageManagerInternal.isEnabledAndMatches(activity, mFlags, userId)) { if (DEBUG) { log("!PackageManagerInternal.isEnabledAndMatches; mFlags=" @@ -1435,7 +1387,7 @@ public class ComponentResolver { return null; } PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( - info.getPackageName()); + activity.getPackageName()); if (ps == null) { if (DEBUG) { log("info.activity.owner.mExtras == null", info, match, userId); @@ -1443,8 +1395,8 @@ public class ComponentResolver { return null; } final PackageUserState userState = ps.readUserState(userId); - ActivityInfo ai = - PackageInfoUtils.generateActivityInfo(pkg, activity, mFlags, userState, userId); + ActivityInfo ai = PackageInfoUtils.generateActivityInfo(pkg, activity, mFlags, + userState, userId, ps); if (ai == null) { if (DEBUG) { log("Failed to create ActivityInfo based on " + activity, info, match, @@ -1502,19 +1454,20 @@ public class ComponentResolver { } res.handleAllWebDataURI = info.handleAllWebDataURI(); res.priority = info.getPriority(); - res.preferredOrder = pkg.getPreferredOrder(); + // TODO(b/135203078): This field was unwritten and does nothing +// res.preferredOrder = pkg.getPreferredOrder(); //System.out.println("Result: " + res.activityInfo.className + // " = " + res.priority); res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; + res.isDefault = info.isHasDefault(); + res.labelRes = info.getLabelRes(); + res.nonLocalizedLabel = info.getNonLocalizedLabel(); if (sPackageManagerInternal.userNeedsBadging(userId)) { res.noResourceId = true; } else { - res.icon = info.icon; + res.icon = info.getIcon(); } - res.iconResourceId = info.icon; + res.iconResourceId = info.getIcon(); res.system = res.activityInfo.applicationInfo.isSystemApp(); res.isInstantAppAvailable = userState.instantApp; return res; @@ -1527,43 +1480,44 @@ public class ComponentResolver { @Override protected void dumpFilter(PrintWriter out, String prefix, - ParsedActivityIntentInfo filter) { - ParsedActivity activity = null; - - AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); - if (pkg != null && pkg.getActivities() != null) { - for (ParsedActivity parsedActivity : pkg.getActivities()) { - if (Objects.equals(parsedActivity.className, filter.getClassName())) { - activity = parsedActivity; - } - } - } + Pair<ParsedActivity, ParsedIntentInfo> pair) { + ParsedActivity activity = pair.first; + ParsedIntentInfo filter = pair.second; out.print(prefix); out.print(Integer.toHexString(System.identityHashCode(activity))); out.print(' '); - ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName()); + ComponentName.printShortString(out, activity.getPackageName(), + activity.getClassName()); out.print(" filter "); out.println(Integer.toHexString(System.identityHashCode(filter))); } @Override - protected Object filterToLabel(ParsedActivityIntentInfo filter) { + protected Object filterToLabel(Pair<ParsedActivity, ParsedIntentInfo> filter) { return filter; } protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - ParsedActivityIntentInfo activity = (ParsedActivityIntentInfo) label; + @SuppressWarnings("unchecked") Pair<ParsedActivity, ParsedIntentInfo> pair = + (Pair<ParsedActivity, ParsedIntentInfo>) label; out.print(prefix); - out.print(Integer.toHexString(System.identityHashCode(activity))); + out.print(Integer.toHexString(System.identityHashCode(pair.first))); out.print(' '); - ComponentName.printShortString(out, activity.getPackageName(), activity.getClassName()); + ComponentName.printShortString(out, pair.first.getPackageName(), + pair.first.getClassName()); if (count > 1) { out.print(" ("); out.print(count); out.print(" filters)"); } out.println(); } + @Override + protected IntentFilter getIntentFilter( + @NonNull Pair<ParsedActivity, ParsedIntentInfo> input) { + return input.second; + } + protected List<ParsedActivity> getResolveList(AndroidPackage pkg) { return pkg.getActivities(); } @@ -1585,7 +1539,7 @@ public class ComponentResolver { } private static final class ProviderIntentResolver - extends MimeGroupsAwareIntentResolver<ParsedProviderIntentInfo, ResolveInfo> { + extends MimeGroupsAwareIntentResolver<Pair<ParsedProvider, ParsedIntentInfo>, ResolveInfo> { @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1617,15 +1571,18 @@ public class ComponentResolver { mFlags = flags; final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; final int providersSize = packageProviders.size(); - ArrayList<ParsedProviderIntentInfo[]> listCut = new ArrayList<>(providersSize); + ArrayList<Pair<ParsedProvider, ParsedIntentInfo>[]> listCut = + new ArrayList<>(providersSize); - List<ParsedProviderIntentInfo> intentFilters; + List<ParsedIntentInfo> intentFilters; for (int i = 0; i < providersSize; ++i) { - intentFilters = packageProviders.get(i).getIntents(); - if (intentFilters != null && intentFilters.size() > 0) { - ParsedProviderIntentInfo[] array = - new ParsedProviderIntentInfo[intentFilters.size()]; - intentFilters.toArray(array); + ParsedProvider provider = packageProviders.get(i); + intentFilters = provider.getIntents(); + if (!intentFilters.isEmpty()) { + Pair<ParsedProvider, ParsedIntentInfo>[] array = newArray(intentFilters.size()); + for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) { + array[arrayIndex] = Pair.create(provider, intentFilters.get(arrayIndex)); + } listCut.add(array); } } @@ -1640,17 +1597,13 @@ public class ComponentResolver { mProviders.put(p.getComponentName(), p); if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " - + (p.nonLocalizedLabel != null - ? p.nonLocalizedLabel - : p.getName()) - + ":"); + Log.v(TAG, " provider:"); Log.v(TAG, " Class=" + p.getName()); } final int intentsSize = p.getIntents().size(); int j; for (j = 0; j < intentsSize; j++) { - ParsedProviderIntentInfo intent = p.getIntents().get(j); + ParsedIntentInfo intent = p.getIntents().get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); @@ -1658,37 +1611,35 @@ public class ComponentResolver { if (!intent.debugCheck()) { Log.w(TAG, "==> For Provider " + p.getName()); } - addFilter(intent); + addFilter(Pair.create(p, intent)); } } void removeProvider(ParsedProvider p) { mProviders.remove(p.getComponentName()); if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + (p.nonLocalizedLabel != null - ? p.nonLocalizedLabel - : p.getName()) + ":"); + Log.v(TAG, " provider:"); Log.v(TAG, " Class=" + p.getName()); } final int intentsSize = p.getIntents().size(); int j; for (j = 0; j < intentsSize; j++) { - ParsedProviderIntentInfo intent = p.getIntents().get(j); + ParsedIntentInfo intent = p.getIntents().get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } - removeFilter(intent); + removeFilter(Pair.create(p, intent)); } } @Override - protected boolean allowFilterResult( - ParsedProviderIntentInfo filter, List<ResolveInfo> dest) { + protected boolean allowFilterResult(Pair<ParsedProvider, ParsedIntentInfo> filter, + List<ResolveInfo> dest) { for (int i = dest.size() - 1; i >= 0; i--) { ProviderInfo destPi = dest.get(i).providerInfo; - if (Objects.equals(destPi.name, filter.getClassName()) - && Objects.equals(destPi.packageName, filter.getPackageName())) { + if (Objects.equals(destPi.name, filter.first.getClassName()) + && Objects.equals(destPi.packageName, filter.first.getPackageName())) { return false; } } @@ -1696,59 +1647,35 @@ public class ComponentResolver { } @Override - protected ParsedProviderIntentInfo[] newArray(int size) { - return new ParsedProviderIntentInfo[size]; + protected Pair<ParsedProvider, ParsedIntentInfo>[] newArray(int size) { + //noinspection unchecked + return (Pair<ParsedProvider, ParsedIntentInfo>[]) new Pair<?, ?>[size]; } @Override - protected boolean isFilterStopped(ParsedProviderIntentInfo filter, int userId) { - if (!sUserManager.exists(userId)) { - return true; - } - - AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); - if (pkg == null) { - return false; - } - - PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( - filter.getPackageName()); - if (ps == null) { - return false; - } - - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); + protected boolean isFilterStopped(Pair<ParsedProvider, ParsedIntentInfo> filter, + int userId) { + return ComponentResolver.isFilterStopped(filter, userId); } @Override protected boolean isPackageForFilter(String packageName, - ParsedProviderIntentInfo info) { - return packageName.equals(info.getPackageName()); + Pair<ParsedProvider, ParsedIntentInfo> info) { + return packageName.equals(info.first.getPackageName()); } @Override - protected ResolveInfo newResult(ParsedProviderIntentInfo filter, + protected ResolveInfo newResult(Pair<ParsedProvider, ParsedIntentInfo> pair, int match, int userId) { if (!sUserManager.exists(userId)) { return null; } - ParsedProvider provider = null; - - AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); - if (pkg != null && pkg.getProviders() != null) { - for (ParsedProvider parsedProvider : pkg.getProviders()) { - if (Objects.equals(parsedProvider.className, filter.getClassName())) { - provider = parsedProvider; - } - } - } + ParsedProvider provider = pair.first; + ParsedIntentInfo filter = pair.second; - if (provider == null) { + AndroidPackage pkg = sPackageManagerInternal.getPackage(provider.getPackageName()); + if (pkg == null) { return null; } @@ -1757,7 +1684,7 @@ public class ComponentResolver { } PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( - filter.getPackageName()); + provider.getPackageName()); if (ps == null) { return null; } @@ -1779,8 +1706,8 @@ public class ComponentResolver { if (userState.instantApp && ps.isUpdateAvailable()) { return null; } - ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider, - mFlags, userState, userId); + ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider, mFlags, + userState, userId, ps); if (pi == null) { return null; } @@ -1790,12 +1717,13 @@ public class ComponentResolver { res.filter = filter; } res.priority = filter.getPriority(); - res.preferredOrder = pkg.getPreferredOrder(); + // TODO(b/135203078): This field was unwritten and does nothing +// res.preferredOrder = pkg.getPreferredOrder(); res.match = match; - res.isDefault = filter.hasDefault; - res.labelRes = filter.labelRes; - res.nonLocalizedLabel = filter.nonLocalizedLabel; - res.icon = filter.icon; + res.isDefault = filter.isHasDefault(); + res.labelRes = filter.getLabelRes(); + res.nonLocalizedLabel = filter.getNonLocalizedLabel(); + res.icon = filter.getIcon(); res.system = res.providerInfo.applicationInfo.isSystemApp(); return res; } @@ -1807,37 +1735,31 @@ public class ComponentResolver { @Override protected void dumpFilter(PrintWriter out, String prefix, - ParsedProviderIntentInfo filter) { - ParsedProvider provider = null; - - AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); - if (pkg != null && pkg.getProviders() != null) { - for (ParsedProvider parsedProvider : pkg.getProviders()) { - if (Objects.equals(parsedProvider.className, filter.getClassName())) { - provider = parsedProvider; - } - } - } + Pair<ParsedProvider, ParsedIntentInfo> pair) { + ParsedProvider provider = pair.first; + ParsedIntentInfo filter = pair.second; out.print(prefix); out.print(Integer.toHexString(System.identityHashCode(provider))); out.print(' '); - ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName()); + ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName()); out.print(" filter "); out.println(Integer.toHexString(System.identityHashCode(filter))); } @Override - protected Object filterToLabel(ParsedProviderIntentInfo filter) { + protected Object filterToLabel(Pair<ParsedProvider, ParsedIntentInfo> filter) { return filter; } protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - final ParsedProviderIntentInfo provider = (ParsedProviderIntentInfo) label; + @SuppressWarnings("unchecked") final Pair<ParsedProvider, ParsedIntentInfo> pair = + (Pair<ParsedProvider, ParsedIntentInfo>) label; out.print(prefix); - out.print(Integer.toHexString(System.identityHashCode(provider))); + out.print(Integer.toHexString(System.identityHashCode(pair.first))); out.print(' '); - ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName()); + ComponentName.printShortString(out, pair.first.getPackageName(), + pair.first.getClassName()); if (count > 1) { out.print(" ("); out.print(count); @@ -1846,12 +1768,18 @@ public class ComponentResolver { out.println(); } + @Override + protected IntentFilter getIntentFilter( + @NonNull Pair<ParsedProvider, ParsedIntentInfo> input) { + return input.second; + } + private final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>(); private int mFlags; } private static final class ServiceIntentResolver - extends MimeGroupsAwareIntentResolver<ParsedServiceIntentInfo, ResolveInfo> { + extends MimeGroupsAwareIntentResolver<Pair<ParsedService, ParsedIntentInfo>, ResolveInfo> { @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1877,15 +1805,18 @@ public class ComponentResolver { mFlags = flags; final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; final int servicesSize = packageServices.size(); - ArrayList<ParsedServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize); + ArrayList<Pair<ParsedService, ParsedIntentInfo>[]> listCut = + new ArrayList<>(servicesSize); - List<ParsedServiceIntentInfo> intentFilters; + List<ParsedIntentInfo> intentFilters; for (int i = 0; i < servicesSize; ++i) { - intentFilters = packageServices.get(i).intents; - if (intentFilters != null && intentFilters.size() > 0) { - ParsedServiceIntentInfo[] array = - new ParsedServiceIntentInfo[intentFilters.size()]; - intentFilters.toArray(array); + ParsedService service = packageServices.get(i); + intentFilters = service.getIntents(); + if (intentFilters.size() > 0) { + Pair<ParsedService, ParsedIntentInfo>[] array = newArray(intentFilters.size()); + for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) { + array[arrayIndex] = Pair.create(service, intentFilters.get(arrayIndex)); + } listCut.add(array); } } @@ -1895,15 +1826,13 @@ public class ComponentResolver { void addService(ParsedService s) { mServices.put(s.getComponentName(), s); if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " - + (s.nonLocalizedLabel != null - ? s.nonLocalizedLabel : s.getName()) + ":"); + Log.v(TAG, " service:"); Log.v(TAG, " Class=" + s.getName()); } - final int intentsSize = s.intents.size(); + final int intentsSize = s.getIntents().size(); int j; for (j = 0; j < intentsSize; j++) { - ParsedServiceIntentInfo intent = s.intents.get(j); + ParsedIntentInfo intent = s.getIntents().get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); @@ -1911,36 +1840,35 @@ public class ComponentResolver { if (!intent.debugCheck()) { Log.w(TAG, "==> For Service " + s.getName()); } - addFilter(intent); + addFilter(Pair.create(s, intent)); } } void removeService(ParsedService s) { mServices.remove(s.getComponentName()); if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + (s.nonLocalizedLabel != null - ? s.nonLocalizedLabel : s.getName()) + ":"); + Log.v(TAG, " service:"); Log.v(TAG, " Class=" + s.getName()); } - final int intentsSize = s.intents.size(); + final int intentsSize = s.getIntents().size(); int j; for (j = 0; j < intentsSize; j++) { - ParsedServiceIntentInfo intent = s.intents.get(j); + ParsedIntentInfo intent = s.getIntents().get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } - removeFilter(intent); + removeFilter(Pair.create(s, intent)); } } @Override - protected boolean allowFilterResult( - ParsedServiceIntentInfo filter, List<ResolveInfo> dest) { + protected boolean allowFilterResult(Pair<ParsedService, ParsedIntentInfo> filter, + List<ResolveInfo> dest) { for (int i = dest.size() - 1; i >= 0; --i) { ServiceInfo destAi = dest.get(i).serviceInfo; - if (Objects.equals(destAi.name, filter.getClassName()) - && Objects.equals(destAi.packageName, filter.getPackageName())) { + if (Objects.equals(destAi.name, filter.first.getClassName()) + && Objects.equals(destAi.packageName, filter.first.getPackageName())) { return false; } } @@ -1948,55 +1876,32 @@ public class ComponentResolver { } @Override - protected ParsedServiceIntentInfo[] newArray(int size) { - return new ParsedServiceIntentInfo[size]; + protected Pair<ParsedService, ParsedIntentInfo>[] newArray(int size) { + //noinspection unchecked + return (Pair<ParsedService, ParsedIntentInfo>[]) new Pair<?, ?>[size]; } @Override - protected boolean isFilterStopped(ParsedServiceIntentInfo filter, int userId) { - if (!sUserManager.exists(userId)) return true; - - AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); - if (pkg == null) { - return false; - } - - PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( - filter.getPackageName()); - if (ps == null) { - return false; - } - - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); + protected boolean isFilterStopped(Pair<ParsedService, ParsedIntentInfo> filter, int userId) { + return ComponentResolver.isFilterStopped(filter, userId); } @Override protected boolean isPackageForFilter(String packageName, - ParsedServiceIntentInfo info) { - return packageName.equals(info.getPackageName()); + Pair<ParsedService, ParsedIntentInfo> info) { + return packageName.equals(info.first.getPackageName()); } @Override - protected ResolveInfo newResult(ParsedServiceIntentInfo filter, - int match, int userId) { + protected ResolveInfo newResult(Pair<ParsedService, ParsedIntentInfo> pair, int match, + int userId) { if (!sUserManager.exists(userId)) return null; - ParsedService service = null; + ParsedService service = pair.first; + ParsedIntentInfo filter = pair.second; - AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); - if (pkg != null && pkg.getServices() != null) { - for (ParsedService parsedService : pkg.getServices()) { - if (Objects.equals(parsedService.className, filter.getClassName())) { - service = parsedService; - } - } - } - - if (service == null) { + AndroidPackage pkg = sPackageManagerInternal.getPackage(service.getPackageName()); + if (pkg == null) { return null; } @@ -2005,13 +1910,13 @@ public class ComponentResolver { } PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( - filter.getPackageName()); + service.getPackageName()); if (ps == null) { return null; } final PackageUserState userState = ps.readUserState(userId); ServiceInfo si = PackageInfoUtils.generateServiceInfo(pkg, service, mFlags, - userState, userId); + userState, userId, ps); if (si == null) { return null; } @@ -2038,12 +1943,13 @@ public class ComponentResolver { res.filter = filter; } res.priority = filter.getPriority(); - res.preferredOrder = pkg.getPreferredOrder(); + // TODO(b/135203078): This field was unwritten and does nothing +// res.preferredOrder = pkg.getPreferredOrder(); res.match = match; - res.isDefault = filter.hasDefault; - res.labelRes = filter.labelRes; - res.nonLocalizedLabel = filter.nonLocalizedLabel; - res.icon = filter.icon; + res.isDefault = filter.isHasDefault(); + res.labelRes = filter.getLabelRes(); + res.nonLocalizedLabel = filter.getNonLocalizedLabel(); + res.icon = filter.getIcon(); res.system = res.serviceInfo.applicationInfo.isSystemApp(); return res; } @@ -2055,25 +1961,17 @@ public class ComponentResolver { @Override protected void dumpFilter(PrintWriter out, String prefix, - ParsedServiceIntentInfo filter) { - ParsedService service = null; - - AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); - if (pkg != null && pkg.getServices() != null) { - for (ParsedService parsedService : pkg.getServices()) { - if (Objects.equals(parsedService.className, filter.getClassName())) { - service = parsedService; - } - } - } + Pair<ParsedService, ParsedIntentInfo> pair) { + ParsedService service = pair.first; + ParsedIntentInfo filter = pair.second; out.print(prefix); out.print(Integer.toHexString(System.identityHashCode(service))); out.print(' '); - ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName()); + ComponentName.printShortString(out, service.getPackageName(), service.getClassName()); out.print(" filter "); out.print(Integer.toHexString(System.identityHashCode(filter))); - if (service != null && service.getPermission() != null) { + if (service.getPermission() != null) { out.print(" permission "); out.println(service.getPermission()); } else { out.println(); @@ -2081,22 +1979,30 @@ public class ComponentResolver { } @Override - protected Object filterToLabel(ParsedServiceIntentInfo filter) { + protected Object filterToLabel(Pair<ParsedService, ParsedIntentInfo> filter) { return filter; } protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - final ParsedServiceIntentInfo service = (ParsedServiceIntentInfo) label; + @SuppressWarnings("unchecked") final Pair<ParsedService, ParsedIntentInfo> pair = + (Pair<ParsedService, ParsedIntentInfo>) label; out.print(prefix); - out.print(Integer.toHexString(System.identityHashCode(service))); + out.print(Integer.toHexString(System.identityHashCode(pair.first))); out.print(' '); - ComponentName.printShortString(out, service.getPackageName(), service.getClassName()); + ComponentName.printShortString(out, pair.first.getPackageName(), + pair.first.getClassName()); if (count > 1) { out.print(" ("); out.print(count); out.print(" filters)"); } out.println(); } + @Override + protected IntentFilter getIntentFilter( + @NonNull Pair<ParsedService, ParsedIntentInfo> input) { + return input.second; + } + // Keys are String (activity class name), values are Activity. private final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>(); private int mFlags; @@ -2183,11 +2089,40 @@ public class ComponentResolver { i--; } } + + @Override + protected IntentFilter getIntentFilter( + @NonNull AuxiliaryResolveInfo.AuxiliaryFilter input) { + return input; + } + } + + private static boolean isFilterStopped(Pair<? extends ParsedComponent, ParsedIntentInfo> pair, + int userId) { + if (!sUserManager.exists(userId)) { + return true; + } + + AndroidPackage pkg = sPackageManagerInternal.getPackage(pair.first.getPackageName()); + if (pkg == null) { + return false; + } + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + pair.first.getPackageName()); + if (ps == null) { + return false; + } + + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return !ps.isSystem() && ps.getStopped(userId); } /** Generic to create an {@link Iterator} for a data type */ static class IterGenerator<E> { - public Iterator<E> generate(ParsedActivityIntentInfo info) { + public Iterator<E> generate(ParsedIntentInfo info) { return null; } } @@ -2195,7 +2130,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent actions */ static class ActionIterGenerator extends IterGenerator<String> { @Override - public Iterator<String> generate(ParsedActivityIntentInfo info) { + public Iterator<String> generate(ParsedIntentInfo info) { return info.actionsIterator(); } } @@ -2203,7 +2138,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent categories */ static class CategoriesIterGenerator extends IterGenerator<String> { @Override - public Iterator<String> generate(ParsedActivityIntentInfo info) { + public Iterator<String> generate(ParsedIntentInfo info) { return info.categoriesIterator(); } } @@ -2211,7 +2146,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent schemes */ static class SchemesIterGenerator extends IterGenerator<String> { @Override - public Iterator<String> generate(ParsedActivityIntentInfo info) { + public Iterator<String> generate(ParsedIntentInfo info) { return info.schemesIterator(); } } @@ -2219,7 +2154,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent authorities */ static class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> { @Override - public Iterator<IntentFilter.AuthorityEntry> generate(ParsedActivityIntentInfo info) { + public Iterator<IntentFilter.AuthorityEntry> generate(ParsedIntentInfo info) { return info.authoritiesIterator(); } } diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java index 0e0096dd1636..8e6b89a241fa 100644 --- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java +++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java @@ -18,6 +18,9 @@ package com.android.server.pm; +import android.annotation.NonNull; +import android.content.IntentFilter; + import com.android.server.IntentResolver; import java.util.List; @@ -40,4 +43,9 @@ class CrossProfileIntentResolver protected void sortResults(List<CrossProfileIntentFilter> results) { //We don't sort the results } + + @Override + protected IntentFilter getIntentFilter(@NonNull CrossProfileIntentFilter input) { + return input; + } } diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java index bcfe5773cfa4..cf85b0f3da7a 100644 --- a/services/core/java/com/android/server/pm/InstantAppRegistry.java +++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java @@ -24,8 +24,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.InstantAppInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageInfoUtils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; @@ -52,6 +50,8 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; import libcore.io.IoUtils; import libcore.util.HexEncoding; @@ -694,12 +694,13 @@ class InstantAppRegistry { final int packageCount = mService.mPackages.size(); for (int i = 0; i < packageCount; i++) { final AndroidPackage pkg = mService.mPackages.valueAt(i); - if (now - pkg.getLatestPackageUseTimeInMills() < maxInstalledCacheDuration) { + final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); + if (ps == null) { continue; } - final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); - if (ps == null) { + if (now - ps.getPkgState().getLatestPackageUseTimeInMills() + < maxInstalledCacheDuration) { continue; } @@ -733,30 +734,28 @@ class InstantAppRegistry { } else if (rhsPkg == null) { return 1; } else { - if (lhsPkg.getLatestPackageUseTimeInMills() > - rhsPkg.getLatestPackageUseTimeInMills()) { + final PackageSetting lhsPs = mService.getPackageSetting( + lhsPkg.getPackageName()); + if (lhsPs == null) { + return 0; + } + + final PackageSetting rhsPs = mService.getPackageSetting( + rhsPkg.getPackageName()); + if (rhsPs == null) { + return 0; + } + + if (lhsPs.getPkgState().getLatestPackageUseTimeInMills() > + rhsPs.getPkgState().getLatestPackageUseTimeInMills()) { return 1; - } else if (lhsPkg.getLatestPackageUseTimeInMills() < - rhsPkg.getLatestPackageUseTimeInMills()) { + } else if (lhsPs.getPkgState().getLatestPackageUseTimeInMills() < + rhsPs.getPkgState().getLatestPackageUseTimeInMills()) { return -1; + } else if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) { + return 1; } else { - final PackageSetting lhsPs = mService.getPackageSetting( - lhsPkg.getPackageName()); - if (lhsPs == null) { - return 0; - } - - final PackageSetting rhsPs = mService.getPackageSetting( - rhsPkg.getPackageName()); - if (rhsPs == null) { - return 0; - } - - if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) { - return 1; - } else { - return -1; - } + return -1; } } }); @@ -869,10 +868,9 @@ class InstantAppRegistry { // TODO(b/135203078): This may be broken due to inner mutability problems that were broken // as part of moving to PackageInfoUtils. Flags couldn't be determined. ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(ps.pkg, 0, - ps.readUserState(userId), userId); + ps.readUserState(userId), userId, ps); if (addApplicationInfo) { - return new InstantAppInfo(appInfo, - requestedPermissions, grantedPermissions); + return new InstantAppInfo(appInfo, requestedPermissions, grantedPermissions); } else { return new InstantAppInfo(appInfo.packageName, appInfo.loadLabel(mService.mContext.getPackageManager()), diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java index 0a065eba4309..2d42107bdd63 100644 --- a/services/core/java/com/android/server/pm/InstructionSets.java +++ b/services/core/java/com/android/server/pm/InstructionSets.java @@ -16,12 +16,14 @@ package com.android.server.pm; -import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.SystemProperties; import android.text.TextUtils; import android.util.ArraySet; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; + import dalvik.system.VMRuntime; import java.util.ArrayList; @@ -109,13 +111,4 @@ public class InstructionSets { return VMRuntime.getInstructionSet(abis.primary); } - - public static String getPrimaryInstructionSet(AndroidPackage pkg) { - if (pkg.getPrimaryCpuAbi() == null) { - return getPreferredInstructionSet(); - } - - return VMRuntime.getInstructionSet(pkg.getPrimaryCpuAbi()); - } - } diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java index c97d85df00ab..9dc545a40e4e 100644 --- a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java +++ b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java @@ -17,7 +17,7 @@ package com.android.server.pm; import android.content.pm.PackageManager; -import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.component.ParsedIntentInfo; import android.util.ArraySet; import android.util.Slog; @@ -35,7 +35,7 @@ public class IntentFilterVerificationState { private int mState; - private ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> mFilters = new ArrayList<>(); + private ArrayList<ParsedIntentInfo> mFilters = new ArrayList<>(); private ArraySet<String> mHosts = new ArraySet<>(); private int mUserId; @@ -66,7 +66,7 @@ public class IntentFilterVerificationState { setState(STATE_VERIFICATION_PENDING); } - public ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> getFilters() { + public ArrayList<ParsedIntentInfo> getFilters() { return mFilters; } @@ -123,7 +123,7 @@ public class IntentFilterVerificationState { return false; } - public void addFilter(ComponentParseUtils.ParsedActivityIntentInfo filter) { + public void addFilter(ParsedIntentInfo filter) { mFilters.add(filter); mHosts.addAll(filter.getHostsList()); } diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java index f9cfee172f36..dabcc35103ba 100644 --- a/services/core/java/com/android/server/pm/KeySetManagerService.java +++ b/services/core/java/com/android/server/pm/KeySetManagerService.java @@ -21,14 +21,13 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static com.android.server.pm.PackageManagerService.SCAN_INITIAL; import android.content.pm.PackageParser; -import android.content.pm.parsing.AndroidPackage; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Base64; import android.util.LongSparseArray; import android.util.Slog; -import com.android.internal.util.Preconditions; +import com.android.server.pm.parsing.pkg.AndroidPackage; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 3a162173a59f..261caba98e4f 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -16,7 +16,6 @@ package com.android.server.pm; -import android.Manifest.permission; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -51,7 +50,6 @@ import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutServiceInternal; import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; import android.content.pm.UserInfo; -import android.content.pm.parsing.AndroidPackage; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; @@ -76,6 +74,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; import com.android.server.SystemService; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.wm.ActivityTaskManagerInternal; import java.util.ArrayList; @@ -307,8 +306,8 @@ public class LauncherAppsService extends SystemService { final int callingUserId = injectCallingUserId(); if (targetUserId == callingUserId) return true; - if (mContext.checkCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL) - == PackageManager.PERMISSION_GRANTED) { + if (injectHasInteractAcrossUsersFullPermission(injectBinderCallingPid(), + injectBinderCallingUid())) { return true; } @@ -684,6 +683,15 @@ public class LauncherAppsService extends SystemService { callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; } + /** + * Returns true if the caller has the "INTERACT_ACROSS_USERS_FULL" permission. + */ + @VisibleForTesting + boolean injectHasInteractAcrossUsersFullPermission(int callingPid, int callingUid) { + return mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; + } + @Override public ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName, List shortcutIds, List<LocusId> locusIds, diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index ae7a4a7b81f5..2df4a920d5c2 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -22,7 +22,6 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import android.annotation.Nullable; import android.content.Context; import android.content.pm.IOtaDexopt; -import android.content.pm.parsing.AndroidPackage; import android.os.Environment; import android.os.RemoteException; import android.os.ResultReceiver; @@ -35,13 +34,17 @@ import android.util.Slog; import com.android.internal.logging.MetricsLogger; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexoptOptions; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import java.io.File; import java.io.FileDescriptor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; /** @@ -118,31 +121,33 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (mDexoptCommands != null) { throw new IllegalStateException("already called prepare()"); } - final List<AndroidPackage> important; - final List<AndroidPackage> others; + final List<PackageSetting> important; + final List<PackageSetting> others; synchronized (mPackageManagerService.mLock) { // Important: the packages we need to run with ab-ota compiler-reason. important = PackageManagerServiceUtils.getPackagesForDexopt( - mPackageManagerService.mPackages.values(), mPackageManagerService, + mPackageManagerService.mSettings.mPackages.values(), mPackageManagerService, DEBUG_DEXOPT); // Others: we should optimize this with the (first-)boot compiler-reason. - others = new ArrayList<>(mPackageManagerService.mPackages.values()); + others = new ArrayList<>(mPackageManagerService.mSettings.mPackages.values()); others.removeAll(important); + others.removeIf(PackageManagerServiceUtils.REMOVE_IF_NULL_PKG); // Pre-size the array list by over-allocating by a factor of 1.5. mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2); } - for (AndroidPackage p : important) { - mDexoptCommands.addAll(generatePackageDexopts(p, PackageManagerService.REASON_AB_OTA)); + for (PackageSetting pkgSetting : important) { + mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.pkg, pkgSetting, + PackageManagerService.REASON_AB_OTA)); } - for (AndroidPackage p : others) { + for (PackageSetting pkgSetting : others) { // We assume here that there are no core apps left. - if (p.isCoreApp()) { + if (pkgSetting.pkg.isCoreApp()) { throw new IllegalStateException("Found a core app that's not important"); } - mDexoptCommands.addAll( - generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT)); + mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.pkg, pkgSetting, + PackageManagerService.REASON_FIRST_BOOT)); } completeSize = mDexoptCommands.size(); @@ -150,8 +155,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (spaceAvailable < BULK_DELETE_THRESHOLD) { Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: " + PackageManagerServiceUtils.packagesToString(others)); - for (AndroidPackage pkg : others) { - mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName()); + for (PackageSetting pkg : others) { + mPackageManagerService.deleteOatArtifactsOfPackage(pkg.name); } } long spaceAvailableNow = getAvailableSpace(); @@ -161,16 +166,18 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (DEBUG_DEXOPT) { try { // Output some data about the packages. - AndroidPackage lastUsed = Collections.max(important, - (pkg1, pkg2) -> Long.compare( - pkg1.getLatestForegroundPackageUseTimeInMills(), - pkg2.getLatestForegroundPackageUseTimeInMills())); + PackageSetting lastUsed = Collections.max(important, + (pkgSetting1, pkgSetting2) -> Long.compare( + pkgSetting1.getPkgState() + .getLatestForegroundPackageUseTimeInMills(), + pkgSetting2.getPkgState() + .getLatestForegroundPackageUseTimeInMills())); Log.d(TAG, "A/B OTA: lastUsed time = " - + lastUsed.getLatestForegroundPackageUseTimeInMills()); + + lastUsed.getPkgState().getLatestForegroundPackageUseTimeInMills()); Log.d(TAG, "A/B OTA: deprioritized packages:"); - for (AndroidPackage pkg : others) { - Log.d(TAG, " " + pkg.getPackageName() + " - " - + pkg.getLatestForegroundPackageUseTimeInMills()); + for (PackageSetting pkgSetting : others) { + Log.d(TAG, " " + pkgSetting.name + " - " + + pkgSetting.getPkgState().getLatestForegroundPackageUseTimeInMills()); } } catch (Exception ignored) { } @@ -263,7 +270,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { * Generate all dexopt commands for the given package. */ private synchronized List<String> generatePackageDexopts(AndroidPackage pkg, - int compilationReason) { + PackageSetting pkgSetting, int compilationReason) { // Intercept and collect dexopt requests final List<String> commands = new ArrayList<String>(); final Installer collectingInstaller = new Installer(mContext, true) { @@ -333,7 +340,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer( collectingInstaller, mPackageManagerService.mInstallLock, mContext); - optimizer.performDexOpt(pkg, + optimizer.performDexOpt(pkg, pkgSetting, null /* ISAs */, null /* CompilerStats.PackageStats */, mPackageManagerService.getDexManager().getPackageUseInfoOrDefault( @@ -386,9 +393,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub { continue; } - final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), - pkg.getSecondaryCpuAbi()); - final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); + PackageSetting pkgSetting = mPackageManagerService.getPackageSetting(pkg.getPackageName()); + final String[] instructionSets = getAppDexInstructionSets( + AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting)); + final List<String> paths = + AndroidPackageUtils.getAllCodePathsExcludingResourceOnly(pkg); final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); for (String dexCodeInstructionSet : dexCodeInstructionSets) { for (String path : paths) { diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java index d7c161cc1a86..e355bb9f6e60 100644 --- a/services/core/java/com/android/server/pm/PackageAbiHelper.java +++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java @@ -17,11 +17,12 @@ package com.android.server.pm; import android.annotation.Nullable; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ParsedPackage; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.parsing.pkg.ParsedPackage; import java.io.File; import java.util.Set; @@ -33,7 +34,8 @@ public interface PackageAbiHelper { * Derive and get the location of native libraries for the given package, * which varies depending on where and how the package was installed. */ - NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, File appLib32InstallDir); + NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, PackageSetting pkgSetting, + File appLib32InstallDir); /** * Calculate the abis for a bundled app. These can uniquely be determined from the contents of @@ -48,9 +50,8 @@ public interface PackageAbiHelper { * * If {@code extractLibs} is true, native libraries are extracted from the app if required. */ - Pair<Abis, NativeLibraryPaths> derivePackageAbi( - AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs) - throws PackageManagerException; + Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, boolean isUpdatedSystemApp, + String cpuAbiOverride, boolean extractLibs) throws PackageManagerException; /** * Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all @@ -113,8 +114,9 @@ public interface PackageAbiHelper { this.secondary = secondary; } - Abis(AndroidPackage pkg) { - this(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi()); + Abis(AndroidPackage pkg, PackageSetting pkgSetting) { + this(AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting)); } public void applyTo(ParsedPackage pkg) { diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java index 482fc4944691..0bd8b28ee6ac 100644 --- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java +++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java @@ -27,9 +27,7 @@ import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet; import android.annotation.Nullable; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.Environment; import android.os.FileUtils; @@ -40,6 +38,8 @@ import android.util.Slog; import com.android.internal.content.NativeLibraryHelper; import com.android.internal.util.ArrayUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import dalvik.system.VMRuntime; @@ -131,11 +131,11 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { } @Override - public NativeLibraryPaths getNativeLibraryPaths( - AndroidPackage pkg, File appLib32InstallDir) { - return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.getCodePath(), - pkg.getBaseCodePath(), pkg.isSystemApp(), - pkg.isUpdatedSystemApp()); + public NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, PackageSetting pkgSetting, + File appLib32InstallDir) { + return getNativeLibraryPaths(new Abis(pkg, pkgSetting), appLib32InstallDir, + pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(), + pkgSetting.getPkgState().isUpdatedSystemApp()); } private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis, @@ -273,7 +273,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { // ABI that's higher on the list, i.e, a device that's configured to prefer // 64 bit apps will see a 64 bit primary ABI, - if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) == 0) { + if (!pkg.isMultiArch()) { Slog.e(PackageManagerService.TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch."); } @@ -293,18 +293,21 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { } @Override - public Pair<Abis, NativeLibraryPaths> derivePackageAbi( - AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs) + public Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, + boolean isUpdatedSystemApp, String cpuAbiOverride, boolean extractLibs) throws PackageManagerException { // Give ourselves some initial paths; we'll come back for another // pass once we've determined ABI below. - final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg), + String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(pkg); + String pkgRawSecondaryCpuAbi = AndroidPackageUtils.getRawSecondaryCpuAbi(pkg); + final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths( + new Abis(pkgRawPrimaryCpuAbi, pkgRawSecondaryCpuAbi), PackageManagerService.sAppLib32InstallDir, pkg.getCodePath(), - pkg.getBaseCodePath(), pkg.isSystemApp(), - pkg.isUpdatedSystemApp()); + pkg.getBaseCodePath(), pkg.isSystem(), + isUpdatedSystemApp); // We shouldn't attempt to extract libs from system app when it was not updated. - if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) { + if (pkg.isSystem() && !isUpdatedSystemApp) { extractLibs = false; } @@ -317,7 +320,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { NativeLibraryHelper.Handle handle = null; try { - handle = NativeLibraryHelper.Handle.create(pkg); + handle = AndroidPackageUtils.createNativeLibraryHandle(pkg); // TODO(multiArch): This can be null for apps that didn't go through the // usual installation process. We can calculate it again, like we // do during install time. @@ -329,17 +332,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { // Null out the abis so that they can be recalculated. primaryCpuAbi = null; secondaryCpuAbi = null; - if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0) { - // Warn if we've set an abiOverride for multi-lib packages.. - // By definition, we need to copy both 32 and 64 bit libraries for - // such packages. - if (pkg.getCpuAbiOverride() != null - && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals( - pkg.getCpuAbiOverride())) { - Slog.w(PackageManagerService.TAG, - "Ignoring abiOverride for multi arch application."); - } - + if (pkg.isMultiArch()) { int abi32 = PackageManager.NO_NATIVE_LIBRARIES; int abi64 = PackageManager.NO_NATIVE_LIBRARIES; if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { @@ -357,7 +350,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { } // Shared library native code should be in the APK zip aligned - if (abi32 >= 0 && pkg.isLibrary() && extractLibs) { + if (abi32 >= 0 && AndroidPackageUtils.isLibrary(pkg) && extractLibs) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Shared library native lib extraction not supported"); } @@ -384,7 +377,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { if (abi64 >= 0) { // Shared library native libs should be in the APK zip aligned - if (extractLibs && pkg.isLibrary()) { + if (extractLibs && AndroidPackageUtils.isLibrary(pkg)) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Shared library native lib extraction not supported"); } @@ -437,7 +430,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { if (copyRet >= 0) { // Shared libraries that have native libs must be multi-architecture - if (pkg.isLibrary()) { + if (AndroidPackageUtils.isLibrary(pkg)) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Shared library with native libs must be multiarch"); } @@ -461,9 +454,8 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi); return new Pair<>(abis, getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir, - pkg.getCodePath(), pkg.getBaseCodePath(), - pkg.isSystemApp(), - pkg.isUpdatedSystemApp())); + pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(), + isUpdatedSystemApp)); } /** @@ -484,9 +476,11 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { public String getAdjustedAbiForSharedUser( Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage) { String requiredInstructionSet = null; - if (scannedPackage != null && scannedPackage.getPrimaryCpuAbi() != null) { - requiredInstructionSet = VMRuntime.getInstructionSet( - scannedPackage.getPrimaryCpuAbi()); + if (scannedPackage != null) { + String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage); + if (pkgRawPrimaryCpuAbi != null) { + requiredInstructionSet = VMRuntime.getInstructionSet(pkgRawPrimaryCpuAbi); + } } PackageSetting requirer = null; @@ -533,7 +527,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { } else { // requirer == null implies that we're updating all ABIs in the set to // match scannedPackage. - adjustedAbi = scannedPackage.getPrimaryCpuAbi(); + adjustedAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage); } return adjustedAbi; } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 2b422211077b..e625aeffc0c6 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -38,13 +38,13 @@ import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReas import static dalvik.system.DexFile.getSafeModeCompilerFilter; import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; -import android.content.pm.parsing.AndroidPackage; import android.os.FileUtils; import android.os.PowerManager; import android.os.SystemClock; @@ -63,6 +63,8 @@ import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.DexoptUtils; import com.android.server.pm.dex.PackageDexUsage; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import dalvik.system.DexFile; @@ -112,7 +114,7 @@ public class PackageDexOptimizer { static boolean canOptimizePackage(AndroidPackage pkg) { // We do not dexopt a package with no code. - if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) == 0) { + if (!pkg.isHasCode()) { return false; } @@ -126,7 +128,7 @@ public class PackageDexOptimizer { * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are * synchronized on {@link #mInstallLock}. */ - int performDexOpt(AndroidPackage pkg, + int performDexOpt(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String[] instructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { if (pkg.getUid() == -1) { @@ -139,7 +141,7 @@ public class PackageDexOptimizer { synchronized (mInstallLock) { final long acquireTime = acquireWakeLockLI(pkg.getUid()); try { - return performDexOptLI(pkg, instructionSets, + return performDexOptLI(pkg, pkgSetting, instructionSets, packageStats, packageUseInfo, options); } finally { releaseWakeLockLI(acquireTime); @@ -152,19 +154,21 @@ public class PackageDexOptimizer { * It assumes the install lock is held. */ @GuardedBy("mInstallLock") - private int performDexOptLI(AndroidPackage pkg, + private int performDexOptLI(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String[] targetInstructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { - final List<SharedLibraryInfo> sharedLibraries = pkg.getUsesLibraryInfos(); + final List<SharedLibraryInfo> sharedLibraries = pkgSetting.getPkgState() + .getUsesLibraryInfos(); final String[] instructionSets = targetInstructionSets != null ? - targetInstructionSets : getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), - pkg.getSecondaryCpuAbi()); + targetInstructionSets : getAppDexInstructionSets( + AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting)); final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); - final List<String> paths = pkg.getAllCodePaths(); + final List<String> paths = AndroidPackageUtils.getAllCodePaths(pkg); int sharedGid = UserHandle.getSharedAppGid(pkg.getUid()); if (sharedGid == -1) { - Slog.wtf(TAG, "Well this is awkward; package " + pkg.getAppInfoName() + " had UID " + Slog.wtf(TAG, "Well this is awkward; package " + pkg.getPackageName() + " had UID " + pkg.getUid(), new Throwable()); sharedGid = android.os.Process.NOBODY_UID; } @@ -173,7 +177,7 @@ public class PackageDexOptimizer { // For each code path in the package, this array contains the class loader context that // needs to be passed to dexopt in order to ensure correct optimizations. boolean[] pathsWithCode = new boolean[paths.size()]; - pathsWithCode[0] = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0; + pathsWithCode[0] = pkg.isHasCode(); for (int i = 1; i < paths.size(); i++) { pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0; } @@ -232,10 +236,10 @@ public class PackageDexOptimizer { // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct // flags. - final int dexoptFlags = getDexFlags(pkg, compilerFilter, options); + final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, options); for (String dexCodeIsa : dexCodeInstructionSets) { - int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, + int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter, profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid, packageStats, options.isDowngrade(), profileName, dexMetadataPath, options.getCompilationReason()); @@ -260,8 +264,8 @@ public class PackageDexOptimizer { * DEX_OPT_SKIPPED if the path does not need to be deopt-ed. */ @GuardedBy("mInstallLock") - private int dexOptPath(AndroidPackage pkg, String path, String isa, - String compilerFilter, boolean profileUpdated, String classLoaderContext, + private int dexOptPath(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String path, + String isa, String compilerFilter, boolean profileUpdated, String classLoaderContext, int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade, String profileName, String dexMetadataPath, int compilationReason) { int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext, @@ -270,10 +274,11 @@ public class PackageDexOptimizer { return DEX_OPT_SKIPPED; } - String oatDir = getPackageOatDirIfSupported(pkg); + String oatDir = getPackageOatDirIfSupported(pkg, + pkgSetting.getPkgState().isUpdatedSystemApp()); Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path - + " pkg=" + pkg.getAppInfoPackageName() + " isa=" + isa + + " pkg=" + pkg.getPackageName() + " isa=" + isa + " dexoptFlags=" + printDexoptFlags(dexoptFlags) + " targetFilter=" + compilerFilter + " oatDir=" + oatDir + " classLoaderContext=" + classLoaderContext); @@ -284,9 +289,10 @@ public class PackageDexOptimizer { // TODO: Consider adding 2 different APIs for primary and secondary dexopt. // installd only uses downgrade flag for secondary dex files and ignores it for // primary dex files. + String seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting); mInstaller.dexopt(path, uid, pkg.getPackageName(), isa, dexoptNeeded, oatDir, dexoptFlags, compilerFilter, pkg.getVolumeUuid(), classLoaderContext, - pkg.getSeInfo(), false /* downgrade*/, pkg.getTargetSdkVersion(), + seInfo, false /* downgrade*/, pkg.getTargetSdkVersion(), profileName, dexMetadataPath, getAugmentedReasonName(compilationReason, dexMetadataPath != null)); @@ -449,13 +455,14 @@ public class PackageDexOptimizer { /** * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}. */ - void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg, + void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg, PackageSetting pkgSetting, PackageDexUsage.PackageUseInfo useInfo) { - final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), - pkg.getSecondaryCpuAbi()); + final String[] instructionSets = getAppDexInstructionSets( + AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting)); final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); - final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); + final List<String> paths = AndroidPackageUtils.getAllCodePathsExcludingResourceOnly(pkg); for (String path : paths) { pw.println("path: " + path); @@ -546,7 +553,7 @@ public class PackageDexOptimizer { private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter, boolean isUsedByOtherApps) { // When an app or priv app is configured to run out of box, only verify it. - if (pkg.isEmbeddedDexUsed() + if (pkg.isUseEmbeddedDex() || (pkg.isPrivileged() && DexManager.isPackageSelectedToRunOob(pkg.getPackageName()))) { return "verify"; @@ -562,8 +569,7 @@ public class PackageDexOptimizer { // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages // but that would have the downside of possibly producing a big odex files which would // be ignored anyway. - boolean vmSafeModeOrDebuggable = ((pkg.getFlags() & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0) - || ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0); + boolean vmSafeModeOrDebuggable = pkg.isVmSafeMode() || pkg.isDebuggable(); if (vmSafeModeOrDebuggable) { return getSafeModeCompilerFilter(targetCompilerFilter); @@ -583,14 +589,15 @@ public class PackageDexOptimizer { } private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) { - return getDexFlags(info.flags, info.getHiddenApiEnforcementPolicy(), - info.splitDependencies, info.requestsIsolatedSplitLoading(), compilerFilter, - options); + return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0, + info.getHiddenApiEnforcementPolicy(), info.splitDependencies, + info.requestsIsolatedSplitLoading(), compilerFilter, options); } - private int getDexFlags(AndroidPackage pkg, String compilerFilter, - DexoptOptions options) { - return getDexFlags(pkg.getFlags(), pkg.getHiddenApiEnforcementPolicy(), - pkg.getSplitDependencies(), pkg.requestsIsolatedSplitLoading(), compilerFilter, + private int getDexFlags(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, + String compilerFilter, DexoptOptions options) { + return getDexFlags(pkg.isDebuggable(), + AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting), + pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter, options); } @@ -598,10 +605,9 @@ public class PackageDexOptimizer { * Computes the dex flags that needs to be pass to installd for the given package and compiler * filter. */ - private int getDexFlags(int flags, int hiddenApiEnforcementPolicy, + private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy, SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading, String compilerFilter, DexoptOptions options) { - boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; // Profile guide compiled oat files should not be public unles they are based // on profiles from dex metadata archives. // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that @@ -699,8 +705,8 @@ public class PackageDexOptimizer { * not needed or unsupported for the package. */ @Nullable - private String getPackageOatDirIfSupported(AndroidPackage pkg) { - if (!pkg.canHaveOatDir()) { + private String getPackageOatDirIfSupported(AndroidPackage pkg, boolean isUpdatedSystemApp) { + if (!AndroidPackageUtils.canHaveOatDir(pkg, isUpdatedSystemApp)) { return null; } File codePath = new File(pkg.getCodePath()); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 0e554f8c3455..41988d6c5786 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -81,7 +81,6 @@ import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.dex.DexMetadataHelper; -import android.content.pm.parsing.AndroidPackage; import android.content.pm.parsing.ApkLiteParseUtils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -127,6 +126,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexManager; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.security.VerityUtils; import libcore.io.IoUtils; @@ -1169,12 +1169,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { */ private static boolean isIncrementalInstallationAllowed(String packageName) { final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); - final AndroidPackage existingPackage = pmi.getPackage(packageName); - if (existingPackage == null) { + final PackageSetting existingPkgSetting = pmi.getPackageSetting(packageName); + if (existingPkgSetting == null || existingPkgSetting.pkg == null) { return true; } - return !PackageManagerService.isSystemApp(existingPackage); + return !existingPkgSetting.pkg.isSystem() + && !existingPkgSetting.getPkgState().isUpdatedSystemApp(); } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2a3f7ed62845..92507e5a0e25 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -104,6 +104,9 @@ import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; import static com.android.internal.util.ArrayUtils.emptyIfNull; import static com.android.internal.util.ArrayUtils.filter; +import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME; +import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME; +import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME; import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; @@ -209,20 +212,17 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ApkParseUtils; -import android.content.pm.parsing.ComponentParseUtils; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; -import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; -import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; -import android.content.pm.parsing.ComponentParseUtils.ParsedService; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.PackageInfoUtils; -import android.content.pm.parsing.ParsedPackage; -import android.content.pm.parsing.library.PackageBackwardCompatibility; +import android.content.pm.parsing.PackageInfoWithoutStateUtils; +import android.content.pm.parsing.ParsingPackageRead; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedMainComponent; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedProcess; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; import android.content.res.Resources; import android.content.rollback.IRollbackManager; import android.database.ContentObserver; @@ -341,6 +341,13 @@ import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.PackageDexUsage; import com.android.server.pm.dex.ViewCompiler; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.parsing.library.PackageBackwardCompatibility; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.permission.BasePermission; import com.android.server.pm.permission.PermissionManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal; @@ -1011,13 +1018,13 @@ public class PackageManagerService extends IPackageManager.Stub private final AppsFilter mAppsFilter; - class PackageParserCallback implements PackageParser.Callback { + class PackageParserCallback extends PackageParser2.Callback { @Override public final boolean hasFeature(String feature) { return PackageManagerService.this.hasSystemFeature(feature, 0); } } - final PackageParser.Callback mPackageParserCallback = new PackageParserCallback(); + final PackageParser2.Callback mPackageParserCallback = new PackageParserCallback(); // Currently known shared libraries. final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>(); @@ -1080,7 +1087,7 @@ public class PackageManagerService extends IPackageManager.Stub boolean mResolverReplaced = false; private final @Nullable ComponentName mIntentFilterVerifierComponent; - private final @Nullable IntentFilterVerifier<ParsedActivityIntentInfo> mIntentFilterVerifier; + private final @Nullable IntentFilterVerifier<ParsedIntentInfo> mIntentFilterVerifier; private int mIntentFilterVerificationToken = 0; @@ -1141,7 +1148,7 @@ public class PackageManagerService extends IPackageManager.Stub void receiveVerificationResponse(int verificationId); } - private class IntentVerifierProxy implements IntentFilterVerifier<ParsedActivityIntentInfo> { + private class IntentVerifierProxy implements IntentFilterVerifier<ParsedIntentInfo> { private Context mContext; private ComponentName mIntentFilterVerifierComponent; private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<>(); @@ -1166,11 +1173,11 @@ public class PackageManagerService extends IPackageManager.Stub String packageName = ivs.getPackageName(); - ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters(); + ArrayList<ParsedIntentInfo> filters = ivs.getFilters(); final int filterCount = filters.size(); ArraySet<String> domainsSet = new ArraySet<>(); for (int m=0; m<filterCount; m++) { - ParsedActivityIntentInfo filter = filters.get(m); + ParsedIntentInfo filter = filters.get(m); domainsSet.addAll(filter.getHostsList()); } synchronized (mLock) { @@ -1222,14 +1229,14 @@ public class PackageManagerService extends IPackageManager.Stub final boolean verified = ivs.isVerified(); - ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters(); + ArrayList<ParsedIntentInfo> filters = ivs.getFilters(); final int count = filters.size(); if (DEBUG_DOMAIN_VERIFICATION) { Slog.i(TAG, "Received verification response " + verificationId + " for " + count + " filters, verified=" + verified); } for (int n=0; n<count; n++) { - ParsedActivityIntentInfo filter = filters.get(n); + ParsedIntentInfo filter = filters.get(n); filter.setVerified(verified); if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "IntentFilter " + filter.toString() @@ -1342,7 +1349,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean addOneIntentFilterVerification(int verifierUid, int userId, int verificationId, - ParsedActivityIntentInfo filter, String packageName) { + ParsedIntentInfo filter, String packageName) { if (!hasValidDomains(filter)) { return false; } @@ -1371,7 +1378,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static boolean hasValidDomains(ParsedActivityIntentInfo filter) { + private static boolean hasValidDomains(ParsedIntentInfo filter) { return filter.hasCategory(Intent.CATEGORY_BROWSABLE) && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)); @@ -2033,7 +2040,7 @@ public class PackageManagerService extends IPackageManager.Stub mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers); } - final String packageName = res.pkg.getAppInfoPackageName(); + final String packageName = res.pkg.getPackageName(); // Determine the set of users who are adding this package for // the first time vs. those who are seeing an update. @@ -2083,7 +2090,7 @@ public class PackageManagerService extends IPackageManager.Stub // Send added for users that see the package for the first time // sendPackageAddedForNewUsers also deals with system apps int appId = UserHandle.getAppId(res.uid); - boolean isSystem = res.pkg.isSystemApp(); + boolean isSystem = res.pkg.isSystem(); sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds); @@ -2147,7 +2154,7 @@ public class PackageManagerService extends IPackageManager.Stub null /*package*/, null /*extras*/, 0 /*flags*/, packageName /*targetPackage*/, null /*finishedReceiver*/, updateUserIds, instantUserIds); - } else if (launchedForRestore && !isSystemApp(res.pkg)) { + } else if (launchedForRestore && !res.pkg.isSystem()) { // First-install and we did a restore, so we're responsible for the // first-launch broadcast. if (DEBUG_BACKUP) { @@ -2159,14 +2166,14 @@ public class PackageManagerService extends IPackageManager.Stub } // Send broadcast package appeared if external for all users - if (isExternal(res.pkg)) { + if (res.pkg.isExternalStorage()) { if (!update) { final StorageManager storage = mInjector.getStorageManager(); VolumeInfo volume = storage.findVolumeByUuid( res.pkg.getStorageUuid().toString()); int packageExternalStorageType = - getPackageExternalStorageType(volume, isExternal(res.pkg)); + getPackageExternalStorageType(volume, res.pkg.isExternalStorage()); // If the package was installed externally, log it. if (packageExternalStorageType != StorageEnums.UNKNOWN) { FrameworkStatsLog.write( @@ -2499,15 +2506,18 @@ public class PackageManagerService extends IPackageManager.Stub packageName -> { synchronized (m.mInstallLock) { final AndroidPackage pkg; + final PackageSetting ps; final SharedUserSetting sharedUser; + final String oldSeInfo; synchronized (m.mLock) { - PackageSetting ps = m.mSettings.getPackageLPr(packageName); + ps = m.mSettings.getPackageLPr(packageName); if (ps == null) { Slog.e(TAG, "Failed to find package setting " + packageName); return; } pkg = ps.pkg; - sharedUser = ps.sharedUser; + sharedUser = ps.getSharedUser(); + oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps); } if (pkg == null) { @@ -2517,10 +2527,10 @@ public class PackageManagerService extends IPackageManager.Stub final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser, m.mInjector.getCompatibility()); - if (!newSeInfo.equals(pkg.getSeInfo())) { + if (!newSeInfo.equals(oldSeInfo)) { Slog.i(TAG, "Updating seInfo for package " + packageName + " from: " - + pkg.getSeInfo() + " to: " + newSeInfo); - pkg.mutate().setSeInfo(newSeInfo); + + oldSeInfo + " to: " + newSeInfo); + ps.getPkgState().setOverrideSeInfo(newSeInfo); m.prepareAppDataAfterInstallLIF(pkg); } } @@ -2859,12 +2869,8 @@ public class PackageManagerService extends IPackageManager.Stub final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM; - PackageParser packageParser = new PackageParser(); - packageParser.setSeparateProcesses(mSeparateProcesses); - packageParser.setOnlyCoreApps(mOnlyCore); - packageParser.setDisplayMetrics(mMetrics); - packageParser.setCacheDir(mCacheDir); - packageParser.setCallback(mPackageParserCallback); + PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore, + mMetrics, mCacheDir, mPackageParserCallback); ExecutorService executorService = ParallelPackageParser.makeExecutorService(); // Collect vendor/product/system_ext overlay packages. (Do this before scanning @@ -2902,7 +2908,9 @@ public class PackageManagerService extends IPackageManager.Stub // Parse overlay configuration files to set default enable state, mutability, and // priority of system overlays. - mOverlayConfig = OverlayConfig.initializeSystemInstance(mPmInternal::forEachPackage); + mOverlayConfig = OverlayConfig.initializeSystemInstance( + consumer -> mPmInternal.forEachPackage( + pkg -> consumer.accept(pkg, pkg.isSystem()))); // Prune any system packages that no longer exist. final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>(); @@ -2995,8 +3003,11 @@ public class PackageManagerService extends IPackageManager.Stub + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount) + " , cached: " + cachedSystemApps); if (mIsUpgrade && systemPackagesCount > 0) { - MetricsLogger.histogram(null, "ota_package_manager_system_app_avg_scan_time", - ((int) systemScanTime) / systemPackagesCount); + //CHECKSTYLE:OFF IndentationCheck + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, + BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME, + systemScanTime / systemPackagesCount); + //CHECKSTYLE:ON IndentationCheck } if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, @@ -3044,7 +3055,7 @@ public class PackageManagerService extends IPackageManager.Stub // special privileges removePackageLI(pkg, true); try { - final File codePath = new File(pkg.getAppInfoCodePath()); + final File codePath = new File(pkg.getCodePath()); scanPackageTracedLI(codePath, 0, scanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse updated, ex-system package: " @@ -3123,8 +3134,12 @@ public class PackageManagerService extends IPackageManager.Stub + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount) + " , cached: " + cachedNonSystemApps); if (mIsUpgrade && dataPackagesCount > 0) { - MetricsLogger.histogram(null, "ota_package_manager_data_app_avg_scan_time", - ((int) dataScanTime) / dataPackagesCount); + //CHECKSTYLE:OFF IndentationCheck + FrameworkStatsLog.write( + FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, + BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME, + dataScanTime / dataPackagesCount); + //CHECKSTYLE:OFF IndentationCheck } } mExpectingBetter.clear(); @@ -3149,7 +3164,7 @@ public class PackageManagerService extends IPackageManager.Stub // Now that we know all of the shared libraries, update all clients to have // the correct library paths. - updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages)); + updateAllSharedLibrariesLocked(null, null, Collections.unmodifiableMap(mPackages)); for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) { // NOTE: We ignore potential failures here during a system scan (like @@ -3177,7 +3192,7 @@ public class PackageManagerService extends IPackageManager.Stub // Now that we know all the packages we are keeping, // read and update their last usage times. - mPackageUsage.read(mPackages); + mPackageUsage.read(mSettings.mPackages); mCompilerStats.read(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, @@ -3385,8 +3400,10 @@ public class PackageManagerService extends IPackageManager.Stub } mDexManager.load(userPackages); if (mIsUpgrade) { - MetricsLogger.histogram(null, "ota_package_manager_init_time", - (int) (SystemClock.uptimeMillis() - startTime)); + FrameworkStatsLog.write( + FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, + BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME, + SystemClock.uptimeMillis() - startTime); } } // synchronized (mLock) } // synchronized (mInstallLock) @@ -3476,7 +3493,8 @@ public class PackageManagerService extends IPackageManager.Stub * APK will be installed and the package will be disabled. To recover from this situation, * the user will need to go into system settings and re-enable the package. */ - private boolean enableCompressedPackage(AndroidPackage stubPkg) { + private boolean enableCompressedPackage(AndroidPackage stubPkg, + @NonNull PackageSetting stubPkgSetting) { final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | PackageParser.PARSE_ENFORCE_CODE; synchronized (mInstallLock) { @@ -3487,7 +3505,7 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { prepareAppDataAfterInstallLIF(pkg); try { - updateSharedLibrariesLocked(pkg, null, + updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null, Collections.unmodifiableMap(mPackages)); } catch (PackageManagerException e) { Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e); @@ -4010,15 +4028,13 @@ public class PackageManagerService extends IPackageManager.Stub } ArraySet<String> domains = null; - if (pkg.getActivities() != null) { - for (ParsedActivity a : pkg.getActivities()) { - for (ParsedActivityIntentInfo filter : a.intents) { - if (hasValidDomains(filter)) { - if (domains == null) { - domains = new ArraySet<>(); - } - domains.addAll(filter.getHostsList()); + for (ParsedActivity a : pkg.getActivities()) { + for (ParsedIntentInfo filter : a.getIntents()) { + if (hasValidDomains(filter)) { + if (domains == null) { + domains = new ArraySet<>(); } + domains.addAll(filter.getHostsList()); } } } @@ -4146,7 +4162,7 @@ public class PackageManagerService extends IPackageManager.Stub ? Collections.emptySet() : permissionsState.getPermissions(userId); PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags, - ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId); + ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps); if (packageInfo == null) { return null; @@ -4208,7 +4224,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new SecurityException("Package " + packageName + " is currently frozen!"); } - if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) { + if (!userKeyUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.pkg)) { throw new SecurityException("Package " + packageName + " is not encryption aware!"); } } @@ -4289,7 +4305,7 @@ public class PackageManagerService extends IPackageManager.Stub } AndroidPackage p = mPackages.get(packageName); - if (matchFactoryOnly && p != null && !isSystemApp(p)) { + if (matchFactoryOnly && p != null && !p.isSystem()) { return null; } if (DEBUG_PACKAGE_INFO) @@ -4344,9 +4360,9 @@ public class PackageManagerService extends IPackageManager.Stub return false; } final boolean visibleToInstantApp = - (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; + (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean explicitlyVisibleToInstantApp = - (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; + (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && explicitlyVisibleToInstantApp; } else if (type == TYPE_RECEIVER) { final ParsedActivity activity = mComponentResolver.getReceiver(component); @@ -4354,20 +4370,18 @@ public class PackageManagerService extends IPackageManager.Stub return false; } final boolean visibleToInstantApp = - (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; + (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean explicitlyVisibleToInstantApp = - (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; + (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && !explicitlyVisibleToInstantApp; } else if (type == TYPE_SERVICE) { final ParsedService service = mComponentResolver.getService(component); return service != null - ? (service.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 - : false; + && (service.getFlags() & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; } else if (type == TYPE_PROVIDER) { final ParsedProvider provider = mComponentResolver.getProvider(component); return provider != null - ? (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 - : false; + && (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; } else if (type == TYPE_UNKNOWN) { return isComponentVisibleToInstantApp(component); } @@ -4574,7 +4588,7 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { final AndroidPackage p = mPackages.get(packageName); - if (p != null && p.isMatch(flags)) { + if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) { PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return -1; @@ -4604,7 +4618,7 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { final AndroidPackage p = mPackages.get(packageName); - if (p != null && p.isMatch(flags)) { + if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) { PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return null; @@ -4656,7 +4670,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags, - ps.readUserState(userId), userId); + ps.readUserState(userId), userId, ps); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(ps.pkg); } @@ -4708,7 +4722,7 @@ public class PackageManagerService extends IPackageManager.Stub } // Note: isEnabledLP() does not apply here - always return info ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo( - p, flags, ps.readUserState(userId), userId); + p, flags, ps.readUserState(userId), userId, ps); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(p); } @@ -5092,7 +5106,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } return PackageInfoUtils.generateActivityInfo(pkg, - a, flags, ps.readUserState(userId), userId); + a, flags, ps.readUserState(userId), userId, ps); } if (mResolveComponentName.equals(component)) { return PackageParser.generateActivityInfo( @@ -5140,8 +5154,8 @@ public class PackageManagerService extends IPackageManager.Stub ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) { return false; } - for (int i=0; i<a.intents.size(); i++) { - if (a.intents.get(i).match(intent.getAction(), resolvedType, intent.getScheme(), + for (int i=0; i< a.getIntents().size(); i++) { + if (a.getIntents().get(i).match(intent.getAction(), resolvedType, intent.getScheme(), intent.getData(), intent.getCategories(), TAG) >= 0) { return true; } @@ -5179,7 +5193,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } return PackageInfoUtils.generateActivityInfo(pkg, - a, flags, ps.readUserState(userId), userId); + a, flags, ps.readUserState(userId), userId, ps); } } return null; @@ -5400,7 +5414,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } return PackageInfoUtils.generateServiceInfo(pkg, - s, flags, ps.readUserState(userId), userId); + s, flags, ps.readUserState(userId), userId, ps); } } return null; @@ -5434,7 +5448,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } PackageUserState state = ps.readUserState(userId); - return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId); + return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId, ps); } } return null; @@ -8272,7 +8286,7 @@ public class PackageManagerService extends IPackageManager.Stub continue; } ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, effectiveFlags, - ps.readUserState(userId), userId); + ps.readUserState(userId), userId, ps); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(ps.pkg); } @@ -8298,7 +8312,7 @@ public class PackageManagerService extends IPackageManager.Stub continue; } ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags, - ps.readUserState(userId), userId); + ps.readUserState(userId), userId, ps); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(p); list.add(ai); @@ -8451,13 +8465,13 @@ public class PackageManagerService extends IPackageManager.Stub final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0) && p.isDirectBootAware(); - if ((p.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0 - && (!mSafeMode || isSystemApp(p)) + if (p.isPersistent() + && (!mSafeMode || p.isSystem()) && (matchesUnaware || matchesAware)) { PackageSetting ps = mSettings.mPackages.get(p.getPackageName()); if (ps != null) { ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags, - ps.readUserState(userId), userId); + ps.readUserState(userId), userId, ps); if (ai != null) { finalList.add(ai); } @@ -8563,7 +8577,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } final ParsedInstrumentation i = mInstrumentation.get(component); - return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags); + return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, callingUserId, ps); } } @@ -8576,11 +8590,12 @@ public class PackageManagerService extends IPackageManager.Stub if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return ParceledListSlice.emptyList(); } - return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags)); + return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags, + callingUserId)); } private @NonNull List<InstrumentationInfo> queryInstrumentationInternal(String targetPackage, - int flags) { + int flags, int userId) { ArrayList<InstrumentationInfo> finalList = new ArrayList<>(); // reader @@ -8590,10 +8605,12 @@ public class PackageManagerService extends IPackageManager.Stub final ParsedInstrumentation p = i.next(); if (targetPackage == null || targetPackage.equals(p.getTargetPackage())) { - AndroidPackage pkg = mPackages.get(p.getPackageName()); + String packageName = p.getPackageName(); + AndroidPackage pkg = mPackages.get(packageName); + PackageSetting pkgSetting = getPackageSetting(packageName); if (pkg != null) { InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p, - pkg, flags); + pkg, flags, userId, pkgSetting); if (ii != null) { finalList.add(ii); } @@ -8606,7 +8623,7 @@ public class PackageManagerService extends IPackageManager.Stub } private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, - long currentTime, PackageParser packageParser, ExecutorService executorService) { + long currentTime, PackageParser2 packageParser, ExecutorService executorService) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]"); try { scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService); @@ -8616,7 +8633,7 @@ public class PackageManagerService extends IPackageManager.Stub } private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime, - PackageParser packageParser, ExecutorService executorService) { + PackageParser2 packageParser, ExecutorService executorService) { final File[] files = scanDir.listFiles(); if (ArrayUtils.isEmpty(files)) { Log.d(TAG, "No files in app dir " + scanDir); @@ -8720,7 +8737,8 @@ public class PackageManagerService extends IPackageManager.Stub try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); - ApkParseUtils.collectCertificates(parsedPackage, skipVerify); + parsedPackage.setSigningDetails( + ParsingPackageUtils.collectCertificates(parsedPackage, skipVerify)); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { @@ -8774,16 +8792,13 @@ public class PackageManagerService extends IPackageManager.Stub private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile); - PackageParser pp = new PackageParser(); - pp.setSeparateProcesses(mSeparateProcesses); - pp.setOnlyCoreApps(mOnlyCore); - pp.setDisplayMetrics(mMetrics); - pp.setCallback(mPackageParserCallback); + PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null, + mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); final ParsedPackage parsedPackage; try { - parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false); + parsedPackage = pp.parsePackage(scanFile, parseFlags, false); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { @@ -8869,18 +8884,6 @@ public class PackageManagerService extends IPackageManager.Stub final boolean pkgAlreadyExists; PackageSetting pkgSetting; - // NOTE: installPackageLI() has the same code to setup the package's - // application info. This probably should be done lower in the call - // stack [such as scanPackageOnly()]. However, we verify the application - // info prior to that [in scanPackageNew()] and thus have to setup - // the application info early. - // TODO(b/135203078): Remove all of these application info calls - parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) - .setApplicationInfoCodePath(parsedPackage.getCodePath()) - .setApplicationInfoResourcePath(parsedPackage.getCodePath()) - .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) - .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); - synchronized (mLock) { renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage()); final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName); @@ -8933,8 +8936,8 @@ public class PackageManagerService extends IPackageManager.Stub final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting, null, disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */, null /* originalPkgSetting */, - null, parseFlags, scanFlags, isPlatformPackage, user); - applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage); + null, parseFlags, scanFlags, isPlatformPackage, user, null); + applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, true); final ScanResult scanResult = scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L); if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) { @@ -9068,7 +9071,7 @@ public class PackageManagerService extends IPackageManager.Stub } final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags - | SCAN_UPDATE_SIGNATURE, currentTime, user); + | SCAN_UPDATE_SIGNATURE, currentTime, user, null); if (scanResult.success) { synchronized (mLock) { boolean appIdCreated = false; @@ -9208,9 +9211,15 @@ public class PackageManagerService extends IPackageManager.Stub return; } - List<AndroidPackage> pkgs; + List<PackageSetting> pkgSettings; synchronized (mLock) { - pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this); + pkgSettings = PackageManagerServiceUtils.getPackagesForDexopt( + mSettings.mPackages.values(), this); + } + + List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size()); + for (int index = 0; index < pkgSettings.size(); index++) { + pkgs.add(pkgSettings.get(index).pkg); } final long startTime = System.nanoTime(); @@ -9255,7 +9264,7 @@ public class PackageManagerService extends IPackageManager.Stub boolean useProfileForDexopt = false; - if ((isFirstBoot() || isDeviceUpgrading()) && isSystemApp(pkg)) { + if ((isFirstBoot() || isDeviceUpgrading()) && pkg.isSystem()) { // Copy over initial preopt profiles since we won't get any JIT samples for methods // that are already compiled. File profileFile = new File(getPrebuildProfilePath(pkg)); @@ -9409,16 +9418,16 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private void notifyPackageUseLocked(String packageName, int reason) { - final AndroidPackage p = mPackages.get(packageName); - if (p == null) { + final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); + if (pkgSetting == null) { return; } - p.mutate().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis()); + pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis()); } @Override - public void notifyDexLoad(String loadingPackageName, List<String> classLoaderNames, - List<String> classPaths, String loaderIsa) { + public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap, + String loaderIsa) { int userId = UserHandle.getCallingUserId(); ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId); if (ai == null) { @@ -9426,7 +9435,7 @@ public class PackageManagerService extends IPackageManager.Stub + loadingPackageName + ", user=" + userId); return; } - mDexManager.notifyDexLoad(ai, classLoaderNames, classPaths, loaderIsa, userId); + mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId); } @Override @@ -9541,19 +9550,21 @@ public class PackageManagerService extends IPackageManager.Stub // if the package can now be considered up to date for the given filter. private int performDexOptInternal(DexoptOptions options) { AndroidPackage p; + PackageSetting pkgSetting; synchronized (mLock) { p = mPackages.get(options.getPackageName()); - if (p == null) { + pkgSetting = mSettings.getPackageLPr(options.getPackageName()); + if (p == null || pkgSetting == null) { // Package could not be found. Report failure. return PackageDexOptimizer.DEX_OPT_FAILED; } - mPackageUsage.maybeWriteAsync(mPackages); + mPackageUsage.maybeWriteAsync(mSettings.mPackages); mCompilerStats.maybeWriteAsync(); } long callingId = Binder.clearCallingIdentity(); try { synchronized (mInstallLock) { - return performDexOptInternalWithDependenciesLI(p, options); + return performDexOptInternalWithDependenciesLI(p, pkgSetting, options); } } finally { Binder.restoreCallingIdentity(callingId); @@ -9573,7 +9584,7 @@ public class PackageManagerService extends IPackageManager.Stub } private int performDexOptInternalWithDependenciesLI(AndroidPackage p, - DexoptOptions options) { + @NonNull PackageSetting pkgSetting, DexoptOptions options) { // Select the dex optimizer based on the force parameter. // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to // allocate an object here. @@ -9588,9 +9599,10 @@ public class PackageManagerService extends IPackageManager.Stub // at boot, or background job), the passed 'targetCompilerFilter' stays the same, // and the first package that uses the library will dexopt it. The // others will see that the compiled code for the library is up to date. - Collection<SharedLibraryInfo> deps = findSharedLibraries(p); - final String[] instructionSets = getAppDexInstructionSets(p.getPrimaryCpuAbi(), - p.getSecondaryCpuAbi()); + Collection<SharedLibraryInfo> deps = findSharedLibraries(pkgSetting); + final String[] instructionSets = getAppDexInstructionSets( + AndroidPackageUtils.getPrimaryCpuAbi(p, pkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(p, pkgSetting)); if (!deps.isEmpty()) { DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(), options.getCompilationReason(), options.getCompilerFilter(), @@ -9598,12 +9610,14 @@ public class PackageManagerService extends IPackageManager.Stub options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY); for (SharedLibraryInfo info : deps) { AndroidPackage depPackage = null; + PackageSetting depPackageSetting = null; synchronized (mLock) { depPackage = mPackages.get(info.getPackageName()); + depPackageSetting = mSettings.getPackageLPr(info.getPackageName()); } - if (depPackage != null) { + if (depPackage != null && depPackageSetting != null) { // TODO: Analyze and investigate if we (should) profile libraries. - pdo.performDexOpt(depPackage, instructionSets, + pdo.performDexOpt(depPackage, depPackageSetting, instructionSets, getOrCreateCompilerPackageStats(depPackage), mDexManager.getPackageUseInfoOrDefault(depPackage.getPackageName()), libraryOptions); @@ -9612,7 +9626,8 @@ public class PackageManagerService extends IPackageManager.Stub } } } - return pdo.performDexOpt(p, instructionSets, + + return pdo.performDexOpt(p, pkgSetting, instructionSets, getOrCreateCompilerPackageStats(p), mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options); } @@ -9655,11 +9670,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static List<SharedLibraryInfo> findSharedLibraries(AndroidPackage p) { - if (p.getUsesLibraryInfos() != null) { + private static List<SharedLibraryInfo> findSharedLibraries(PackageSetting pkgSetting) { + if (!pkgSetting.getPkgState().getUsesLibraryInfos().isEmpty()) { ArrayList<SharedLibraryInfo> retValue = new ArrayList<>(); Set<String> collectedNames = new HashSet<>(); - for (SharedLibraryInfo info : p.getUsesLibraryInfos()) { + for (SharedLibraryInfo info : pkgSetting.getPkgState().getUsesLibraryInfos()) { findSharedLibrariesRecursive(info, retValue, collectedNames); } return retValue; @@ -9682,15 +9697,16 @@ public class PackageManagerService extends IPackageManager.Stub } } - List<AndroidPackage> findSharedNonSystemLibraries(AndroidPackage pkg) { - List<SharedLibraryInfo> deps = findSharedLibraries(pkg); + List<PackageSetting> findSharedNonSystemLibraries(PackageSetting pkgSetting) { + List<SharedLibraryInfo> deps = findSharedLibraries(pkgSetting); if (!deps.isEmpty()) { - ArrayList<AndroidPackage> retValue = new ArrayList<>(); + List<PackageSetting> retValue = new ArrayList<>(); synchronized (mLock) { for (SharedLibraryInfo info : deps) { - AndroidPackage depPackage = mPackages.get(info.getPackageName()); - if (depPackage != null) { - retValue.add(depPackage); + PackageSetting depPackageSetting = + mSettings.getPackageLPr(info.getPackageName()); + if (depPackageSetting != null && depPackageSetting.pkg != null) { + retValue.add(depPackageSetting); } } } @@ -9762,7 +9778,7 @@ public class PackageManagerService extends IPackageManager.Stub } public void shutdown() { - mPackageUsage.writeNow(mPackages); + mPackageUsage.writeNow(mSettings.mPackages); mCompilerStats.writeNow(); mDexManager.writePackageDexUsageNow(); PackageWatchdog.getInstance(mContext).writeNow(); @@ -9808,9 +9824,11 @@ public class PackageManagerService extends IPackageManager.Stub enforceSystemOrRoot("forceDexOpt"); AndroidPackage pkg; + PackageSetting pkgSetting; synchronized (mLock) { pkg = mPackages.get(packageName); - if (pkg == null) { + pkgSetting = mSettings.getPackageLPr(packageName); + if (pkg == null || pkgSetting == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } } @@ -9820,8 +9838,7 @@ public class PackageManagerService extends IPackageManager.Stub // Whoever is calling forceDexOpt wants a compiled package. // Don't use profiles since that may cause compilation to be skipped. - final int res = performDexOptInternalWithDependenciesLI( - pkg, + final int res = performDexOptInternalWithDependenciesLI(pkg, pkgSetting, new DexoptOptions(packageName, getDefaultCompilerFilter(), DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE)); @@ -9957,7 +9974,7 @@ public class PackageManagerService extends IPackageManager.Stub // Or: // - Package manager is in a state where package isn't scanned yet. This will // get called again after scanning to fix the dependencies. - if (pkg.isLibrary()) { + if (AndroidPackageUtils.isLibrary(pkg)) { if (pkg.getStaticSharedLibName() != null) { SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion()); @@ -9978,40 +9995,44 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private void addSharedLibraryLPr(AndroidPackage pkg, Set<String> usesLibraryFiles, - SharedLibraryInfo libInfo, AndroidPackage changingLib) { + SharedLibraryInfo libInfo, @Nullable AndroidPackage changingLib, + @Nullable PackageSetting changingLibSetting) { if (libInfo.getPath() != null) { usesLibraryFiles.add(libInfo.getPath()); return; } - AndroidPackage p = mPackages.get(libInfo.getPackageName()); + AndroidPackage pkgForCodePaths = mPackages.get(libInfo.getPackageName()); + PackageSetting pkgSetting = mSettings.getPackageLPr(libInfo.getPackageName()); if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) { // If we are doing this while in the middle of updating a library apk, // then we need to make sure to use that new apk for determining the // dependencies here. (We haven't yet finished committing the new apk // to the package manager state.) - if (p == null || p.getPackageName().equals(changingLib.getPackageName())) { - p = changingLib; + if (pkgForCodePaths == null + || pkgForCodePaths.getPackageName().equals(changingLib.getPackageName())) { + pkgForCodePaths = changingLib; + pkgSetting = changingLibSetting; } } - if (p != null) { - usesLibraryFiles.addAll(p.getAllCodePaths()); + if (pkgForCodePaths != null) { + usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(pkgForCodePaths)); // If the package provides libraries, add the dependency to them. - applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> { - definingLibrary.addDependency(dependency); - }); - if (p.getUsesLibraryFiles() != null) { - Collections.addAll(usesLibraryFiles, p.getUsesLibraryFiles()); + applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, SharedLibraryInfo::addDependency); + if (pkgSetting != null) { + usesLibraryFiles.addAll(pkgSetting.getPkgState().getUsesLibraryFiles()); } } } @GuardedBy("mLock") - private void updateSharedLibrariesLocked(AndroidPackage pkg, - AndroidPackage changingLib, Map<String, AndroidPackage> availablePackages) - throws PackageManagerException { - final ArrayList<SharedLibraryInfo> sharedLibraryInfos = - collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null); - executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos); + private void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting, + @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting, + Map<String, AndroidPackage> availablePackages) + throws PackageManagerException { + final ArrayList<SharedLibraryInfo> sharedLibraryInfos = collectSharedLibraryInfos( + pkgSetting.pkg, availablePackages, mSharedLibraries, null); + executeSharedLibrariesUpdateLPr(pkg, pkgSetting, changingLib, changingLibSetting, + sharedLibraryInfos); } private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(AndroidPackage pkg, @@ -10026,18 +10047,18 @@ public class PackageManagerService extends IPackageManager.Stub // that libraries are searched in the correct order) and must have no // duplicates. ArrayList<SharedLibraryInfo> usesLibraryInfos = null; - if (pkg.getUsesLibraries() != null) { + if (!pkg.getUsesLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null, pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null, availablePackages, existingLibraries, newLibraries); } - if (pkg.getUsesStaticLibraries() != null) { + if (!pkg.getUsesStaticLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(), pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(), pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } - if (pkg.getUsesOptionalLibraries() != null) { + if (!pkg.getUsesOptionalLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(), null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); @@ -10046,25 +10067,27 @@ public class PackageManagerService extends IPackageManager.Stub } private void executeSharedLibrariesUpdateLPr(AndroidPackage pkg, - AndroidPackage changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) { + @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib, + @Nullable PackageSetting changingLibSetting, + ArrayList<SharedLibraryInfo> usesLibraryInfos) { // If the package provides libraries, clear their old dependencies. // This method will set them up again. applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> { definingLibrary.clearDependencies(); }); if (usesLibraryInfos != null) { - pkg.mutate().setUsesLibraryInfos(usesLibraryInfos); + pkgSetting.getPkgState().setUsesLibraryInfos(usesLibraryInfos); // Use LinkedHashSet to preserve the order of files added to // usesLibraryFiles while eliminating duplicates. Set<String> usesLibraryFiles = new LinkedHashSet<>(); for (SharedLibraryInfo libInfo : usesLibraryInfos) { - addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib); + addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib, + changingLibSetting); } - pkg.mutate().setUsesLibraryFiles(usesLibraryFiles.toArray( - new String[usesLibraryFiles.size()])); + pkgSetting.getPkgState().setUsesLibraryFiles(new ArrayList<>(usesLibraryFiles)); } else { - pkg.mutate().setUsesLibraryInfos(null) - .setUsesLibraryFiles(null); + pkgSetting.getPkgState().setUsesLibraryInfos(Collections.emptyList()) + .setUsesLibraryFiles(Collections.emptyList()); } } @@ -10180,27 +10203,32 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private ArrayList<AndroidPackage> updateAllSharedLibrariesLocked( - AndroidPackage updatedPkg, + @Nullable AndroidPackage updatedPkg, @Nullable PackageSetting updatedPkgSetting, Map<String, AndroidPackage> availablePackages) { ArrayList<AndroidPackage> resultList = null; // Set of all descendants of a library; used to eliminate cycles ArraySet<String> descendants = null; // The current list of packages that need updating - ArrayList<AndroidPackage> needsUpdating = null; - if (updatedPkg != null) { + List<Pair<AndroidPackage, PackageSetting>> needsUpdating = null; + if (updatedPkg != null && updatedPkgSetting != null) { needsUpdating = new ArrayList<>(1); - needsUpdating.add(updatedPkg); + needsUpdating.add(Pair.create(updatedPkg, updatedPkgSetting)); } do { - final AndroidPackage changingPkg = + final Pair<AndroidPackage, PackageSetting> changingPkgPair = (needsUpdating == null) ? null : needsUpdating.remove(0); + final AndroidPackage changingPkg = changingPkgPair != null + ? changingPkgPair.first : null; + final PackageSetting changingPkgSetting = changingPkgPair != null + ? changingPkgPair.second : null; for (int i = mPackages.size() - 1; i >= 0; --i) { final AndroidPackage pkg = mPackages.valueAt(i); + final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName()); if (changingPkg != null && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames()) && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames()) && !ArrayUtils.contains(pkg.getUsesStaticLibraries(), - changingPkg.getStaticSharedLibName())) { + changingPkg.getStaticSharedLibName())) { continue; } if (resultList == null) { @@ -10214,19 +10242,20 @@ public class PackageManagerService extends IPackageManager.Stub } if (!descendants.contains(pkg.getPackageName())) { descendants.add(pkg.getPackageName()); - needsUpdating.add(pkg); + needsUpdating.add(Pair.create(pkg, pkgSetting)); } } try { - updateSharedLibrariesLocked(pkg, changingPkg, availablePackages); + updateSharedLibrariesLocked(pkg, pkgSetting, changingPkg, + changingPkgSetting, availablePackages); } catch (PackageManagerException e) { // If a system app update or an app and a required lib missing we // delete the package and for updated system apps keep the data as // it is better for the user to reinstall than to be in an limbo // state. Also libs disappearing under an app should never happen // - just in case. - if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) { - final int flags = pkg.isUpdatedSystemApp() + if (!pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) { + final int flags = pkgSetting.getPkgState().isUpdatedSystemApp() ? PackageManager.DELETE_KEEP_DATA : 0; deletePackageLIF(pkg.getPackageName(), null, true, mUserManager.getUserIds(), flags, null, @@ -10242,10 +10271,11 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy({"mInstallLock", "mLock"}) private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, - @Nullable UserHandle user) throws PackageManagerException { + @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); try { - return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user); + return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user, + cpuAbiOverride); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -10320,6 +10350,9 @@ public class PackageManagerService extends IPackageManager.Stub @Nullable public final UserHandle user; /** Whether or not the platform package is being scanned */ public final boolean isPlatformPackage; + /** Override value for package ABI if set during install */ + @Nullable + public final String cpuAbiOverride; public ScanRequest( @NonNull ParsedPackage parsedPackage, @Nullable SharedUserSetting sharedUserSetting, @@ -10331,7 +10364,8 @@ public class PackageManagerService extends IPackageManager.Stub @ParseFlags int parseFlags, @ScanFlags int scanFlags, boolean isPlatformPackage, - @Nullable UserHandle user) { + @Nullable UserHandle user, + @Nullable String cpuAbiOverride) { this.parsedPackage = parsedPackage; this.oldPkg = oldPkg; this.pkgSetting = pkgSetting; @@ -10344,6 +10378,7 @@ public class PackageManagerService extends IPackageManager.Stub this.scanFlags = scanFlags; this.isPlatformPackage = isPlatformPackage; this.user = user; + this.cpuAbiOverride = cpuAbiOverride; } } @@ -10451,7 +10486,7 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy({"mInstallLock", "mLock"}) private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, - @Nullable UserHandle user) throws PackageManagerException { + @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException { final String renamedPkgName = mSettings.getRenamedPackageLPr( parsedPackage.getRealPackage()); @@ -10472,7 +10507,13 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, parsedPackage); synchronized (mLock) { - applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage); + boolean isUpdatedSystemApp; + if (pkgSetting != null) { + isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp(); + } else { + isUpdatedSystemApp = disabledPkgSetting != null; + } + applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, isUpdatedSystemApp); assertPackageIsValid(parsedPackage, parseFlags, scanFlags); SharedUserSetting sharedUserSetting = null; @@ -10492,7 +10533,8 @@ public class PackageManagerService extends IPackageManager.Stub final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting, pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting, originalPkgSetting, realPkgName, parseFlags, scanFlags, - Objects.equals(parsedPackage.getPackageName(), platformPackageName), user); + Objects.equals(parsedPackage.getPackageName(), platformPackageName), user, + cpuAbiOverride); return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime); } } @@ -10594,7 +10636,8 @@ public class PackageManagerService extends IPackageManager.Stub } if (reconciledPkg.collectedSharedLibraryInfos != null) { - executeSharedLibrariesUpdateLPr(pkg, null, reconciledPkg.collectedSharedLibraryInfos); + executeSharedLibrariesUpdateLPr(pkg, pkgSetting, null, null, + reconciledPkg.collectedSharedLibraryInfos); } final KeySetManagerService ksms = mSettings.mKeySetManagerService; @@ -10607,7 +10650,7 @@ public class PackageManagerService extends IPackageManager.Stub } pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails; - if (pkg.getAdoptPermissions() != null) { + if (!pkg.getAdoptPermissions().isEmpty()) { // This package wants to adopt ownership of permissions from // another package. for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) { @@ -10661,8 +10704,7 @@ public class PackageManagerService extends IPackageManager.Stub /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */ private static boolean isPackageRenamed(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { - return pkg.getOriginalPackages() != null - && pkg.getOriginalPackages().contains(renamedPkgName); + return pkg.getOriginalPackages().contains(renamedPkgName); } /** @@ -10714,8 +10756,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage, @NonNull String renamedPackageName) { - if (parsedPackage.getOriginalPackages() == null - || !parsedPackage.getOriginalPackages().contains(renamedPackageName) + if (!parsedPackage.getOriginalPackages().contains(renamedPackageName) || parsedPackage.getPackageName().equals(renamedPackageName)) { return; } @@ -10744,19 +10785,21 @@ public class PackageManagerService extends IPackageManager.Stub } ps.primaryCpuAbiString = adjustedAbi; - if (ps.pkg != null && !TextUtils.equals(adjustedAbi, ps.pkg.getPrimaryCpuAbi())) { - ps.pkg.mutate().setPrimaryCpuAbi(adjustedAbi); - if (DEBUG_ABI_SELECTION) { - Slog.i(TAG, - "Adjusting ABI for " + ps.name + " to " + adjustedAbi - + " (scannedPackage=" - + (scannedPackage != null ? scannedPackage : "null") - + ")"); - } - if (changedAbiCodePath == null) { - changedAbiCodePath = new ArrayList<>(); + if (ps.pkg != null) { + if (!TextUtils.equals(adjustedAbi, + AndroidPackageUtils.getRawPrimaryCpuAbi(ps.pkg))) { + if (DEBUG_ABI_SELECTION) { + Slog.i(TAG, + "Adjusting ABI for " + ps.name + " to " + adjustedAbi + + " (scannedPackage=" + + (scannedPackage != null ? scannedPackage : "null") + + ")"); + } + if (changedAbiCodePath == null) { + changedAbiCodePath = new ArrayList<>(); + } + changedAbiCodePath.add(ps.codePathString); } - changedAbiCodePath.add(ps.codePathString); } } } @@ -10766,6 +10809,8 @@ public class PackageManagerService extends IPackageManager.Stub /** * Sets the enabled state of components configured through {@link SystemConfig}. * This modifies the {@link PackageSetting} object. + * + * TODO(b/135203078): Move this to package parsing **/ static void configurePackageComponents(AndroidPackage pkg) { final ArrayMap<String, Boolean> componentsEnabledStates = SystemConfig.getInstance() @@ -10776,7 +10821,7 @@ public class PackageManagerService extends IPackageManager.Stub for (int i = ArrayUtils.size(pkg.getActivities()) - 1; i >= 0; i--) { final ParsedActivity component = pkg.getActivities().get(i); - final Boolean enabled = componentsEnabledStates.get(component.className); + final Boolean enabled = componentsEnabledStates.get(component.getName()); if (enabled != null) { component.setEnabled(enabled); } @@ -10784,7 +10829,7 @@ public class PackageManagerService extends IPackageManager.Stub for (int i = ArrayUtils.size(pkg.getReceivers()) - 1; i >= 0; i--) { final ParsedActivity component = pkg.getReceivers().get(i); - final Boolean enabled = componentsEnabledStates.get(component.className); + final Boolean enabled = componentsEnabledStates.get(component.getName()); if (enabled != null) { component.setEnabled(enabled); } @@ -10792,7 +10837,7 @@ public class PackageManagerService extends IPackageManager.Stub for (int i = ArrayUtils.size(pkg.getProviders()) - 1; i >= 0; i--) { final ParsedProvider component = pkg.getProviders().get(i); - final Boolean enabled = componentsEnabledStates.get(component.className); + final Boolean enabled = componentsEnabledStates.get(component.getName()); if (enabled != null) { component.setEnabled(enabled); } @@ -10800,7 +10845,7 @@ public class PackageManagerService extends IPackageManager.Stub for (int i = ArrayUtils.size(pkg.getServices()) - 1; i >= 0; i--) { final ParsedService component = pkg.getServices().get(i); - final Boolean enabled = componentsEnabledStates.get(component.className); + final Boolean enabled = componentsEnabledStates.get(component.getName()); if (enabled != null) { component.setEnabled(enabled); } @@ -10848,8 +10893,8 @@ public class PackageManagerService extends IPackageManager.Stub } // Initialize package source and resource directories - final File destCodeFile = new File(parsedPackage.getAppInfoCodePath()); - final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath()); + final File destCodeFile = new File(parsedPackage.getCodePath()); + final File destResourceFile = new File(parsedPackage.getCodePath()); // We keep references to the derived CPU Abis from settings in oder to reuse // them in the case where we're not upgrading or booting for the first time. @@ -10878,10 +10923,13 @@ public class PackageManagerService extends IPackageManager.Stub } String[] usesStaticLibraries = null; - if (parsedPackage.getUsesStaticLibraries() != null) { + if (!parsedPackage.getUsesStaticLibraries().isEmpty()) { usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()]; parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries); } + // TODO(b/135203078): Remove appInfoFlag usage in favor of individually assigned booleans + // to avoid adding something that's unsupported due to lack of state, since it's called + // with null. final boolean createNewPackage = (pkgSetting == null); if (createNewPackage) { final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; @@ -10890,16 +10938,18 @@ public class PackageManagerService extends IPackageManager.Stub pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(), originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(), - parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(), - parsedPackage.getVersionCode(), parsedPackage.getFlags(), - parsedPackage.getPrivateFlags(), user, true /*allowInstall*/, instantApp, + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage), + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage), + parsedPackage.getVersionCode(), + PackageInfoWithoutStateUtils.appInfoFlags(parsedPackage), + PackageInfoWithoutStateUtils.appInfoPrivateFlags(parsedPackage), + user, true /*allowInstall*/, instantApp, virtualPreload, UserManagerService.getInstance(), usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups()); } else { // make a deep copy to avoid modifying any existing system state. pkgSetting = new PackageSetting(pkgSetting); - // TODO(b/135203078): Remove entirely. Set package directly. - parsedPackage.setPackageSettingCallback(pkgSetting); + pkgSetting.pkg = parsedPackage; // REMOVE SharedUserSetting from method; update in a separate call. // @@ -10908,8 +10958,10 @@ public class PackageManagerService extends IPackageManager.Stub // to null here, only to reset them at a later point. Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting, destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(), - parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(), - parsedPackage.getFlags(), parsedPackage.getPrivateFlags(), + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage), + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage), + PackageInfoWithoutStateUtils.appInfoFlags(parsedPackage), + PackageInfoWithoutStateUtils.appInfoPrivateFlags(parsedPackage), UserManagerService.getInstance(), usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups()); @@ -10938,35 +10990,28 @@ public class PackageManagerService extends IPackageManager.Stub if (disabledPkgSetting != null || (0 != (scanFlags & SCAN_NEW_INSTALL) && pkgSetting != null && pkgSetting.isSystem())) { - parsedPackage.mutate().setUpdatedSystemApp(true); + pkgSetting.getPkgState().setUpdatedSystemApp(true); } parsedPackage .setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting, injector.getCompatibility())) .setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState( - userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId))) - .setProcessName(fixProcessName(parsedPackage.getPackageName(), - parsedPackage.getProcessName())); - - if (!isPlatformPackage) { - // Get all of our default paths setup - parsedPackage.initForUser(UserHandle.USER_SYSTEM); - } + userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId))); if (parsedPackage.isSystem()) { configurePackageComponents(parsedPackage); } - final String cpuAbiOverride = deriveAbiOverride(parsedPackage.getCpuAbiOverride(), - pkgSetting); + final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride, pkgSetting); if ((scanFlags & SCAN_NEW_INSTALL) == 0) { if (needToDeriveAbi) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi"); - final boolean extractNativeLibs = !parsedPackage.isLibrary(); + final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage); final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi = - packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride, + packageAbiHelper.derivePackageAbi(parsedPackage, + pkgSetting.getPkgState().isUpdatedSystemApp(), cpuAbiOverride, extractNativeLibs); derivedAbi.first.applyTo(parsedPackage); derivedAbi.second.applyTo(parsedPackage); @@ -10975,14 +11020,16 @@ public class PackageManagerService extends IPackageManager.Stub // Some system apps still use directory structure for native libraries // in which case we might end up not detecting abi solely based on apk // structure. Try to detect abi based on directory structure. - if (isSystemApp(parsedPackage) && !parsedPackage.isUpdatedSystemApp() && - parsedPackage.getPrimaryCpuAbi() == null) { + + String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage); + if (parsedPackage.isSystem() && !pkgSetting.getPkgState().isUpdatedSystemApp() && + pkgRawPrimaryCpuAbi == null) { final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis( parsedPackage); abis.applyTo(parsedPackage); abis.applyTo(pkgSetting); final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = - packageAbiHelper.getNativeLibraryPaths(parsedPackage, + packageAbiHelper.getNativeLibraryPaths(parsedPackage, pkgSetting, sAppLib32InstallDir); nativeLibraryPaths.applyTo(parsedPackage); } @@ -10994,13 +11041,16 @@ public class PackageManagerService extends IPackageManager.Stub .setSecondaryCpuAbi(secondaryCpuAbiFromSettings); final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = - packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir); + packageAbiHelper.getNativeLibraryPaths(parsedPackage, + pkgSetting, sAppLib32InstallDir); nativeLibraryPaths.applyTo(parsedPackage); if (DEBUG_ABI_SELECTION) { Slog.i(TAG, "Using ABIS and native lib paths from settings : " + - parsedPackage.getPackageName() + " " + parsedPackage.getPrimaryCpuAbi() - + ", " + parsedPackage.getSecondaryCpuAbi()); + parsedPackage.getPackageName() + " " + + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage) + + ", " + + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage)); } } } else { @@ -11017,7 +11067,8 @@ public class PackageManagerService extends IPackageManager.Stub // ABIs we determined during compilation, but the path will depend on the final // package path (after the rename away from the stage path). final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = - packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir); + packageAbiHelper.getNativeLibraryPaths(parsedPackage, pkgSetting, + sAppLib32InstallDir); nativeLibraryPaths.applyTo(parsedPackage); } @@ -11035,20 +11086,16 @@ public class PackageManagerService extends IPackageManager.Stub // would've already compiled the app without taking the package setting into // account. if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) { - if (cpuAbiOverride == null && parsedPackage.getPackageName() != null) { + if (cpuAbiOverride == null) { Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride + " for package " + parsedPackage.getPackageName()); } } - pkgSetting.primaryCpuAbiString = parsedPackage.getPrimaryCpuAbi(); - pkgSetting.secondaryCpuAbiString = parsedPackage.getSecondaryCpuAbi(); + pkgSetting.primaryCpuAbiString = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage); + pkgSetting.secondaryCpuAbiString = AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage); pkgSetting.cpuAbiOverrideString = cpuAbiOverride; - // Copy the derived override back to the parsed package, so that we can - // update the package settings accordingly. - parsedPackage.setCpuAbiOverride(cpuAbiOverride); - if (DEBUG_ABI_SELECTION) { Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName() + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", isa=" @@ -11061,8 +11108,8 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_ABI_SELECTION) { Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" + - " primary=" + parsedPackage.getPrimaryCpuAbi() + - " secondary=" + parsedPackage.getSecondaryCpuAbi()); + " primary=" + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage) + + " secondary=" + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage)); } if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) { @@ -11104,13 +11151,13 @@ public class PackageManagerService extends IPackageManager.Stub } pkgSetting.setTimeStamp(scanFileTime); // TODO(b/135203078): Remove, move to constructor - parsedPackage.setPackageSettingCallback(pkgSetting); - pkgSetting.pkgFlags = parsedPackage.getFlags(); + pkgSetting.pkg = parsedPackage; + pkgSetting.pkgFlags = PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting); if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) { pkgSetting.versionCode = parsedPackage.getLongVersionCode(); } // Update volume if needed - final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid(); + final String volumeUuid = parsedPackage.getVolumeUuid(); if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) { Slog.i(PackageManagerService.TAG, "Update" + (pkgSetting.isSystem() ? " system" : "") @@ -11122,14 +11169,15 @@ public class PackageManagerService extends IPackageManager.Stub SharedLibraryInfo staticSharedLibraryInfo = null; if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) { - staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage); + staticSharedLibraryInfo = + AndroidPackageUtils.createSharedLibraryForStatic(parsedPackage); } List<SharedLibraryInfo> dynamicSharedLibraryInfos = null; if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) { dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size()); for (String name : parsedPackage.getLibraryNames()) { dynamicSharedLibraryInfos.add( - SharedLibraryInfo.createForDynamic(parsedPackage, name)); + AndroidPackageUtils.createSharedLibraryForDynamic(parsedPackage, name)); } } @@ -11167,7 +11215,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private static void assertCodePolicy(AndroidPackage pkg) throws PackageManagerException { - final boolean shouldHaveCode = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0; + final boolean shouldHaveCode = pkg.isHasCode(); if (shouldHaveCode && !apkHasCode(pkg.getBaseCodePath())) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Package " + pkg.getBaseCodePath() + " code is missing"); @@ -11193,7 +11241,8 @@ public class PackageManagerService extends IPackageManager.Stub * ideally be static, but, it requires locks to read system state. */ private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, - final @ScanFlags int scanFlags, AndroidPackage platformPkg) { + final @ScanFlags int scanFlags, AndroidPackage platformPkg, + boolean isUpdatedSystemApp) { if ((scanFlags & SCAN_AS_SYSTEM) != 0) { parsedPackage.setSystem(true); // TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag @@ -11202,7 +11251,7 @@ public class PackageManagerService extends IPackageManager.Stub parsedPackage.setAllComponentsDirectBootAware(true); } if (compressedFileExists(parsedPackage.getCodePath())) { - parsedPackage.setIsStub(true); + parsedPackage.setStub(true); } } else { parsedPackage @@ -11237,14 +11286,14 @@ public class PackageManagerService extends IPackageManager.Stub ) == PackageManager.SIGNATURE_MATCH)) ); - if (!isSystemApp(parsedPackage)) { + if (!parsedPackage.isSystem()) { // Only system apps can use these features. parsedPackage.clearOriginalPackages() .setRealPackage(null) .clearAdoptPermissions(); } - PackageBackwardCompatibility.modifySharedLibraries(parsedPackage); + PackageBackwardCompatibility.modifySharedLibraries(parsedPackage, isUpdatedSystemApp); } private static @NonNull <T> T assertNotNull(@Nullable T object, String message) @@ -11255,19 +11304,19 @@ public class PackageManagerService extends IPackageManager.Stub return object; } - private <T extends ComponentParseUtils.ParsedMainComponent> + private <T extends ParsedMainComponent> void assertPackageProcesses(AndroidPackage pkg, List<T> components, - ArrayMap<String, ComponentParseUtils.ParsedProcess> procs, String compName) + Map<String, ParsedProcess> procs, String compName) throws PackageManagerException { if (components == null) { return; } for (int i = components.size() - 1; i >= 0; i--) { - final ComponentParseUtils.ParsedMainComponent<?> component = components.get(i); + final ParsedMainComponent component = components.get(i); if (!procs.containsKey(component.getProcessName())) { throw new PackageManagerException( INSTALL_FAILED_PROCESS_NOT_DEFINED, - "Can't install because " + compName + " " + component.className + "Can't install because " + compName + " " + component.getClassName() + "'s process attribute " + component.getProcessName() + " (in package " + pkg.getPackageName() + ") is not included in the <processes> list"); @@ -11291,8 +11340,7 @@ public class PackageManagerService extends IPackageManager.Stub assertCodePolicy(pkg); } - if (pkg.getAppInfoCodePath() == null || - pkg.getAppInfoResourcePath() == null) { + if (pkg.getCodePath() == null) { // Bail out. The resource and code paths haven't been set. throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Code and resource paths haven't been set correctly"); @@ -11375,49 +11423,49 @@ public class PackageManagerService extends IPackageManager.Stub } // Static shared libs cannot declare activities - if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) { + if (!pkg.getActivities().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare activities"); } // Static shared libs cannot declare services - if (pkg.getServices() != null && !pkg.getServices().isEmpty()) { + if (!pkg.getServices().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare services"); } // Static shared libs cannot declare providers - if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) { + if (!pkg.getProviders().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare content providers"); } // Static shared libs cannot declare receivers - if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) { + if (!pkg.getReceivers().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare broadcast receivers"); } // Static shared libs cannot declare permission groups - if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) { + if (!pkg.getPermissionGroups().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permission groups"); } // Static shared libs cannot declare features - if (pkg.getFeatures() != null && !pkg.getFeatures().isEmpty()) { + if (!pkg.getFeatures().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare features"); } // Static shared libs cannot declare permissions - if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) { + if (!pkg.getPermissions().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permissions"); } // Static shared libs cannot declare protected broadcasts - if (pkg.getProtectedBroadcasts() != null) { + if (!pkg.getProtectedBroadcasts().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare protected broadcasts"); } @@ -11479,12 +11527,11 @@ public class PackageManagerService extends IPackageManager.Stub + " and requiring known paths " + known.codePathString + " & " + known.resourcePathString); } - if (!pkg.getAppInfoCodePath().equals(known.codePathString) - || !pkg.getAppInfoResourcePath().equals( - known.resourcePathString)) { + if (!pkg.getCodePath().equals(known.codePathString) + || !pkg.getCodePath().equals(known.resourcePathString)) { throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED, "Application package " + pkg.getPackageName() - + " found at " + pkg.getAppInfoCodePath() + + " found at " + pkg.getCodePath() + " but expected at " + known.codePathString + "; ignoring."); } @@ -11506,8 +11553,8 @@ public class PackageManagerService extends IPackageManager.Stub // If this package has defined explicit processes, then ensure that these are // the only processes used by its components. - final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses(); - if (procs != null) { + final Map<String, ParsedProcess> procs = pkg.getProcesses(); + if (!procs.isEmpty()) { if (!procs.containsKey(pkg.getProcessName())) { throw new PackageManagerException( INSTALL_FAILED_PROCESS_NOT_DEFINED, @@ -11761,14 +11808,16 @@ public class PackageManagerService extends IPackageManager.Stub reconciledPkg.getCombinedAvailablePackages(); try { // Shared libraries for the package need to be updated. - updateSharedLibrariesLocked(pkg, null, combinedSigningDetails); + updateSharedLibrariesLocked(pkg, pkgSetting, null, null, + combinedSigningDetails); } catch (PackageManagerException e) { Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e); } // Update all applications that use this library. Skip when booting // since this will be done after all packages are scaned. if ((scanFlags & SCAN_BOOTING) == 0) { - clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedSigningDetails); + clientLibPkgs = updateAllSharedLibrariesLocked(pkg, pkgSetting, + combinedSigningDetails); } } } @@ -11793,7 +11842,7 @@ public class PackageManagerService extends IPackageManager.Stub if (clientLibPkgs != null) { for (int i=0; i<clientLibPkgs.size(); i++) { AndroidPackage clientPkg = clientLibPkgs.get(i); - killApplication(clientPkg.getAppInfoPackageName(), + killApplication(clientPkg.getPackageName(), clientPkg.getUid(), "update lib"); } } @@ -11807,7 +11856,7 @@ public class PackageManagerService extends IPackageManager.Stub // Add the new setting to mSettings mSettings.insertPackageSettingLPw(pkgSetting, pkg); // Add the new setting to mPackages - mPackages.put(pkg.getAppInfoPackageName(), pkg); + mPackages.put(pkg.getPackageName(), pkg); if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) { mApexManager.registerApkInApex(pkg); } @@ -11855,7 +11904,7 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r); } - if (pkg.getProtectedBroadcasts() != null) { + if (!pkg.getProtectedBroadcasts().isEmpty()) { synchronized (mProtectedBroadcasts) { mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts()); } @@ -11887,8 +11936,8 @@ public class PackageManagerService extends IPackageManager.Stub // Set up information for custom user intent resolution activity. mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState(); mResolveActivity.name = mCustomResolverComponentName.getClassName(); - mResolveActivity.packageName = pkg.getAppInfoPackageName(); - mResolveActivity.processName = pkg.getAppInfoProcessName(); + mResolveActivity.packageName = pkg.getPackageName(); + mResolveActivity.processName = pkg.getProcessName(); mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; @@ -12006,21 +12055,19 @@ public class PackageManagerService extends IPackageManager.Stub } r = null; - if ((pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) { + if (pkg.isSystem()) { // Only system apps can hold shared libraries. - if (pkg.getLibraryNames() != null) { - final int libraryNamesSize = pkg.getLibraryNames().size(); - for (i = 0; i < libraryNamesSize; i++) { - String name = pkg.getLibraryNames().get(i); - if (removeSharedLibraryLPw(name, 0)) { - if (DEBUG_REMOVE && chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(name); + final int libraryNamesSize = pkg.getLibraryNames().size(); + for (i = 0; i < libraryNamesSize; i++) { + String name = pkg.getLibraryNames().get(i); + if (removeSharedLibraryLPw(name, 0)) { + if (DEBUG_REMOVE && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); } + r.append(name); } } } @@ -12431,18 +12478,12 @@ public class PackageManagerService extends IPackageManager.Stub if (pkgSetting == null || !pkgSetting.isSystem()) { return; } - AndroidPackage pkg = pkgSetting.pkg; - if (pkg != null) { - pkg.mutate().setHiddenUntilInstalled(hidden); - } + pkgSetting.getPkgState().setHiddenUntilInstalled(hidden); final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName); if (disabledPs == null) { return; } - pkg = disabledPs.pkg; - if (pkg != null) { - pkg.mutate().setHiddenUntilInstalled(hidden); - } + disabledPs.getPkgState().setHiddenUntilInstalled(hidden); } } @@ -13464,15 +13505,15 @@ public class PackageManagerService extends IPackageManager.Stub ArrayList<IntentFilter> result = new ArrayList<>(); for (int n=0; n<count; n++) { ParsedActivity activity = pkg.getActivities().get(n); - if (activity.intents != null && activity.intents.size() > 0) { - result.addAll(activity.intents); + if (activity.getIntents() != null && activity.getIntents().size() > 0) { + result.addAll(activity.getIntents()); } } return new ParceledListSlice<IntentFilter>(result) { @Override protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) { // IntentFilter has final Parcelable methods, so redirect to the subclass - ((ParsedActivityIntentInfo) parcelable).writeIntentInfoToParcel(dest, + ((ParsedIntentInfo) parcelable).writeIntentInfoToParcel(dest, callFlags); } }; @@ -13657,9 +13698,8 @@ public class PackageManagerService extends IPackageManager.Stub // package has not opted out of backup participation. final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null; - final int flags = (res.pkg == null) ? 0 : res.pkg.getFlags(); - boolean doRestore = !update - && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0); + boolean allowBackup = res.pkg != null && res.pkg.isAllowBackup(); + boolean doRestore = !update && allowBackup; // Set up the post-install work request bookkeeping. This will be used // and cleaned up by the post-install event handling regardless of whether @@ -13727,7 +13767,7 @@ public class PackageManagerService extends IPackageManager.Stub try { if (bm.isUserReadyForBackup(userId)) { bm.restoreAtInstallForUser( - userId, res.pkg.getAppInfoPackageName(), token); + userId, res.pkg.getPackageName(), token); } else { Slog.w(TAG, "User " + userId + " is not ready. Restore at install " + "didn't take place."); @@ -13755,8 +13795,7 @@ public class PackageManagerService extends IPackageManager.Stub IRollbackManager rm = IRollbackManager.Stub.asInterface( ServiceManager.getService(Context.ROLLBACK_SERVICE)); - final String packageName = res.pkg.getAppInfoPackageName(); - final String seInfo = res.pkg.getSeInfo(); + final String packageName = res.pkg.getPackageName(); final int[] allUsers = mUserManager.getUserIds(); final int[] installedUsers; @@ -13780,6 +13819,7 @@ public class PackageManagerService extends IPackageManager.Stub || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0); if (ps != null && doSnapshotOrRestore) { + final String seInfo = AndroidPackageUtils.getSeInfo(res.pkg, ps); try { rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode, seInfo, token); @@ -13815,7 +13855,7 @@ public class PackageManagerService extends IPackageManager.Stub if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) { continue; } - if (packageName.equals(data.res.pkg.getAppInfoPackageName())) { + if (packageName.equals(data.res.pkg.getPackageName())) { // right package; but is it for the right user? for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) { if (userId == data.res.newUsers[uIndex]) { @@ -14200,7 +14240,7 @@ public class PackageManagerService extends IPackageManager.Stub if (dataOwnerPkg != null) { if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, - dataOwnerPkg.getFlags())) { + dataOwnerPkg.isDebuggable())) { try { checkDowngrade(dataOwnerPkg, pkgLite); } catch (PackageManagerException e) { @@ -14213,7 +14253,7 @@ public class PackageManagerService extends IPackageManager.Stub if (installedPkg != null) { if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { // Check for updated system application. - if ((installedPkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) { + if (installedPkg.isSystem()) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } else { // If current upgrade specifies particular preference @@ -14224,7 +14264,7 @@ public class PackageManagerService extends IPackageManager.Stub // App explictly prefers external. Let policy decide } else { // Prefer previous location - if (isExternal(installedPkg)) { + if (installedPkg.isExternalStorage()) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } return PackageHelper.RECOMMEND_INSTALL_INTERNAL; @@ -15000,14 +15040,6 @@ public class PackageManagerService extends IPackageManager.Stub parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile, parsedPackage.getSplitCodePaths())); - // Reflect the rename in app info - // TODO(b/135203078): Remove all of these application info calls - parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) - .setApplicationInfoCodePath(parsedPackage.getCodePath()) - .setApplicationInfoResourcePath(parsedPackage.getCodePath()) - .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) - .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); - return true; } @@ -15117,14 +15149,6 @@ public class PackageManagerService extends IPackageManager.Stub return false; } - // Reflect the move in app info - // TODO(b/135203078): Remove all of these application info calls - parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) - .setApplicationInfoCodePath(parsedPackage.getCodePath()) - .setApplicationInfoResourcePath(parsedPackage.getCodePath()) - .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) - .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); - return true; } @@ -15320,7 +15344,7 @@ public class PackageManagerService extends IPackageManager.Stub final PackageSetting ps = mSettings.mPackages.get(pkgName); final int userId = installArgs.user.getIdentifier(); if (ps != null) { - if (isSystemApp(pkg)) { + if (pkg.isSystem()) { if (DEBUG_INSTALL) { Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName); } @@ -15349,8 +15373,8 @@ public class PackageManagerService extends IPackageManager.Stub } // Retrieve the overlays for shared libraries of the package. - if (pkg.getUsesLibraryInfos() != null) { - for (SharedLibraryInfo sharedLib : pkg.getUsesLibraryInfos()) { + if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) { + for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) { for (int currentUserId : UserManagerService.getInstance().getUserIds()) { if (!sharedLib.isDynamic()) { // TODO(146804378): Support overlaying static shared libraries @@ -15822,13 +15846,13 @@ public class PackageManagerService extends IPackageManager.Stub if (scanResult.staticSharedLibraryInfo != null) { return Collections.singletonList(scanResult.staticSharedLibraryInfo); } - final boolean hasDynamicLibraries = - (parsedPackage.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0 + final boolean hasDynamicLibraries = parsedPackage.isSystem() && scanResult.dynamicSharedLibraryInfos != null; if (!hasDynamicLibraries) { return null; } - final boolean isUpdatedSystemApp = parsedPackage.isUpdatedSystemApp(); + final boolean isUpdatedSystemApp = scanResult.pkgSetting.getPkgState() + .isUpdatedSystemApp(); // We may not yet have disabled the updated package yet, so be sure to grab the // current setting if that's the case. final PackageSetting updatedSystemPs = isUpdatedSystemApp @@ -15925,10 +15949,13 @@ public class PackageManagerService extends IPackageManager.Stub // which means we are replacing another update that is already // installed. We need to make sure to delete the older one's .apk. res.removedInfo.args = createInstallArgsForExisting( - oldPackage.getAppInfoCodePath(), - oldPackage.getAppInfoResourcePath(), - getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(), - oldPackage.getSecondaryCpuAbi())); + oldPackage.getCodePath(), + oldPackage.getCodePath(), + getAppDexInstructionSets( + AndroidPackageUtils.getPrimaryCpuAbi(oldPackage, + deletedPkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(oldPackage, + deletedPkgSetting))); } else { res.removedInfo.args = null; } @@ -15947,14 +15974,14 @@ public class PackageManagerService extends IPackageManager.Stub // If deleted package lived in a container, give users a chance to // relinquish resources before killing. - if (oldPackage.isForwardLocked() || isExternal(oldPackage)) { + if (oldPackage.isExternalStorage()) { if (DEBUG_INSTALL) { Slog.i(TAG, "upgrading pkg " + oldPackage + " is ASEC-hosted -> UNAVAILABLE"); } final int[] uidArray = new int[]{oldPackage.getUid()}; final ArrayList<String> pkgList = new ArrayList<>(1); - pkgList.add(oldPackage.getAppInfoPackageName()); + pkgList.add(oldPackage.getPackageName()); sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null); } @@ -16061,7 +16088,7 @@ public class PackageManagerService extends IPackageManager.Stub final ScanResult result = scanPackageTracedLI( prepareResult.packageToScan, prepareResult.parseFlags, prepareResult.scanFlags, System.currentTimeMillis(), - request.args.user); + request.args.user, request.args.abiOverride); if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) { request.installResult.setError( PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE, @@ -16194,7 +16221,7 @@ public class PackageManagerService extends IPackageManager.Stub final boolean performDexopt = (!instantApp || Global.getInt(mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) - && ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) == 0) + && !pkg.isDebuggable() && (!onIncremental); if (performDexopt) { @@ -16214,7 +16241,7 @@ public class PackageManagerService extends IPackageManager.Stub REASON_INSTALL, DexoptOptions.DEXOPT_BOOT_COMPLETE | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE); - mPackageDexOptimizer.performDexOpt(pkg, + mPackageDexOptimizer.performDexOpt(pkg, reconciledPkg.pkgSetting, null /* instructionSets */, getOrCreateCompilerPackageStats(pkg), mDexManager.getPackageUseInfoOrDefault(packageName), @@ -16331,16 +16358,14 @@ public class PackageManagerService extends IPackageManager.Stub | PackageParser.PARSE_ENFORCE_CODE | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0); - PackageParser pp = new PackageParser(); - pp.setSeparateProcesses(mSeparateProcesses); - pp.setDisplayMetrics(mMetrics); - pp.setCallback(mPackageParserCallback); + PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null, + mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); ParsedPackage parsedPackage; try { - parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false); - DexMetadataHelper.validatePackageDexMetadata(parsedPackage); + parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false); + AndroidPackageUtils.validatePackageDexMetadata(parsedPackage); } catch (PackageParserException e) { throw new PrepareFailure("Failed parse during installPackageLI", e); } finally { @@ -16375,16 +16400,8 @@ public class PackageManagerService extends IPackageManager.Stub } } - // If package doesn't declare API override, mark that we have an install - // time CPU ABI override. - // TODO(b/135203078): Isn't this always true because cpuAbiOverride isn't assigned during - // parsing? - if (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())) { - parsedPackage.setCpuAbiOverride(args.abiOverride); - } - String pkgName = res.name = parsedPackage.getPackageName(); - if ((parsedPackage.getFlags() & ApplicationInfo.FLAG_TEST_ONLY) != 0) { + if (parsedPackage.isTestOnly()) { if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) { throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI"); } @@ -16396,7 +16413,8 @@ public class PackageManagerService extends IPackageManager.Stub parsedPackage.setSigningDetails(args.signingDetails); } else { // TODO(b/136132412): skip for Incremental installation - ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */); + parsedPackage.setSigningDetails( + ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */)); } } catch (PackageParserException e) { throw new PrepareFailure("Failed collect during installPackageLI", e); @@ -16418,8 +16436,7 @@ public class PackageManagerService extends IPackageManager.Stub // Check if installing already existing package if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { String oldName = mSettings.getRenamedPackageLPr(pkgName); - if (parsedPackage.getOriginalPackages() != null - && parsedPackage.getOriginalPackages().contains(oldName) + if (parsedPackage.getOriginalPackages().contains(oldName) && mPackages.containsKey(oldName)) { // This package is derived from an original package, // and this device has been updating from that original @@ -16454,7 +16471,7 @@ public class PackageManagerService extends IPackageManager.Stub + " target SDK " + oldTargetSdk + " does."); } // Prevent persistent apps from being updated - if (((oldPackage.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0) + if (oldPackage.isPersistent() && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK, "Package " + oldPackage.getPackageName() + " is a persistent app. " @@ -16509,7 +16526,7 @@ public class PackageManagerService extends IPackageManager.Stub } if (ps.pkg != null) { - systemApp = (ps.pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0; + systemApp = ps.pkg.isSystem(); } res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); } @@ -16521,12 +16538,12 @@ public class PackageManagerService extends IPackageManager.Stub final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName()); // Don't allow anyone but the system to define ephemeral permissions. - if ((perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 + if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 && !systemApp) { Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName() + " attempting to delcare ephemeral permission " + perm.getName() + "; Removing ephemeral."); - perm.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT; + perm.setProtectionLevel(perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT); } // Check whether the newly-scanned package wants to define an already-defined perm @@ -16587,14 +16604,14 @@ public class PackageManagerService extends IPackageManager.Stub // type as this would allow a privilege escalation where an app adds a // normal/signature permission in other app's group and later redefines // it as dangerous leading to the group auto-grant. - if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) + if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_DANGEROUS) { if (bp != null && !bp.isRuntime()) { Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " trying to change a non-runtime permission " + perm.getName() + " to runtime; keeping old protection level"); - perm.protectionLevel = bp.getProtectionLevel(); + perm.setProtectionLevel(bp.getProtectionLevel()); } } } @@ -16637,12 +16654,22 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags |= SCAN_NO_DEX; try { - String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride()) - ? args.abiOverride : parsedPackage.getCpuAbiOverride()); - final boolean extractNativeLibs = !parsedPackage.isLibrary(); + final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage); + PackageSetting pkgSetting; + synchronized (mLock) { + pkgSetting = mSettings.getPackageLPr(pkgName); + } + String abiOverride = + (pkgSetting == null || TextUtils.isEmpty(pkgSetting.cpuAbiOverrideString) + ? args.abiOverride : pkgSetting.cpuAbiOverrideString); + boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null + && pkgSetting.getPkgState().isUpdatedSystemApp(); + AndroidPackage oldPackage = mPackages.get(pkgName); + boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem(); final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> - derivedAbi = mInjector.getAbiHelper().derivePackageAbi( - parsedPackage, abiOverride, extractNativeLibs); + derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage, + isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred, + abiOverride, extractNativeLibs); derivedAbi.first.applyTo(parsedPackage); derivedAbi.second.applyTo(parsedPackage); } catch (PackageManagerException pme) { @@ -16817,14 +16844,14 @@ public class PackageManagerService extends IPackageManager.Stub res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId)); } - sysPkg = (isSystemApp(oldPackage)); + sysPkg = oldPackage.isSystem(); if (sysPkg) { // Set the system/privileged/oem/vendor/product flags as needed - final boolean privileged = isPrivilegedApp(oldPackage); - final boolean oem = isOemApp(oldPackage); - final boolean vendor = isVendorApp(oldPackage); - final boolean product = isProductApp(oldPackage); - final boolean odm = isOdmApp(oldPackage); + final boolean privileged = oldPackage.isPrivileged(); + final boolean oem = oldPackage.isOem(); + final boolean vendor = oldPackage.isVendor(); + final boolean product = oldPackage.isProduct(); + final boolean odm = oldPackage.isOdm(); final @ParseFlags int systemParseFlags = parseFlags; final @ScanFlags int systemScanFlags = scanFlags | SCAN_AS_SYSTEM @@ -16839,7 +16866,7 @@ public class PackageManagerService extends IPackageManager.Stub + ", old=" + oldPackage); } res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); - parsedPackage.setUpdatedSystemApp(true); + ps.getPkgState().setUpdatedSystemApp(true); targetParseFlags = systemParseFlags; targetScanFlags = systemScanFlags; } else { // non system replace @@ -17006,7 +17033,7 @@ public class PackageManagerService extends IPackageManager.Stub Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS); msg.obj = new IFVerificationParams( pkg.getPackageName(), - hasDomainURLs(pkg), + pkg.isHasDomainUrls(), pkg.getActivities(), replacing, userId, @@ -17058,11 +17085,12 @@ public class PackageManagerService extends IPackageManager.Stub // examine handling policy even if not re-verifying. boolean needToVerify = false; for (ParsedActivity a : activities) { - for (ParsedActivityIntentInfo filter : a.intents) { + for (ParsedIntentInfo filter : a.getIntents()) { if (filter.handlesWebUris(true)) { handlesWebUris = true; } - if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { + if (filter.needsVerification() + && needsNetworkVerificationLPr(a.getPackageName())) { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, "Intent filter needs verification, so processing all filters"); @@ -17082,8 +17110,9 @@ public class PackageManagerService extends IPackageManager.Stub if (needToVerify) { final int verificationId = mIntentFilterVerificationToken++; for (ParsedActivity a : activities) { - for (ParsedActivityIntentInfo filter : a.intents) { - if (filter.handlesWebUris(true) && needsNetworkVerificationLPr(filter)) { + for (ParsedIntentInfo filter : a.getIntents()) { + if (filter.handlesWebUris(true) + && needsNetworkVerificationLPr(a.getPackageName())) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Verification needed for IntentFilter:" + filter.toString()); mIntentFilterVerifier.addOneIntentFilterVerification( @@ -17118,9 +17147,7 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private boolean needsNetworkVerificationLPr(ParsedActivityIntentInfo filter) { - final String packageName = filter.getPackageName(); - + private boolean needsNetworkVerificationLPr(String packageName) { IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr( packageName); if (ivi == null) { @@ -17139,47 +17166,10 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static boolean isExternal(AndroidPackage pkg) { - return (pkg.getFlags() & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; - } - private static boolean isExternal(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } - static boolean isSystemApp(AndroidPackage pkg) { - return (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0; - } - - private static boolean isPrivilegedApp(AndroidPackage pkg) { - return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; - } - - private static boolean isOemApp(AndroidPackage pkg) { - return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; - } - - private static boolean isVendorApp(AndroidPackage pkg) { - return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; - } - - private static boolean isProductApp(AndroidPackage pkg) { - return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; - } - - private static boolean isSystemExtApp(AndroidPackage pkg) { - return (pkg.getPrivateFlags() - & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0; - } - - private static boolean isOdmApp(AndroidPackage pkg) { - return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; - } - - private static boolean hasDomainURLs(AndroidPackage pkg) { - return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; - } - private static boolean isSystemApp(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; } @@ -17189,7 +17179,7 @@ public class PackageManagerService extends IPackageManager.Stub } private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) { - if (isExternal(pkg)) { + if (pkg.isExternalStorage()) { if (TextUtils.isEmpty(pkg.getVolumeUuid())) { return mSettings.getExternalVersion(); } else { @@ -17649,10 +17639,11 @@ public class PackageManagerService extends IPackageManager.Stub final AndroidPackage stubPkg = (disabledSystemPs == null) ? null : disabledSystemPs.pkg; if (stubPkg != null && stubPkg.isStub()) { + final PackageSetting stubPs; synchronized (mLock) { // restore the enabled state of the stub; the state is overwritten when // the stub is uninstalled - final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.getPackageName()); + stubPs = mSettings.getPackageLPr(stubPkg.getPackageName()); if (stubPs != null) { stubPs.setEnabled(origEnabledState, userId, "android"); } @@ -17663,7 +17654,7 @@ public class PackageManagerService extends IPackageManager.Stub Slog.i(TAG, "Enabling system stub after removal; pkg: " + stubPkg.getPackageName()); } - enableCompressedPackage(stubPkg); + enableCompressedPackage(stubPkg, stubPs); } } } @@ -18046,9 +18037,12 @@ public class PackageManagerService extends IPackageManager.Stub final AndroidPackage pkg = scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null); + PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName()); + try { // update shared libraries for the newly re-installed system package - updateSharedLibrariesLocked(pkg, null, Collections.unmodifiableMap(mPackages)); + updateSharedLibrariesLocked(pkg, pkgSetting, null, null, + Collections.unmodifiableMap(mPackages)); } catch (PackageManagerException e) { Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); } @@ -18479,10 +18473,11 @@ public class PackageManagerService extends IPackageManager.Stub // Try finding details about the requested package AndroidPackage pkg; + PackageSetting ps; synchronized (mLock) { pkg = mPackages.get(packageName); + ps = mSettings.mPackages.get(packageName); if (pkg == null) { - final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { pkg = ps.pkg; } @@ -18509,7 +18504,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { flags = 0; } - prepareAppDataContentsLIF(pkg, userId, flags); + prepareAppDataContentsLIF(pkg, ps, userId, flags); return true; } @@ -19966,7 +19961,7 @@ public class PackageManagerService extends IPackageManager.Stub if (isSystemStub && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) { - if (!enableCompressedPackage(deletedPkg)) { + if (!enableCompressedPackage(deletedPkg, pkgSetting)) { return; } } @@ -19983,7 +19978,7 @@ public class PackageManagerService extends IPackageManager.Stub // We're dealing with a component level state change // First, verify that this is a valid class name. AndroidPackage pkg = pkgSetting.pkg; - if (pkg == null || !pkg.hasComponentClassName(className)) { + if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) { if (pkg != null && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.JELLY_BEAN) { @@ -21216,24 +21211,27 @@ public class PackageManagerService extends IPackageManager.Stub ipw.println(); ipw.println("Dexopt state:"); ipw.increaseIndent(); - Collection<AndroidPackage> packages; + Collection<PackageSetting> pkgSettings; if (packageName != null) { - AndroidPackage targetPackage = mPackages.get(packageName); - if (targetPackage != null) { - packages = Collections.singletonList(targetPackage); + PackageSetting targetPkgSetting = mSettings.mPackages.get(packageName); + if (targetPkgSetting != null) { + pkgSettings = Collections.singletonList(targetPkgSetting); } else { ipw.println("Unable to find package: " + packageName); return; } } else { - packages = mPackages.values(); + pkgSettings = mSettings.mPackages.values(); } - for (AndroidPackage pkg : packages) { - ipw.println("[" + pkg.getPackageName() + "]"); + for (PackageSetting pkgSetting : pkgSettings) { + if (pkgSetting.pkg == null) { + continue; + } + ipw.println("[" + pkgSetting.name + "]"); ipw.increaseIndent(); - mPackageDexOptimizer.dumpDexoptState(ipw, pkg, - mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName())); + mPackageDexOptimizer.dumpDexoptState(ipw, pkgSetting.pkg, pkgSetting, + mDexManager.getPackageUseInfoOrDefault(pkgSetting.pkg.getPackageName())); ipw.decreaseIndent(); } } @@ -21339,7 +21337,7 @@ public class PackageManagerService extends IPackageManager.Stub final int[] packageUids = new int[size]; for (int i = 0; i < size; i++) { final AndroidPackage pkg = packages.get(i); - packageNames[i] = pkg.getAppInfoPackageName(); + packageNames[i] = pkg.getPackageName(); packageUids[i] = pkg.getUid(); } sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids, @@ -21803,16 +21801,17 @@ public class PackageManagerService extends IPackageManager.Stub final int appId = UserHandle.getAppId(pkg.getUid()); - Preconditions.checkNotNull(pkg.getSeInfo()); + String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps); + + Preconditions.checkNotNull(pkgSeInfo); - final String seInfo = - pkg.getSeInfo() + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : ""); + final String seInfo = pkgSeInfo + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : ""); long ceDataInode = -1; try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); } catch (InstallerException e) { - if (pkg.isSystemApp()) { + if (pkg.isSystem()) { logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName + ", but trying to recover: " + e); destroyAppDataLeafLIF(pkg, userId, flags); @@ -21857,18 +21856,20 @@ public class PackageManagerService extends IPackageManager.Stub } } - prepareAppDataContentsLeafLIF(pkg, userId, flags); + prepareAppDataContentsLeafLIF(pkg, ps, userId, flags); } - private void prepareAppDataContentsLIF(AndroidPackage pkg, int userId, int flags) { + private void prepareAppDataContentsLIF(AndroidPackage pkg, @Nullable PackageSetting pkgSetting, + int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } - prepareAppDataContentsLeafLIF(pkg, userId, flags); + prepareAppDataContentsLeafLIF(pkg, pkgSetting, userId, flags); } - private void prepareAppDataContentsLeafLIF(AndroidPackage pkg, int userId, int flags) { + private void prepareAppDataContentsLeafLIF(AndroidPackage pkg, + @Nullable PackageSetting pkgSetting, int userId, int flags) { final String volumeUuid = pkg.getVolumeUuid(); final String packageName = pkg.getPackageName(); @@ -21876,7 +21877,8 @@ public class PackageManagerService extends IPackageManager.Stub // Create a native library symlink only if we have native libraries // and if the native libraries are 32 bit libraries. We do not provide // this symlink for 64 bit libraries. - if (pkg.getPrimaryCpuAbi() != null && !VMRuntime.is64BitAbi(pkg.getPrimaryCpuAbi())) { + String primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting); + if (primaryCpuAbi != null && !VMRuntime.is64BitAbi(primaryCpuAbi)) { final String nativeLibPath = pkg.getNativeLibraryDir(); try { mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName, @@ -22065,7 +22067,7 @@ public class PackageManagerService extends IPackageManager.Stub || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) { throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package"); } - if (pkg.isSystemApp()) { + if (pkg.isSystem()) { throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE, "Cannot move system application"); } @@ -22091,7 +22093,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Package already moved to " + volumeUuid); } - if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) { + if (!pkg.isExternalStorage() && isPackageDeviceAdminOnAnyUser(packageName)) { throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN, "Device admin cannot be moved"); } @@ -22101,12 +22103,12 @@ public class PackageManagerService extends IPackageManager.Stub "Failed to move already frozen package"); } - isCurrentLocationExternal = isExternal(pkg); + isCurrentLocationExternal = pkg.isExternalStorage(); codeFile = new File(pkg.getCodePath()); installSource = ps.installSource; packageAbiOverride = ps.cpuAbiOverrideString; appId = UserHandle.getAppId(pkg.getUid()); - seinfo = pkg.getSeInfo(); + seinfo = AndroidPackageUtils.getSeInfo(pkg, ps); label = String.valueOf(pm.getApplicationLabel(pkg.toAppInfoWithoutState())); targetSdkVersion = pkg.getTargetSdkVersion(); freezer = freezePackage(packageName, "movePackageInternal"); @@ -22281,15 +22283,15 @@ public class PackageManagerService extends IPackageManager.Stub final StorageManager storage = mInjector.getStorageManager();; VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString()); - int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg)); + int packageExternalStorageType = getPackageExternalStorageType(volume, pkg.isExternalStorage()); - if (!isPreviousLocationExternal && isExternal(pkg)) { + if (!isPreviousLocationExternal && pkg.isExternalStorage()) { // Move from internal to external storage. FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType, FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL, packageName); - } else if (isPreviousLocationExternal && !isExternal(pkg)) { + } else if (isPreviousLocationExternal && !pkg.isExternalStorage()) { // Move from external to internal storage. FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType, @@ -23013,7 +23015,7 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public Object getDisabledSystemPackage(@NonNull String packageName) { + public PackageSetting getDisabledSystemPackage(@NonNull String packageName) { synchronized (mLock) { return mSettings.getDisabledSystemPkgLPr(packageName); } @@ -23363,7 +23365,7 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) { + public boolean isEnabledAndMatches(ParsedMainComponent component, int flags, int userId) { synchronized (mLock) { AndroidPackage pkg = getPackage(component.getPackageName()); return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId); @@ -23455,11 +23457,7 @@ public class PackageManagerService extends IPackageManager.Stub public boolean isPackagePersistent(String packageName) { synchronized (mLock) { AndroidPackage pkg = mPackages.get(packageName); - return pkg != null - ? ((pkg.getFlags() & (ApplicationInfo.FLAG_SYSTEM - | ApplicationInfo.FLAG_PERSISTENT)) == - (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT)) - : false; + return pkg != null && pkg.isSystem() && pkg.isPersistent(); } } @@ -23690,6 +23688,15 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public void forEachPackageSetting(Consumer<PackageSetting> actionLocked) { + synchronized (mLock) { + for (int index = 0; index < mSettings.mPackages.size(); index++) { + actionLocked.accept(mSettings.mPackages.valueAt(index)); + } + } + } + + @Override public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId) { PackageManagerService.this.forEachInstalledPackage(actionLocked, userId); @@ -24185,15 +24192,18 @@ public class PackageManagerService extends IPackageManager.Stub boolean canHaveOatDir(String packageName) { synchronized (mLock) { AndroidPackage p = mPackages.get(packageName); - if (p == null) { + PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); + if (p == null || pkgSetting == null) { return false; } - return p.canHaveOatDir(); + return AndroidPackageUtils.canHaveOatDir(p, + pkgSetting.getPkgState().isUpdatedSystemApp()); } } - private String getOatDir(AndroidPackage pkg) { - if (!pkg.canHaveOatDir()) { + private String getOatDir(AndroidPackage pkg, @NonNull PackageSetting pkgSetting) { + if (!AndroidPackageUtils.canHaveOatDir(pkg, + pkgSetting.getPkgState().isUpdatedSystemApp())) { return null; } File codePath = new File(pkg.getCodePath()); @@ -24208,13 +24218,16 @@ public class PackageManagerService extends IPackageManager.Stub final List<String> codePaths; final String oatDir; final AndroidPackage pkg; + final PackageSetting pkgSetting; synchronized (mLock) { pkg = mPackages.get(packageName); + pkgSetting = mSettings.getPackageLPr(packageName); } - instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), - pkg.getSecondaryCpuAbi()); - codePaths = pkg.getAllCodePaths(); - oatDir = getOatDir(pkg); + instructionSets = getAppDexInstructionSets( + AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting)); + codePaths = AndroidPackageUtils.getAllCodePaths(pkg); + oatDir = getOatDir(pkg, pkgSetting); for (String codePath : codePaths) { for (String isa : instructionSets) { @@ -24241,8 +24254,8 @@ public class PackageManagerService extends IPackageManager.Stub if (PackageManagerServiceUtils .isUnusedSinceTimeInMillis(ps.firstInstallTime, currentTimeInMillis, downgradeTimeThresholdMillis, packageUseInfo, - pkg.getLatestPackageUseTimeInMills(), - pkg.getLatestForegroundPackageUseTimeInMills())) { + ps.getPkgState().getLatestPackageUseTimeInMills(), + ps.getPkgState().getLatestForegroundPackageUseTimeInMills())) { unusedPackages.add(pkg.getPackageName()); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index a9035b21a32b..91afd846a9c3 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -40,8 +40,7 @@ import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ApkParseUtils; +import android.content.pm.parsing.ParsingPackageUtils; import android.os.Build; import android.os.Debug; import android.os.Environment; @@ -66,6 +65,7 @@ import com.android.internal.util.FastPrintWriter; import com.android.server.EventLogTags; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.PackageDexUsage; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.permission.PermissionsState; import dalvik.system.VMRuntime; @@ -94,6 +94,8 @@ import java.util.Collections; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.Predicate; import java.util.zip.GZIPInputStream; @@ -105,6 +107,9 @@ import java.util.zip.GZIPInputStream; public class PackageManagerServiceUtils { private final static long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000; + public final static Predicate<PackageSetting> REMOVE_IF_NULL_PKG = + pkgSetting -> pkgSetting.pkg == null; + private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) { List<ResolveInfo> ris = null; try { @@ -124,40 +129,43 @@ public class PackageManagerServiceUtils { // Sort a list of apps by their last usage, most recently used apps first. The order of // packages without usage data is undefined (but they will be sorted after the packages // that do have usage data). - public static void sortPackagesByUsageDate(List<AndroidPackage> pkgs, + public static void sortPackagesByUsageDate(List<PackageSetting> pkgSettings, PackageManagerService packageManagerService) { if (!packageManagerService.isHistoricalPackageUsageAvailable()) { return; } - Collections.sort(pkgs, (pkg1, pkg2) -> - Long.compare(pkg2.getLatestForegroundPackageUseTimeInMills(), - pkg1.getLatestForegroundPackageUseTimeInMills())); + Collections.sort(pkgSettings, (pkgSetting1, pkgSetting2) -> + Long.compare( + pkgSetting2.getPkgState().getLatestForegroundPackageUseTimeInMills(), + pkgSetting1.getPkgState().getLatestForegroundPackageUseTimeInMills()) + ); } // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the // package will be removed from {@code packages} and added to {@code result} with its // dependencies. If usage data is available, the positive packages will be sorted by usage // data (with {@code sortTemp} as temporary storage). - private static void applyPackageFilter(Predicate<AndroidPackage> filter, - Collection<AndroidPackage> result, - Collection<AndroidPackage> packages, - @NonNull List<AndroidPackage> sortTemp, + private static void applyPackageFilter( + Predicate<PackageSetting> filter, + Collection<PackageSetting> result, + Collection<PackageSetting> packages, + @NonNull List<PackageSetting> sortTemp, PackageManagerService packageManagerService) { - for (AndroidPackage pkg : packages) { - if (filter.test(pkg)) { - sortTemp.add(pkg); + for (PackageSetting pkgSetting : packages) { + if (filter.test(pkgSetting)) { + sortTemp.add(pkgSetting); } } sortPackagesByUsageDate(sortTemp, packageManagerService); packages.removeAll(sortTemp); - for (AndroidPackage pkg : sortTemp) { - result.add(pkg); + for (PackageSetting pkgSetting : sortTemp) { + result.add(pkgSetting); - Collection<AndroidPackage> deps = - packageManagerService.findSharedNonSystemLibraries(pkg); + List<PackageSetting> deps = + packageManagerService.findSharedNonSystemLibraries(pkgSetting); if (!deps.isEmpty()) { deps.removeAll(result); result.addAll(deps); @@ -170,74 +178,79 @@ public class PackageManagerServiceUtils { // Sort apps by importance for dexopt ordering. Important apps are given // more priority in case the device runs out of space. - public static List<AndroidPackage> getPackagesForDexopt( - Collection<AndroidPackage> packages, + public static List<PackageSetting> getPackagesForDexopt( + Collection<PackageSetting> packages, PackageManagerService packageManagerService) { return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT); } - public static List<AndroidPackage> getPackagesForDexopt( - Collection<AndroidPackage> packages, + public static List<PackageSetting> getPackagesForDexopt( + Collection<PackageSetting> pkgSettings, PackageManagerService packageManagerService, boolean debug) { - ArrayList<AndroidPackage> remainingPkgs = new ArrayList<>(packages); - LinkedList<AndroidPackage> result = new LinkedList<>(); - ArrayList<AndroidPackage> sortTemp = new ArrayList<>(remainingPkgs.size()); + List<PackageSetting> result = new LinkedList<>(); + ArrayList<PackageSetting> remainingPkgSettings = new ArrayList<>(pkgSettings); + + // First, remove all settings without available packages + remainingPkgSettings.removeIf(REMOVE_IF_NULL_PKG); + + ArrayList<PackageSetting> sortTemp = new ArrayList<>(remainingPkgSettings.size()); // Give priority to core apps. - applyPackageFilter((pkg) -> pkg.isCoreApp(), result, remainingPkgs, sortTemp, + applyPackageFilter(pkgSetting -> pkgSetting.pkg.isCoreApp(), result, remainingPkgSettings, sortTemp, packageManagerService); // Give priority to system apps that listen for pre boot complete. Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM); - applyPackageFilter((pkg) -> pkgNames.contains(pkg.getPackageName()), result, remainingPkgs, - sortTemp, packageManagerService); + applyPackageFilter(pkgSetting -> pkgNames.contains(pkgSetting.name), result, + remainingPkgSettings, sortTemp, packageManagerService); // Give priority to apps used by other apps. DexManager dexManager = packageManagerService.getDexManager(); - applyPackageFilter((pkg) -> - dexManager.getPackageUseInfoOrDefault(pkg.getPackageName()) + applyPackageFilter(pkgSetting -> + dexManager.getPackageUseInfoOrDefault(pkgSetting.name) .isAnyCodePathUsedByOtherApps(), - result, remainingPkgs, sortTemp, packageManagerService); + result, remainingPkgSettings, sortTemp, packageManagerService); // Filter out packages that aren't recently used, add all remaining apps. // TODO: add a property to control this? - Predicate<AndroidPackage> remainingPredicate; - if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) { + Predicate<PackageSetting> remainingPredicate; + if (!remainingPkgSettings.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) { if (debug) { Log.i(TAG, "Looking at historical package use"); } // Get the package that was used last. - AndroidPackage lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) -> - Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(), - pkg2.getLatestForegroundPackageUseTimeInMills())); + PackageSetting lastUsed = Collections.max(remainingPkgSettings, + (pkgSetting1, pkgSetting2) -> Long.compare( + pkgSetting1.getPkgState().getLatestForegroundPackageUseTimeInMills(), + pkgSetting2.getPkgState().getLatestForegroundPackageUseTimeInMills())); if (debug) { - Log.i(TAG, "Taking package " + lastUsed.getPackageName() + Log.i(TAG, "Taking package " + lastUsed.name + " as reference in time use"); } - long estimatedPreviousSystemUseTime = - lastUsed.getLatestForegroundPackageUseTimeInMills(); + long estimatedPreviousSystemUseTime = lastUsed.getPkgState() + .getLatestForegroundPackageUseTimeInMills(); // Be defensive if for some reason package usage has bogus data. if (estimatedPreviousSystemUseTime != 0) { final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS; - remainingPredicate = - (pkg) -> pkg.getLatestForegroundPackageUseTimeInMills() >= cutoffTime; + remainingPredicate = pkgSetting -> pkgSetting.getPkgState() + .getLatestForegroundPackageUseTimeInMills() >= cutoffTime; } else { // No meaningful historical info. Take all. - remainingPredicate = (pkg) -> true; + remainingPredicate = pkgSetting -> true; } - sortPackagesByUsageDate(remainingPkgs, packageManagerService); + sortPackagesByUsageDate(remainingPkgSettings, packageManagerService); } else { // No historical info. Take all. - remainingPredicate = (pkg) -> true; + remainingPredicate = pkgSetting -> true; } - applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp, + applyPackageFilter(remainingPredicate, result, remainingPkgSettings, sortTemp, packageManagerService); if (debug) { Log.i(TAG, "Packages to be dexopted: " + packagesToString(result)); - Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs)); + Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgSettings)); } return result; @@ -290,13 +303,13 @@ public class PackageManagerServiceUtils { } } - public static String packagesToString(Collection<AndroidPackage> c) { + public static String packagesToString(List<PackageSetting> pkgSettings) { StringBuilder sb = new StringBuilder(); - for (AndroidPackage pkg : c) { + for (int index = 0; index < pkgSettings.size(); index++) { if (sb.length() > 0) { sb.append(", "); } - sb.append(pkg.getPackageName()); + sb.append(pkgSettings.get(index).name); } return sb.toString(); } @@ -543,23 +556,16 @@ public class PackageManagerServiceUtils { */ private static boolean matchSignatureInSystem(PackageSetting pkgSetting, PackageSetting disabledPkgSetting) { - try { - ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */); - if (pkgSetting.signatures.mSigningDetails.checkCapability( - disabledPkgSetting.signatures.mSigningDetails, - PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA) - || disabledPkgSetting.signatures.mSigningDetails.checkCapability( - pkgSetting.signatures.mSigningDetails, - PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) { - return true; - } else { - logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " + - pkgSetting.name); - return false; - } - } catch (PackageParserException e) { - logCriticalInfo(Log.ERROR, "Failed to collect cert for " + pkgSetting.name + ": " + - e.getMessage()); + if (pkgSetting.signatures.mSigningDetails.checkCapability( + disabledPkgSetting.signatures.mSigningDetails, + PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA) + || disabledPkgSetting.signatures.mSigningDetails.checkCapability( + pkgSetting.signatures.mSigningDetails, + PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) { + return true; + } else { + logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " + + pkgSetting.name); return false; } } @@ -642,8 +648,8 @@ public class PackageManagerServiceUtils { } } // Check for shared user signatures - if (pkgSetting.sharedUser != null - && pkgSetting.sharedUser.signatures.mSigningDetails + if (pkgSetting.getSharedUser() != null + && pkgSetting.getSharedUser().signatures.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) { // Already existing package. Make sure signatures match. In case of signing certificate @@ -653,24 +659,24 @@ public class PackageManagerServiceUtils { // with being sharedUser with the existing signing cert. boolean match = parsedSignatures.checkCapability( - pkgSetting.sharedUser.signatures.mSigningDetails, + pkgSetting.getSharedUser().signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID) - || pkgSetting.sharedUser.signatures.mSigningDetails.checkCapability( + || pkgSetting.getSharedUser().signatures.mSigningDetails.checkCapability( parsedSignatures, PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID); if (!match && compareCompat) { match = matchSignaturesCompat( - packageName, pkgSetting.sharedUser.signatures, parsedSignatures); + packageName, pkgSetting.getSharedUser().signatures, parsedSignatures); } if (!match && compareRecover) { match = matchSignaturesRecover(packageName, - pkgSetting.sharedUser.signatures.mSigningDetails, + pkgSetting.getSharedUser().signatures.mSigningDetails, parsedSignatures, PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID) || matchSignaturesRecover(packageName, parsedSignatures, - pkgSetting.sharedUser.signatures.mSigningDetails, + pkgSetting.getSharedUser().signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID); compatMatch |= match; } @@ -678,7 +684,7 @@ public class PackageManagerServiceUtils { throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, "Package " + packageName + " has no signatures that match those in shared user " - + pkgSetting.sharedUser.name + "; ignoring!"); + + pkgSetting.getSharedUser().name + "; ignoring!"); } } return compatMatch; @@ -823,11 +829,11 @@ public class PackageManagerServiceUtils { * Checks whenever downgrade of an app is permitted. * * @param installFlags flags of the current install. - * @param applicationFlags flags of the currently installed version of the app. + * @param isAppDebuggable if the currently installed version of the app is debuggable. * @return {@code true} if downgrade is permitted according to the {@code installFlags} and * {@code applicationFlags}. */ - public static boolean isDowngradePermitted(int installFlags, int applicationFlags) { + public static boolean isDowngradePermitted(int installFlags, boolean isAppDebuggable) { // If installed, the package will get access to data left on the device by its // predecessor. As a security measure, this is permitted only if this is not a // version downgrade or if the predecessor package is marked as debuggable and @@ -849,9 +855,7 @@ public class PackageManagerServiceUtils { if (!downgradeRequested) { return false; } - final boolean isDebuggable = - Build.IS_DEBUGGABLE || ((applicationFlags - & ApplicationInfo.FLAG_DEBUGGABLE) != 0); + final boolean isDebuggable = Build.IS_DEBUGGABLE || isAppDebuggable; if (isDebuggable) { return true; } @@ -915,8 +919,8 @@ public class PackageManagerServiceUtils { */ public static PermissionsState getPermissionsState( PackageManagerInternal packageManagerInternal, AndroidPackage pkg) { - final PackageSetting packageSetting = - (PackageSetting) packageManagerInternal.getPackageSetting(pkg.getPackageName()); + final PackageSetting packageSetting = packageManagerInternal.getPackageSetting( + pkg.getPackageName()); if (packageSetting == null) { return null; } diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index d83e6f4c7418..2bd1a26f1e28 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -16,18 +16,19 @@ package com.android.server.pm; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ParsedPackage; import android.service.pm.PackageProto; import android.util.ArrayMap; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.permission.PermissionsState; +import com.android.server.pm.pkg.PackageStateUnserialized; import java.io.File; import java.util.ArrayList; @@ -39,8 +40,7 @@ import java.util.Set; /** * Settings data for a particular package we know about. */ -public final class PackageSetting extends PackageSettingBase implements - ParsedPackage.PackageSettingCallback { +public class PackageSetting extends PackageSettingBase { int appId; public AndroidPackage pkg; @@ -65,6 +65,9 @@ public final class PackageSetting extends PackageSettingBase implements @Nullable Map<String, ArraySet<String>> mimeGroups; + @NonNull + private PackageStateUnserialized pkgState = new PackageStateUnserialized(); + PackageSetting(String name, String realName, File codePath, File resourcePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, @@ -223,10 +226,6 @@ public final class PackageSetting extends PackageSettingBase implements return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; } - public boolean isUpdatedSystem() { - return (pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; - } - @Override public boolean isSharedUser() { return sharedUser != null; @@ -324,9 +323,8 @@ public final class PackageSetting extends PackageSettingBase implements updateMimeGroups(mimeGroupNames); } - // TODO(b/135203078): Move to constructor - @Override - public void setAndroidPackage(AndroidPackage pkg) { - this.pkg = pkg; + @NonNull + public PackageStateUnserialized getPkgState() { + return pkgState; } } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 7d95b198d8ce..18bc879b978b 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -78,12 +78,12 @@ public abstract class PackageSettingBase extends SettingBase { /** * The primary CPU abi for this package. */ - String primaryCpuAbiString; + public String primaryCpuAbiString; /** * The secondary CPU abi for this package. */ - String secondaryCpuAbiString; + public String secondaryCpuAbiString; /** * The install time CPU override, if any. This value is written at install time diff --git a/services/core/java/com/android/server/pm/PackageUsage.java b/services/core/java/com/android/server/pm/PackageUsage.java index ce2c9e767d5e..ef37a20479d6 100644 --- a/services/core/java/com/android/server/pm/PackageUsage.java +++ b/services/core/java/com/android/server/pm/PackageUsage.java @@ -20,11 +20,12 @@ import static android.os.Process.PACKAGE_INFO_GID; import static android.os.Process.SYSTEM_UID; import android.content.pm.PackageManager; -import android.content.pm.parsing.AndroidPackage; import android.os.FileUtils; import android.util.AtomicFile; import android.util.Log; +import com.android.server.pm.parsing.pkg.AndroidPackage; + import libcore.io.IoUtils; import java.io.BufferedInputStream; @@ -36,7 +37,7 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Map; -class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { +class PackageUsage extends AbstractStatsBase<Map<String, PackageSetting>> { private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_"; private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1"; @@ -52,7 +53,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { } @Override - protected void writeInternal(Map<String, AndroidPackage> packages) { + protected void writeInternal(Map<String, PackageSetting> pkgSettings) { AtomicFile file = getFile(); FileOutputStream f = null; try { @@ -66,13 +67,14 @@ class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { sb.append('\n'); out.write(sb.toString().getBytes(StandardCharsets.US_ASCII)); - for (AndroidPackage pkg : packages.values()) { - if (pkg.getLatestPackageUseTimeInMills() == 0L) { + for (PackageSetting pkgSetting : pkgSettings.values()) { + if (pkgSetting.getPkgState().getLatestPackageUseTimeInMills() == 0L) { continue; } sb.setLength(0); - sb.append(pkg.getPackageName()); - for (long usageTimeInMillis : pkg.getLastPackageUsageTimeInMills()) { + sb.append(pkgSetting.name); + for (long usageTimeInMillis : pkgSetting.getPkgState() + .getLastPackageUsageTimeInMills()) { sb.append(' '); sb.append(usageTimeInMillis); } @@ -90,7 +92,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { } @Override - protected void readInternal(Map<String, AndroidPackage> packages) { + protected void readInternal(Map<String, PackageSetting> pkgSettings) { AtomicFile file = getFile(); BufferedInputStream in = null; try { @@ -101,9 +103,9 @@ class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { if (firstLine == null) { // Empty file. Do nothing. } else if (USAGE_FILE_MAGIC_VERSION_1.equals(firstLine)) { - readVersion1LP(packages, in, sb); + readVersion1LP(pkgSettings, in, sb); } else { - readVersion0LP(packages, in, sb, firstLine); + readVersion0LP(pkgSettings, in, sb, firstLine); } } catch (FileNotFoundException expected) { mIsHistoricalPackageUsageAvailable = false; @@ -114,7 +116,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { } } - private void readVersion0LP(Map<String, AndroidPackage> packages, InputStream in, + private void readVersion0LP(Map<String, PackageSetting> pkgSettings, InputStream in, StringBuffer sb, String firstLine) throws IOException { // Initial version of the file had no version number and stored one @@ -128,8 +130,8 @@ class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { } String packageName = tokens[0]; - AndroidPackage pkg = packages.get(packageName); - if (pkg == null) { + PackageSetting pkgSetting = pkgSettings.get(packageName); + if (pkgSetting == null) { continue; } @@ -137,12 +139,12 @@ class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { for (int reason = 0; reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT; reason++) { - pkg.mutate().setLastPackageUsageTimeInMills(reason, timestamp); + pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason, timestamp); } } } - private void readVersion1LP(Map<String, AndroidPackage> packages, InputStream in, + private void readVersion1LP(Map<String, PackageSetting> pkgSettings, InputStream in, StringBuffer sb) throws IOException { // Version 1 of the file started with the corresponding version // number and then stored a package name and eight timestamps per line. @@ -154,15 +156,15 @@ class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { } String packageName = tokens[0]; - AndroidPackage pkg = packages.get(packageName); - if (pkg == null) { + PackageSetting pkgSetting = pkgSettings.get(packageName); + if (pkgSetting == null) { continue; } for (int reason = 0; reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT; reason++) { - pkg.mutate().setLastPackageUsageTimeInMills(reason, + pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason, parseAsLong(tokens[reason + 1])); } } diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java index 448dad026e16..21334c0f4d19 100644 --- a/services/core/java/com/android/server/pm/ParallelPackageParser.java +++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java @@ -19,12 +19,13 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import android.content.pm.PackageParser; -import android.content.pm.parsing.ParsedPackage; import android.os.Process; import android.os.Trace; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ConcurrentUtils; +import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.parsing.pkg.ParsedPackage; import java.io.File; import java.util.concurrent.ArrayBlockingQueue; @@ -50,11 +51,11 @@ class ParallelPackageParser { Process.THREAD_PRIORITY_FOREGROUND); } - private final PackageParser mPackageParser; + private final PackageParser2 mPackageParser; private final ExecutorService mExecutorService; - ParallelPackageParser(PackageParser packageParser, ExecutorService executorService) { + ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) { mPackageParser = packageParser; mExecutorService = executorService; } @@ -125,6 +126,6 @@ class ParallelPackageParser { @VisibleForTesting protected ParsedPackage parsePackage(File scanFile, int parseFlags) throws PackageParser.PackageParserException { - return mPackageParser.parseParsedPackage(scanFile, parseFlags, true); + return mPackageParser.parsePackage(scanFile, parseFlags, true); } } diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java index ef29cb348938..08a87d88382a 100644 --- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java +++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java @@ -16,6 +16,9 @@ package com.android.server.pm; +import android.annotation.NonNull; +import android.content.IntentFilter; + import com.android.server.IntentResolver; public class PersistentPreferredIntentResolver @@ -26,6 +29,11 @@ public class PersistentPreferredIntentResolver } @Override + protected IntentFilter getIntentFilter(@NonNull PersistentPreferredActivity input) { + return input; + } + + @Override protected boolean isPackageForFilter(String packageName, PersistentPreferredActivity filter) { return packageName.equals(filter.mComponent.getPackageName()); } diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java index bce24d7b8817..a261e29b05a7 100644 --- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java +++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java @@ -16,6 +16,9 @@ package com.android.server.pm; +import android.annotation.NonNull; +import android.content.IntentFilter; + import java.io.PrintWriter; import com.android.server.IntentResolver; @@ -37,4 +40,9 @@ public class PreferredIntentResolver PreferredActivity filter) { filter.mPref.dump(out, prefix, filter); } + + @Override + protected IntentFilter getIntentFilter(@NonNull PreferredActivity input) { + return input; + } } diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java index 466f19c43289..67e1994eac9a 100644 --- a/services/core/java/com/android/server/pm/SELinuxMMAC.java +++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java @@ -18,15 +18,14 @@ package com.android.server.pm; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; -import android.content.pm.PackageParser; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.Signature; -import android.content.pm.parsing.AndroidPackage; import android.os.Environment; import android.util.Slog; import android.util.Xml; import com.android.server.compat.PlatformCompat; +import com.android.server.pm.parsing.pkg.AndroidPackage; import libcore.io.IoUtils; diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 60c8b949ec52..42b2eebd63a7 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -49,10 +49,12 @@ import android.content.pm.Signature; import android.content.pm.SuspendDialogInfo; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils; -import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.PackageInfoWithoutStateUtils; +import android.content.pm.parsing.component.ParsedComponent; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedMainComponent; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedProcess; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -76,6 +78,7 @@ import android.util.ArraySet; import android.util.AtomicFile; import android.util.Log; import android.util.LogPrinter; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -96,6 +99,9 @@ import com.android.permission.persistence.RuntimePermissionsPersistence; import com.android.permission.persistence.RuntimePermissionsState; import com.android.server.LocalServices; import com.android.server.pm.Installer.InstallerException; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import com.android.server.pm.permission.BasePermission; import com.android.server.pm.permission.PermissionSettings; import com.android.server.pm.permission.PermissionsState; @@ -479,10 +485,9 @@ public final class Settings { } final PackageSetting dp = mDisabledSysPackages.get(name); // always make sure the system package code and resource paths dont change - if (dp == null && p.pkg != null && p.pkg.isSystem() && !p.pkg.isUpdatedSystemApp()) { - if(p.pkg != null) { - p.pkg.mutate().setUpdatedSystemApp(true); - } + if (dp == null && p.pkg != null && p.pkg.isSystem() + && !p.getPkgState().isUpdatedSystemApp()) { + p.getPkgState().setUpdatedSystemApp(true); final PackageSetting disabled; if (replaced) { // a little trick... when we install the new package, we don't @@ -506,10 +511,7 @@ public final class Settings { Log.w(PackageManagerService.TAG, "Package " + name + " is not disabled"); return null; } - // Reset flag in ApplicationInfo object - if(p.pkg != null) { - p.pkg.mutate().setUpdatedSystemApp(false); - } + p.getPkgState().setUpdatedSystemApp(false); PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath, p.legacyNativeLibraryPathString, p.primaryCpuAbiString, p.secondaryCpuAbiString, p.cpuAbiOverrideString, @@ -2673,15 +2675,19 @@ public final class Settings { StringBuilder sb = new StringBuilder(); for (final PackageSetting pkg : mPackages.values()) { - if (pkg.pkg == null || pkg.pkg.getDataDir() == null) { + // TODO(b/135203078): This doesn't handle multiple users + final String dataPath = pkg.pkg == null ? null : + PackageInfoWithoutStateUtils.getDataDir(pkg.pkg, + UserHandle.USER_SYSTEM).getAbsolutePath(); + + if (pkg.pkg == null || dataPath == null) { if (!"android".equals(pkg.name)) { Slog.w(TAG, "Skipping " + pkg + " due to missing metadata"); } continue; } - final String dataPath = pkg.pkg.getDataDir(); - final boolean isDebug = (pkg.pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + final boolean isDebug = pkg.pkg.isDebuggable(); final int[] gids = pkg.getPermissionsState().computeGids(userIds); // Avoid any application that has a space in its path. @@ -2712,7 +2718,7 @@ public final class Settings { sb.append(isDebug ? " 1 " : " 0 "); sb.append(dataPath); sb.append(" "); - sb.append(pkg.pkg.getSeInfo()); + sb.append(AndroidPackageUtils.getSeInfo(pkg.pkg, pkg)); sb.append(" "); if (gids != null && gids.length > 0) { sb.append(gids[0]); @@ -3154,14 +3160,14 @@ public final class Settings { final PackageManagerInternal pmInternal = LocalServices.getService(PackageManagerInternal.class); for (PackageSetting ps : mPackages.values()) { - if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null - && ps.pkg.getPreferredActivityFilters() != null) { - List<ComponentParseUtils.ParsedActivityIntentInfo> intents + if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null + && !ps.pkg.getPreferredActivityFilters().isEmpty()) { + List<Pair<String, ParsedIntentInfo>> intents = ps.pkg.getPreferredActivityFilters(); for (int i=0; i<intents.size(); i++) { - ComponentParseUtils.ParsedActivityIntentInfo aii = intents.get(i); - applyDefaultPreferredActivityLPw(pmInternal, aii, new ComponentName( - ps.name, aii.getClassName()), userId); + Pair<String, ParsedIntentInfo> pair = intents.get(i); + applyDefaultPreferredActivityLPw(pmInternal, pair.second, new ComponentName( + ps.name, pair.first), userId); } } } @@ -4129,7 +4135,7 @@ public final class Settings { final boolean shouldInstall = ps.isSystem() && (skipPackageWhitelist || installablePackages.contains(ps.name)) && !ArrayUtils.contains(disallowedPackages, ps.name) && - !ps.pkg.isHiddenUntilInstalled(); + !ps.getPkgState().isHiddenUntilInstalled(); // Only system apps are initially installed. ps.setInstalled(shouldInstall, userHandle); if (!shouldInstall) { @@ -4140,7 +4146,7 @@ public final class Settings { volumeUuids[i] = ps.volumeUuid; names[i] = ps.name; appIds[i] = ps.appId; - seinfos[i] = ps.pkg.getSeInfo(); + seinfos[i] = AndroidPackageUtils.getSeInfo(ps.pkg, ps); targetSdkVersions[i] = ps.pkg.getTargetSdkVersion(); } } @@ -4281,7 +4287,7 @@ public final class Settings { return userState.isMatch(componentInfo, flags); } - boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedComponent component, int flags, + boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedMainComponent component, int flags, int userId) { final PackageSetting ps = mPackages.get(component.getPackageName()); if (ps == null) return false; @@ -4596,58 +4602,60 @@ public final class Settings { pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion); // TODO(b/135203078): Is there anything to print here with AppInfo removed? pw.print(prefix); pw.print(" applicationInfo="); - pw.println(pkg.toAppInfoWithoutState().toString()); - pw.print(prefix); pw.print(" flags="); printFlags(pw, pkg.getFlags(), - FLAG_DUMP_SPEC); pw.println(); - if (pkg.getPrivateFlags() != 0) { + pw.println(pkg.toAppInfoToString()); + pw.print(prefix); pw.print(" flags="); + printFlags(pw, PackageInfoUtils.appInfoFlags(pkg, ps), FLAG_DUMP_SPEC); pw.println(); + int privateFlags = PackageInfoUtils.appInfoPrivateFlags(pkg, ps); + if (privateFlags != 0) { pw.print(prefix); pw.print(" privateFlags="); printFlags(pw, - pkg.getPrivateFlags(), PRIVATE_FLAG_DUMP_SPEC); pw.println(); + privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println(); } pw.print(prefix); pw.print(" forceQueryable="); pw.print(ps.pkg.isForceQueryable()); if (ps.forceQueryableOverride) { pw.print(" (override=true)"); } pw.println(); - if (ps.pkg.getQueriesPackages() != null) { + if (ps.pkg.getQueriesPackages().isEmpty()) { pw.append(prefix).append(" queriesPackages=").println(ps.pkg.getQueriesPackages()); } - if (ps.pkg.getQueriesIntents() != null) { + if (!ps.pkg.getQueriesIntents().isEmpty()) { pw.append(prefix).append(" queriesIntents=").println(ps.pkg.getQueriesIntents()); } - pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.getDataDir()); + File dataDir = PackageInfoWithoutStateUtils.getDataDir(pkg, UserHandle.myUserId()); + pw.print(prefix); pw.print(" dataDir="); pw.println(dataDir.getAbsolutePath()); pw.print(prefix); pw.print(" supportsScreens=["); boolean first = true; - if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { + if (pkg.isSupportsSmallScreens()) { if (!first) pw.print(", "); first = false; pw.print("small"); } - if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) { + if (pkg.isSupportsNormalScreens()) { if (!first) pw.print(", "); first = false; pw.print("medium"); } - if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { + if (pkg.isSupportsLargeScreens()) { if (!first) pw.print(", "); first = false; pw.print("large"); } - if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { + if (pkg.isSupportsExtraLargeScreens()) { if (!first) pw.print(", "); first = false; pw.print("xlarge"); } - if ((pkg.getFlags() & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { + if (pkg.isResizeable()) { if (!first) pw.print(", "); first = false; pw.print("resizeable"); } - if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { + if (pkg.isAnyDensity()) { if (!first) pw.print(", "); first = false; @@ -4669,18 +4677,17 @@ public final class Settings { pw.print(" version:"); pw.println(pkg.getStaticSharedLibVersion()); } - final List<String> usesLibraries = pkg.getUsesLibraries(); - if (usesLibraries != null && usesLibraries.size() > 0) { + List<String> usesLibraries = pkg.getUsesLibraries(); + if (usesLibraries.size() > 0) { pw.print(prefix); pw.println(" usesLibraries:"); for (int i=0; i< usesLibraries.size(); i++) { pw.print(prefix); pw.print(" "); pw.println(usesLibraries.get(i)); } } - final List<String> usesStaticLibraries = pkg.getUsesStaticLibraries(); - final long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions(); - if (usesStaticLibraries != null - && usesStaticLibraries.size() > 0) { + List<String> usesStaticLibraries = pkg.getUsesStaticLibraries(); + long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions(); + if (usesStaticLibraries.size() > 0) { pw.print(prefix); pw.println(" usesStaticLibraries:"); for (int i=0; i< usesStaticLibraries.size(); i++) { pw.print(prefix); pw.print(" "); @@ -4689,9 +4696,8 @@ public final class Settings { } } - final List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries(); - if (usesOptionalLibraries != null - && usesOptionalLibraries.size() > 0) { + List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries(); + if (usesOptionalLibraries.size() > 0) { pw.print(prefix); pw.println(" usesOptionalLibraries:"); for (int i=0; i< usesOptionalLibraries.size(); i++) { pw.print(prefix); pw.print(" "); @@ -4699,24 +4705,22 @@ public final class Settings { } } - final String[] usesLibraryFiles = pkg.getUsesLibraryFiles(); - if (usesLibraryFiles != null - && usesLibraryFiles.length > 0) { + List<String> usesLibraryFiles = ps.getPkgState().getUsesLibraryFiles(); + if (usesLibraryFiles.size() > 0) { pw.print(prefix); pw.println(" usesLibraryFiles:"); - for (int i=0; i< usesLibraryFiles.length; i++) { - pw.print(prefix); pw.print(" "); pw.println(usesLibraryFiles[i]); + for (int i=0; i< usesLibraryFiles.size(); i++) { + pw.print(prefix); pw.print(" "); pw.println(usesLibraryFiles.get(i)); } } - final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses(); - if (procs != null) { + final Map<String, ParsedProcess> procs = pkg.getProcesses(); + if (!procs.isEmpty()) { pw.print(prefix); pw.println(" processes:"); - for (int i = 0; i < procs.size(); i++) { - final ComponentParseUtils.ParsedProcess proc = procs.valueAt(i); - pw.print(prefix); pw.print(" "); pw.println(proc.name); - if (proc.deniedPermissions != null) { - for (int j = 0; j < proc.deniedPermissions.size(); j++) { + for (ParsedProcess proc : procs.values()) { + pw.print(prefix); pw.print(" "); pw.println(proc.getName()); + if (proc.getDeniedPermissions() != null) { + for (String deniedPermission : proc.getDeniedPermissions()) { pw.print(prefix); pw.print(" deny: "); - pw.println(proc.deniedPermissions.valueAt(j)); + pw.println(deniedPermission); } } } @@ -4751,7 +4755,7 @@ public final class Settings { pw.print(prefix); pw.print(" overlayCategory="); pw.println(pkg.getOverlayCategory()); } - if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) { + if (pkg != null && !pkg.getPermissions().isEmpty()) { final List<ParsedPermission> perms = pkg.getPermissions(); pw.print(prefix); pw.println(" declared permissions:"); for (int i=0; i<perms.size(); i++) { @@ -4762,14 +4766,14 @@ public final class Settings { } pw.print(prefix); pw.print(" "); pw.print(perm.getName()); pw.print(": prot="); - pw.print(PermissionInfo.protectionToString(perm.protectionLevel)); - if ((perm.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) { + pw.print(PermissionInfo.protectionToString(perm.getProtectionLevel())); + if ((perm.getFlags() &PermissionInfo.FLAG_COSTS_MONEY) != 0) { pw.print(", COSTS_MONEY"); } - if ((perm.flags&PermissionInfo.FLAG_REMOVED) != 0) { + if ((perm.getFlags() &PermissionInfo.FLAG_REMOVED) != 0) { pw.print(", HIDDEN"); } - if ((perm.flags&PermissionInfo.FLAG_INSTALLED) != 0) { + if ((perm.getFlags() &PermissionInfo.FLAG_INSTALLED) != 0) { pw.print(", INSTALLED"); } pw.println(); @@ -5403,7 +5407,7 @@ public final class Settings { packagePermissions, sharedUserPermissions); } - mPersistence.write(runtimePermissions, UserHandle.of(userId)); + mPersistence.writeAsUser(runtimePermissions, UserHandle.of(userId)); } @NonNull @@ -5457,12 +5461,13 @@ public final class Settings { } public void deleteUserRuntimePermissionsFile(int userId) { - mPersistence.delete(UserHandle.of(userId)); + mPersistence.deleteAsUser(UserHandle.of(userId)); } @GuardedBy("Settings.this.mLock") public void readStateForUserSyncLPr(int userId) { - RuntimePermissionsState runtimePermissions = mPersistence.read(UserHandle.of(userId)); + RuntimePermissionsState runtimePermissions = mPersistence.readAsUser(UserHandle.of( + userId)); if (runtimePermissions == null) { readLegacyStateForUserSyncLPr(userId); writePermissionsForUserAsyncLPr(userId); diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index bbd319cb1c69..6103f558bd25 100644 --- a/services/core/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java @@ -18,19 +18,20 @@ package com.android.server.pm; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.component.ParsedProcess; import android.service.pm.PackageServiceDumpProto; import android.util.ArrayMap; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; import libcore.util.EmptyArray; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Settings data for a particular shared user ID we know about. @@ -53,7 +54,7 @@ public final class SharedUserSetting extends SettingBase { final PackageSignatures signatures = new PackageSignatures(); Boolean signaturesChanged; - ArrayMap<String, ComponentParseUtils.ParsedProcess> processes; + ArrayMap<String, ParsedProcess> processes; SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) { super(_pkgFlags, _pkgPrivateFlags); @@ -76,18 +77,18 @@ public final class SharedUserSetting extends SettingBase { proto.end(token); } - void addProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> newProcs) { + void addProcesses(Map<String, ParsedProcess> newProcs) { if (newProcs != null) { final int numProcs = newProcs.size(); if (processes == null) { processes = new ArrayMap<>(numProcs); } - for (int i = 0; i < numProcs; i++) { - ComponentParseUtils.ParsedProcess newProc = newProcs.valueAt(i); - ComponentParseUtils.ParsedProcess proc = processes.get(newProc.name); + for (String key : newProcs.keySet()) { + ParsedProcess newProc = newProcs.get(key); + ParsedProcess proc = processes.get(newProc.getName()); if (proc == null) { - proc = new ComponentParseUtils.ParsedProcess(newProc); - processes.put(newProc.name, proc); + proc = new ParsedProcess(newProc); + processes.put(newProc.getName(), proc); } else { proc.addStateFrom(newProc); } @@ -159,19 +160,24 @@ public final class SharedUserSetting extends SettingBase { * restrictive selinux domain. */ public void fixSeInfoLocked() { - final List<AndroidPackage> pkgList = getPackages(); - if (pkgList == null || pkgList.size() == 0) { + if (packages == null || packages.size() == 0) { return; } - - for (AndroidPackage pkg : pkgList) { - if (pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) { - seInfoTargetSdkVersion = pkg.getTargetSdkVersion(); + for (PackageSetting ps : packages) { + if ((ps == null) || (ps.pkg == null)) { + continue; + } + if (ps.pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) { + seInfoTargetSdkVersion = ps.pkg.getTargetSdkVersion(); } } - for (AndroidPackage pkg : pkgList) { - final boolean isPrivileged = isPrivileged() | pkg.isPrivileged(); - pkg.mutate().setSeInfo(SELinuxMMAC.getSeInfo(pkg, isPrivileged, + + for (PackageSetting ps : packages) { + if ((ps == null) || (ps.pkg == null)) { + continue; + } + final boolean isPrivileged = isPrivileged() | ps.pkg.isPrivileged(); + ps.getPkgState().setOverrideSeInfo(SELinuxMMAC.getSeInfo(ps.pkg, isPrivileged, seInfoTargetSdkVersion)); } } @@ -221,9 +227,9 @@ public final class SharedUserSetting extends SettingBase { final int numProcs = sharedUser.processes.size(); this.processes = new ArrayMap<>(numProcs); for (int i = 0; i < numProcs; i++) { - ComponentParseUtils.ParsedProcess proc = - new ComponentParseUtils.ParsedProcess(sharedUser.processes.valueAt(i)); - this.processes.put(proc.name, proc); + ParsedProcess proc = + new ParsedProcess(sharedUser.processes.valueAt(i)); + this.processes.put(proc.getName(), proc); } } else { this.processes = null; diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index c37ceb3bc1b0..2de9858d91f9 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -310,6 +310,60 @@ class ShortcutPackage extends ShortcutPackageItem { } /** + * Push a shortcut. If the max number of dynamic shortcuts is already reached, remove the + * shortcut with the lowest rank before adding the new shortcut. + */ + public boolean pushDynamicShortcut(@NonNull ShortcutInfo newShortcut) { + Preconditions.checkArgument(newShortcut.isEnabled(), + "pushDynamicShortcuts() cannot publish disabled shortcuts"); + + newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC); + + final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId()); + boolean wasPinned = false; + + if (oldShortcut == null) { + final ShortcutService service = mShortcutUser.mService; + final int maxShortcuts = service.getMaxActivityShortcuts(); + + final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> all = + sortShortcutsToActivities(); + final ArrayList<ShortcutInfo> activityShortcuts = all.get(newShortcut.getActivity()); + + if (activityShortcuts != null && activityShortcuts.size() == maxShortcuts) { + // Max has reached. Delete the shortcut with lowest rank. + + // Sort by isManifestShortcut() and getRank(). + Collections.sort(activityShortcuts, mShortcutTypeAndRankComparator); + + final ShortcutInfo shortcut = activityShortcuts.get(maxShortcuts - 1); + if (shortcut.isManifestShortcut()) { + // All shortcuts are manifest shortcuts and cannot be removed. + Slog.e(TAG, "Failed to remove manifest shortcut while pushing dynamic shortcut " + + newShortcut.getId()); + return false; + } + + deleteDynamicWithId(shortcut.getId(), /*ignoreInvisible=*/ true); + } + } else { + // It's an update case. + // Make sure the target is updatable. (i.e. should be mutable.) + oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false); + + wasPinned = oldShortcut.isPinned(); + } + + // If it was originally pinned, the new one should be pinned too. + if (wasPinned) { + newShortcut.addFlags(ShortcutInfo.FLAG_PINNED); + } + + forceReplaceShortcutInner(newShortcut); + return true; + } + + /** * Remove all shortcuts that aren't pinned, cached nor dynamic. */ private void removeOrphans() { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 12f7d5c27459..54f9f761241f 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -133,6 +133,7 @@ import java.lang.annotation.RetentionPolicy; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -1946,6 +1947,50 @@ public class ShortcutService extends IShortcutService.Stub { } @Override + public void pushDynamicShortcut(String packageName, ShortcutInfo shortcut, + @UserIdInt int userId) { + verifyCaller(packageName, userId); + verifyShortcutInfoPackage(packageName, shortcut); + + final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( + injectBinderCallingPid(), injectBinderCallingUid()); + + synchronized (mLock) { + throwIfUserLockedL(userId); + + final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); + + ps.ensureNotImmutable(shortcut.getId(), /*ignoreInvisible=*/ true); + fillInDefaultActivity(Arrays.asList(shortcut)); + + if (!shortcut.hasRank()) { + shortcut.setRank(0); + } + // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). + ps.clearAllImplicitRanks(); + shortcut.setImplicitRank(0); + + // Validate the shortcut. + fixUpIncomingShortcutInfo(shortcut, /* forUpdate= */ false); + + // When ranks are changing, we need to insert between ranks, so set the + // "rank changed" flag. + shortcut.setRankChanged(); + + // Push it. + if (!ps.pushDynamicShortcut(shortcut)) { + return; + } + + // Lastly, adjust the ranks. + ps.adjustRanks(); + } + packageShortcutsChanged(packageName, userId); + + verifyStates(); + } + + @Override public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut, IntentSender resultIntent, int userId) { Objects.requireNonNull(shortcut); diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 614cc3fc2f3a..fe992290a3c9 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -29,6 +29,7 @@ import android.content.IIntentSender; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; @@ -39,7 +40,6 @@ import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.ParceledListSlice; -import android.content.pm.parsing.AndroidPackage; import android.content.rollback.IRollbackManager; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; @@ -68,6 +68,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageHelper; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import com.android.server.rollback.WatchdogRollbackLogger; import java.io.File; @@ -284,8 +286,10 @@ public class StagingManager { throws PackageManagerException { final long activeVersion = activePackage.applicationInfo.longVersionCode; final long newVersionCode = newPackage.applicationInfo.longVersionCode; + boolean isAppDebuggable = (activePackage.applicationInfo.flags + & ApplicationInfo.FLAG_DEBUGGABLE) != 0; final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted( - session.params.installFlags, activePackage.applicationInfo.flags); + session.params.installFlags, isAppDebuggable); if (activeVersion > newVersionCode && !allowsDowngrade) { if (!mApexManager.abortStagedSession(session.sessionId)) { Slog.e(TAG, "Failed to abort apex session " + session.sessionId); @@ -426,11 +430,10 @@ public class StagingManager { + "for snapshotting/restoring user data."); return; } - final String seInfo = pkg.getSeInfo(); int appId = -1; long ceDataInode = -1; - final PackageSetting ps = (PackageSetting) mPmi.getPackageSetting(packageName); + final PackageSetting ps = mPmi.getPackageSetting(packageName); if (ps != null) { appId = ps.appId; ceDataInode = ps.getCeDataInode(UserHandle.USER_SYSTEM); @@ -438,6 +441,7 @@ public class StagingManager { // an update, and hence need to restore data for all installed users. final int[] installedUsers = ps.queryInstalledUsers(allUsers, true); + final String seInfo = AndroidPackageUtils.getSeInfo(pkg, ps); try { rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode, seInfo, 0 /*token*/); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index cb755f9cf52f..df3c83aec85a 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -437,7 +437,7 @@ public class UserManagerService extends IUserManager.Stub { /** * Start an {@link IntentSender} when user is unlocked after disabling quiet mode. * - * @see {@link #requestQuietModeEnabled(String, boolean, int, IntentSender)} + * @see #requestQuietModeEnabled(String, boolean, int, IntentSender, int) */ private class DisableQuietModeUserUnlockedCallback extends IProgressListener.Stub { private final IntentSender mTarget; @@ -967,7 +967,16 @@ public class UserManagerService extends IUserManager.Stub { "target should only be specified when we are disabling quiet mode."); } - ensureCanModifyQuietMode(callingPackage, Binder.getCallingUid(), userId, target != null); + final boolean dontAskCredential = + (flags & UserManager.QUIET_MODE_DISABLE_DONT_ASK_CREDENTIAL) != 0; + final boolean onlyIfCredentialNotRequired = + (flags & UserManager.QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED) != 0; + if (dontAskCredential && onlyIfCredentialNotRequired) { + throw new IllegalArgumentException("invalid flags: " + flags); + } + + ensureCanModifyQuietMode( + callingPackage, Binder.getCallingUid(), userId, target != null, dontAskCredential); final long identity = Binder.clearCallingIdentity(); try { if (enableQuietMode) { @@ -976,11 +985,11 @@ public class UserManagerService extends IUserManager.Stub { return true; } mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId); - boolean needToShowConfirmCredential = - mLockPatternUtils.isSecure(userId) - && !StorageManager.isUserKeyUnlocked(userId); + final boolean needToShowConfirmCredential = !dontAskCredential + && mLockPatternUtils.isSecure(userId) + && !StorageManager.isUserKeyUnlocked(userId); if (needToShowConfirmCredential) { - if ((flags & UserManager.QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED) != 0) { + if (onlyIfCredentialNotRequired) { return false; } showConfirmCredentialToDisableQuietMode(userId, target); @@ -1007,7 +1016,7 @@ public class UserManagerService extends IUserManager.Stub { * {@link Manifest.permission#MANAGE_USERS}. */ private void ensureCanModifyQuietMode(String callingPackage, int callingUid, - @UserIdInt int targetUserId, boolean startIntent) { + @UserIdInt int targetUserId, boolean startIntent, boolean dontAskCredential) { if (hasManageUsersPermission()) { return; } @@ -1015,6 +1024,10 @@ public class UserManagerService extends IUserManager.Stub { throw new SecurityException("MANAGE_USERS permission is required to start intent " + "after disabling quiet mode."); } + if (dontAskCredential) { + throw new SecurityException("MANAGE_USERS permission is required to disable quiet " + + "mode without credentials."); + } if (!isSameProfileGroupNoChecks(UserHandle.getUserId(callingUid), targetUserId)) { throw new SecurityException("MANAGE_USERS permission is required to modify quiet mode " + "for a different profile group."); diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java index 4c40448085ff..d6480d35110d 100644 --- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java +++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; -import android.content.pm.parsing.AndroidPackage; import android.content.res.Resources; import android.os.SystemProperties; import android.os.UserHandle; @@ -33,6 +32,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.SystemConfig; +import com.android.server.pm.parsing.pkg.AndroidPackage; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -190,13 +190,14 @@ class UserSystemPackageInstaller { // Install/uninstall system packages per user. for (int userId : mUm.getUserIds()) { final Set<String> userWhitelist = getInstallablePackagesForUserId(userId); - pmInt.forEachPackage(pkg -> { - if (!pkg.isSystem()) { + pmInt.forEachPackageSetting(pkgSetting -> { + AndroidPackage pkg = pkgSetting.pkg; + if (pkg == null || !pkg.isSystem()) { return; } final boolean install = (userWhitelist == null || userWhitelist.contains(pkg.getPackageName())) - && !pkg.isHiddenUntilInstalled(); + && !pkgSetting.getPkgState().isHiddenUntilInstalled(); if (isConsideredUpgrade && !isFirstBoot && !install) { return; // To be careful, we don’t uninstall apps during OTAs } diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index 0caab6dddfe3..51e07faf8443 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -31,7 +31,7 @@ import android.content.pm.dex.ArtManagerInternal; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; import android.content.pm.dex.PackageOptimizationInfo; -import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -54,6 +54,7 @@ import com.android.server.LocalServices; import com.android.server.pm.Installer; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.PackageManagerServiceCompilerMapping; +import com.android.server.pm.parsing.pkg.AndroidPackage; import dalvik.system.DexFile; import dalvik.system.VMRuntime; @@ -482,8 +483,10 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { try { final String packageName = pkg.getPackageName(); final String apkPath = pkg.getBaseCodePath(); - final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex"; - if (pkg.isPrivileged() || pkg.isEmbeddedDexUsed() + // TODO(b/143971007): Use a cross-user directory + File dataDir = PackageInfoWithoutStateUtils.getDataDir(pkg, UserHandle.myUserId()); + final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex"; + if (pkg.isPrivileged() || pkg.isUseEmbeddedDex() || pkg.isDefaultToDeviceProtectedStorage()) { // Privileged apps prefer to load trusted code so they don't use compiled views. // If the app is not privileged but prefers code integrity, also avoid compiling @@ -516,7 +519,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { */ private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) { ArrayMap<String, String> result = new ArrayMap<>(); - if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0) { + if (pkg.isHasCode()) { result.put(pkg.getBaseCodePath(), ArtManager.getProfileName(null)); } diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index df24c0130061..117cc5e8eb80 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -41,6 +41,8 @@ import com.android.server.pm.PackageDexOptimizer; import com.android.server.pm.PackageManagerService; import com.android.server.pm.PackageManagerServiceUtils; +import dalvik.system.VMRuntime; + import java.io.File; import java.io.IOException; import java.util.Arrays; @@ -136,22 +138,15 @@ public class DexManager { * return as fast as possible. * * @param loadingAppInfo the package performing the load - * @param classLoadersNames the names of the class loaders present in the loading chain. The - * list encodes the class loader chain in the natural order. The first class loader has - * the second one as its parent and so on. The dex files present in the class path of the - * first class loader will be recorded in the usage file. - * @param classPaths the class paths corresponding to the class loaders names from - * {@param classLoadersNames}. The the first element corresponds to the first class loader - * and so on. A classpath is represented as a list of dex files separated by - * {@code File.pathSeparator}, or null if the class loader's classpath is not known. - * The dex files found in the first class path will be recorded in the usage file. + * @param classLoaderContextMap a map from file paths to dex files that have been loaded to + * the class loader context that was used to load them. * @param loaderIsa the ISA of the app loading the dex files * @param loaderUserId the user id which runs the code loading the dex files */ - public void notifyDexLoad(ApplicationInfo loadingAppInfo, List<String> classLoadersNames, - List<String> classPaths, String loaderIsa, int loaderUserId) { + public void notifyDexLoad(ApplicationInfo loadingAppInfo, + Map<String, String> classLoaderContextMap, String loaderIsa, int loaderUserId) { try { - notifyDexLoadInternal(loadingAppInfo, classLoadersNames, classPaths, loaderIsa, + notifyDexLoadInternal(loadingAppInfo, classLoaderContextMap, loaderIsa, loaderUserId); } catch (Exception e) { Slog.w(TAG, "Exception while notifying dex load for package " + @@ -161,46 +156,23 @@ public class DexManager { @VisibleForTesting /*package*/ void notifyDexLoadInternal(ApplicationInfo loadingAppInfo, - List<String> classLoaderNames, List<String> classPaths, String loaderIsa, + Map<String, String> classLoaderContextMap, String loaderIsa, int loaderUserId) { - if (classLoaderNames.size() != classPaths.size()) { - Slog.wtf(TAG, "Bad call to noitfyDexLoad: args have different size"); + if (classLoaderContextMap == null) { return; } - if (classLoaderNames.isEmpty()) { + if (classLoaderContextMap.isEmpty()) { Slog.wtf(TAG, "Bad call to notifyDexLoad: class loaders list is empty"); return; } if (!PackageManagerServiceUtils.checkISA(loaderIsa)) { - Slog.w(TAG, "Loading dex files " + classPaths + " in unsupported ISA: " + - loaderIsa + "?"); + Slog.w(TAG, "Loading dex files " + classLoaderContextMap.keySet() + + " in unsupported ISA: " + loaderIsa + "?"); return; } - // The first classpath should never be null because the first classloader - // should always be an instance of BaseDexClassLoader. - String firstClassPath = classPaths.get(0); - if (firstClassPath == null) { - return; - } - // The classpath is represented as a list of dex files separated by File.pathSeparator. - String[] dexPathsToRegister = firstClassPath.split(File.pathSeparator); - - // Encode the class loader contexts for the dexPathsToRegister. - String[] classLoaderContexts = DexoptUtils.processContextForDexLoad( - classLoaderNames, classPaths); - - // A null classLoaderContexts means that there are unsupported class loaders in the - // chain. - if (classLoaderContexts == null) { - if (DEBUG) { - Slog.i(TAG, loadingAppInfo.packageName + - " uses unsupported class loader in " + classLoaderNames); - } - } - - int dexPathIndex = 0; - for (String dexPath : dexPathsToRegister) { + for (Map.Entry<String, String> mapping : classLoaderContextMap.entrySet()) { + String dexPath = mapping.getKey(); // Find the owning package name. DexSearchResult searchResult = getDexPackage(loadingAppInfo, dexPath, loaderUserId); @@ -222,7 +194,6 @@ public class DexManager { // If the dex file is the primary apk (or a split) and not isUsedByOtherApps // do not record it. This case does not bring any new usable information // and can be safely skipped. - dexPathIndex++; continue; } @@ -232,13 +203,13 @@ public class DexManager { searchResult.mOwningPackageName, loadingAppInfo.packageName); } - if (classLoaderContexts != null) { - + String classLoaderContext = mapping.getValue(); + if (classLoaderContext != null + && VMRuntime.isValidClassLoaderContext(classLoaderContext)) { // Record dex file usage. If the current usage is a new pattern (e.g. new // secondary, or UsedByOtherApps), record will return true and we trigger an // async write to disk to make sure we don't loose the data in case of a reboot. - String classLoaderContext = classLoaderContexts[dexPathIndex]; if (mPackageDexUsage.record(searchResult.mOwningPackageName, dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit, loadingAppInfo.packageName, classLoaderContext)) { @@ -252,7 +223,6 @@ public class DexManager { Slog.i(TAG, "Could not find owning package for dex file: " + dexPath); } } - dexPathIndex++; } } diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java index 6e6b137d23a2..6807388fa2b2 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java +++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java @@ -18,7 +18,7 @@ package com.android.server.pm.dex; import android.content.pm.ApplicationInfo; import android.content.pm.SharedLibraryInfo; -import android.content.pm.parsing.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackage; import android.util.Slog; import android.util.SparseArray; @@ -77,7 +77,7 @@ public final class DexoptUtils { } String baseApkContextClassLoader = encodeClassLoader( - "", pkg.getAppInfoClassLoaderName(), sharedLibrariesContext); + "", pkg.getClassLoaderName(), sharedLibrariesContext); if (pkg.getSplitCodePaths() == null) { // The application has no splits. return new String[] {baseApkContextClassLoader}; @@ -101,7 +101,7 @@ public final class DexoptUtils { SparseArray<int[]> splitDependencies = pkg.getSplitDependencies(); - if (!pkg.requestsIsolatedSplitLoading() + if (!pkg.isIsolatedSplitLoading() || splitDependencies == null || splitDependencies.size() == 0) { // If the app didn't request for the splits to be loaded in isolation or if it does not @@ -111,7 +111,7 @@ public final class DexoptUtils { for (int i = 1; i < classLoaderContexts.length; i++) { if (pathsWithCode[i]) { classLoaderContexts[i] = encodeClassLoader( - classpath, pkg.getAppInfoClassLoaderName(), sharedLibrariesContext); + classpath, pkg.getClassLoaderName(), sharedLibrariesContext); } else { classLoaderContexts[i] = null; } diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java index e68c2386e03b..08763e729c71 100644 --- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java +++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java @@ -83,8 +83,9 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { "=UnknownClassLoaderContext="; // The marker used for unsupported class loader contexts (no longer written, may occur in old - // files so discarded on read). - private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT = + // files so discarded on read). Note: this matches + // ClassLoaderContext::kUnsupportedClassLoaderContextEncoding in the runtime. + /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT = "=UnsupportedClassLoaderContext="; /** @@ -133,6 +134,9 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { if (classLoaderContext == null) { throw new IllegalArgumentException("Null classLoaderContext"); } + if (classLoaderContext.equals(UNSUPPORTED_CLASS_LOADER_CONTEXT)) { + return false; + } synchronized (mPackageUseInfoMap) { PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName); @@ -843,10 +847,11 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages); String oldClassLoaderContext = mClassLoaderContext; - if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) { + if (isUnknownOrUnsupportedContext(mClassLoaderContext)) { // Can happen if we read a previous version. mClassLoaderContext = dexUseInfo.mClassLoaderContext; - } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) { + } else if (!isUnknownOrUnsupportedContext(dexUseInfo.mClassLoaderContext) + && !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) { // We detected a context change. mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT; } @@ -857,6 +862,13 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { || !Objects.equals(oldClassLoaderContext, mClassLoaderContext); } + private static boolean isUnknownOrUnsupportedContext(String context) { + // TODO: Merge UNKNOWN_CLASS_LOADER_CONTEXT & UNSUPPORTED_CLASS_LOADER_CONTEXT cases + // into UNSUPPORTED_CLASS_LOADER_CONTEXT. + return UNKNOWN_CLASS_LOADER_CONTEXT.equals(context) + || UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(context); + } + public boolean isUsedByOtherApps() { return mIsUsedByOtherApps; } @@ -878,7 +890,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { public boolean isUnknownClassLoaderContext() { // The class loader context may be unknown if we loaded the data from a previous version // which didn't save the context. - return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext); + return isUnknownOrUnsupportedContext(mClassLoaderContext); } public boolean isVariableClassLoaderContext() { diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java index b7443f36e494..5506a523cd60 100644 --- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java +++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java @@ -16,12 +16,16 @@ package com.android.server.pm.dex; -import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.os.Binder; +import android.os.UserHandle; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.server.pm.Installer; +import com.android.server.pm.parsing.pkg.AndroidPackage; + +import java.io.File; public class ViewCompiler { private final Object mInstallLock; @@ -37,7 +41,9 @@ public class ViewCompiler { try { final String packageName = pkg.getPackageName(); final String apkPath = pkg.getBaseCodePath(); - final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex"; + // TODO(b/143971007): Use a cross-user directory + File dataDir = PackageInfoWithoutStateUtils.getDataDir(pkg, UserHandle.myUserId()); + final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex"; Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath + ") to " + outDexFile); long callingId = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java new file mode 100644 index 000000000000..e5e1b0b20955 --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing; + +import android.annotation.NonNull; +import android.content.pm.PackageParserCacheHelper; +import android.os.Parcel; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.system.StructStat; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + +import libcore.io.IoUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; + +public class PackageCacher { + + private static final String TAG = "PackageCacher"; + + /** + * Total number of packages that were read from the cache. We use it only for logging. + */ + public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger(); + + @NonNull + private File mCacheDir; + + public PackageCacher(@NonNull File cacheDir) { + this.mCacheDir = cacheDir; + } + + /** + * Returns the cache key for a specified {@code packageFile} and {@code flags}. + */ + private String getCacheKey(File packageFile, int flags) { + StringBuilder sb = new StringBuilder(packageFile.getName()); + sb.append('-'); + sb.append(flags); + + return sb.toString(); + } + + @VisibleForTesting + protected ParsedPackage fromCacheEntry(byte[] bytes) { + return fromCacheEntryStatic(bytes); + } + + /** static version of {@link #fromCacheEntry} for unit tests. */ + @VisibleForTesting + public static ParsedPackage fromCacheEntryStatic(byte[] bytes) { + final Parcel p = Parcel.obtain(); + p.unmarshall(bytes, 0, bytes.length); + p.setDataPosition(0); + + final PackageParserCacheHelper.ReadHelper helper = new PackageParserCacheHelper.ReadHelper(p); + helper.startAndInstall(); + + // TODO(b/135203078): Hide PackageImpl constructor? + ParsedPackage pkg = new PackageImpl(p); + + p.recycle(); + + sCachedPackageReadCount.incrementAndGet(); + + return pkg; + } + + @VisibleForTesting + protected byte[] toCacheEntry(ParsedPackage pkg) { + return toCacheEntryStatic(pkg); + + } + + /** static version of {@link #toCacheEntry} for unit tests. */ + @VisibleForTesting + public static byte[] toCacheEntryStatic(ParsedPackage pkg) { + final Parcel p = Parcel.obtain(); + final PackageParserCacheHelper.WriteHelper helper = new PackageParserCacheHelper.WriteHelper(p); + + pkg.writeToParcel(p, 0 /* flags */); + + helper.finishAndUninstall(); + + byte[] serialized = p.marshall(); + p.recycle(); + + return serialized; + } + + /** + * Given a {@code packageFile} and a {@code cacheFile} returns whether the + * cache file is up to date based on the mod-time of both files. + */ + private static boolean isCacheUpToDate(File packageFile, File cacheFile) { + try { + // NOTE: We don't use the File.lastModified API because it has the very + // non-ideal failure mode of returning 0 with no excepions thrown. + // The nio2 Files API is a little better but is considerably more expensive. + final StructStat pkg = Os.stat(packageFile.getAbsolutePath()); + final StructStat cache = Os.stat(cacheFile.getAbsolutePath()); + return pkg.st_mtime < cache.st_mtime; + } catch (ErrnoException ee) { + // The most common reason why stat fails is that a given cache file doesn't + // exist. We ignore that here. It's easy to reason that it's safe to say the + // cache isn't up to date if we see any sort of exception here. + // + // (1) Exception while stating the package file : This should never happen, + // and if it does, we do a full package parse (which is likely to throw the + // same exception). + // (2) Exception while stating the cache file : If the file doesn't exist, the + // cache is obviously out of date. If the file *does* exist, we can't read it. + // We will attempt to delete and recreate it after parsing the package. + if (ee.errno != OsConstants.ENOENT) { + Slog.w("Error while stating package cache : ", ee); + } + + return false; + } + } + + /** + * Returns the cached parse result for {@code packageFile} for parse flags {@code flags}, + * or {@code null} if no cached result exists. + */ + public ParsedPackage getCachedResult(File packageFile, int flags) { + final String cacheKey = getCacheKey(packageFile, flags); + final File cacheFile = new File(mCacheDir, cacheKey); + + try { + // If the cache is not up to date, return null. + if (!isCacheUpToDate(packageFile, cacheFile)) { + return null; + } + + final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath()); + return fromCacheEntry(bytes); + } catch (Throwable e) { + Slog.w(TAG, "Error reading package cache: ", e); + + // If something went wrong while reading the cache entry, delete the cache file + // so that we regenerate it the next time. + cacheFile.delete(); + return null; + } + } + + /** + * Caches the parse result for {@code packageFile} with flags {@code flags}. + */ + public void cacheResult(File packageFile, int flags, ParsedPackage parsed) { + try { + final String cacheKey = getCacheKey(packageFile, flags); + final File cacheFile = new File(mCacheDir, cacheKey); + + if (cacheFile.exists()) { + if (!cacheFile.delete()) { + Slog.e(TAG, "Unable to delete cache file: " + cacheFile); + } + } + + final byte[] cacheEntry = toCacheEntry(parsed); + + if (cacheEntry == null) { + return; + } + + try (FileOutputStream fos = new FileOutputStream(cacheFile)) { + fos.write(cacheEntry); + } catch (IOException ioe) { + Slog.w(TAG, "Error writing cache entry.", ioe); + cacheFile.delete(); + } + } catch (Throwable e) { + Slog.w(TAG, "Error saving package cache.", e); + } + } +} diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java new file mode 100644 index 000000000000..23bdf5f101f3 --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing; + +import android.annotation.CheckResult; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.apex.ApexInfo; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageUserState; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; +import android.content.pm.ProcessInfo; +import android.content.pm.ProviderInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.PackageInfoWithoutStateUtils; +import android.content.pm.parsing.component.ComponentParseUtils; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedComponent; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedMainComponent; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.content.pm.parsing.component.ParsedProcess; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Pair; + +import com.android.internal.util.ArrayUtils; +import com.android.server.pm.PackageSetting; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.pkg.PackageStateUnserialized; + +import libcore.util.EmptyArray; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * Methods that use a {@link PackageSetting} use it to override information provided from the raw + * package, or to provide information that would otherwise be missing. Null can be passed if none + * of the state values should be applied. + * + * @hide + **/ +public class PackageInfoUtils { + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + public static PackageInfo generate(AndroidPackage pkg, int[] gids, + @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, + Set<String> grantedPermissions, PackageUserState state, int userId, + @Nullable PackageSetting pkgSetting) { + return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime, + grantedPermissions, state, userId, null, pkgSetting); + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags, + @Nullable PackageSetting pkgSetting) { + return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(), + new PackageUserState(), UserHandle.getCallingUserId(), apexInfo, pkgSetting); + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + private static PackageInfo generateWithComponents(AndroidPackage pkg, int[] gids, + @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, + Set<String> grantedPermissions, PackageUserState state, int userId, + @Nullable ApexInfo apexInfo, @Nullable PackageSetting pkgSetting) { + ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId, + pkgSetting); + if (applicationInfo == null) { + return null; + } + + PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponents(pkg, gids, flags, + firstInstallTime, lastUpdateTime, grantedPermissions, state, userId, apexInfo, + applicationInfo); + if (info == null) { + return null; + } + + info.isStub = pkg.isStub(); + info.coreApp = pkg.isCoreApp(); + + if ((flags & PackageManager.GET_ACTIVITIES) != 0) { + final int N = pkg.getActivities().size(); + if (N > 0) { + int num = 0; + final ActivityInfo[] res = new ActivityInfo[N]; + for (int i = 0; i < N; i++) { + final ParsedActivity a = pkg.getActivities().get(i); + if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), a, + flags)) { + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals( + a.getName())) { + continue; + } + res[num++] = generateActivityInfo(pkg, a, flags, state, + applicationInfo, userId, pkgSetting); + } + } + info.activities = ArrayUtils.trimToSize(res, num); + } + } + if ((flags & PackageManager.GET_RECEIVERS) != 0) { + final int size = pkg.getReceivers().size(); + if (size > 0) { + int num = 0; + final ActivityInfo[] res = new ActivityInfo[size]; + for (int i = 0; i < size; i++) { + final ParsedActivity a = pkg.getReceivers().get(i); + if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), a, + flags)) { + res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo, + userId, pkgSetting); + } + } + info.receivers = ArrayUtils.trimToSize(res, num); + } + } + if ((flags & PackageManager.GET_SERVICES) != 0) { + final int size = pkg.getServices().size(); + if (size > 0) { + int num = 0; + final ServiceInfo[] res = new ServiceInfo[size]; + for (int i = 0; i < size; i++) { + final ParsedService s = pkg.getServices().get(i); + if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), s, + flags)) { + res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo, + userId, pkgSetting); + } + } + info.services = ArrayUtils.trimToSize(res, num); + } + } + if ((flags & PackageManager.GET_PROVIDERS) != 0) { + final int size = pkg.getProviders().size(); + if (size > 0) { + int num = 0; + final ProviderInfo[] res = new ProviderInfo[size]; + for (int i = 0; i < size; i++) { + final ParsedProvider pr = pkg.getProviders() + .get(i); + if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), pr, + flags)) { + res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo, + userId, pkgSetting); + } + } + info.providers = ArrayUtils.trimToSize(res, num); + } + } + if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) { + int N = pkg.getInstrumentations().size(); + if (N > 0) { + info.instrumentation = new InstrumentationInfo[N]; + for (int i = 0; i < N; i++) { + info.instrumentation[i] = generateInstrumentationInfo( + pkg.getInstrumentations().get(i), pkg, flags, userId, pkgSetting); + } + } + } + + return info; + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg, + @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId, + @Nullable PackageSetting pkgSetting) { + // TODO(b/135203078): Consider cases where we don't have a PkgSetting + if (pkg == null) { + return null; + } + + if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags) + || !AndroidPackageUtils.isMatchForSystemOnly(pkg, flags)) { + return null; + } + + ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfo(pkg, flags, + state, userId); + if (info == null) { + return null; + } + + if (pkgSetting != null) { + // TODO(b/135203078): Remove PackageParser1/toAppInfoWithoutState and clean all this up + PackageStateUnserialized pkgState = pkgSetting.getPkgState(); + info.hiddenUntilInstalled = pkgState.isHiddenUntilInstalled(); + List<String> usesLibraryFiles = pkgState.getUsesLibraryFiles(); + List<SharedLibraryInfo> usesLibraryInfos = pkgState.getUsesLibraryInfos(); + info.sharedLibraryFiles = usesLibraryFiles.isEmpty() + ? null : usesLibraryFiles.toArray(new String[0]); + info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos; + } + + info.flags |= appInfoFlags(pkg, pkgSetting); + info.privateFlags |= appInfoPrivateFlags(pkg, pkgSetting); + return info; + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId, + @Nullable PackageSetting pkgSetting) { + return generateActivityInfo(pkg, a, flags, state, null, userId, pkgSetting); + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, + @Nullable ApplicationInfo applicationInfo, int userId, + @Nullable PackageSetting pkgSetting) { + if (a == null) return null; + if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting); + } + ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfo(pkg, a, flags, state, + applicationInfo, userId); + if (info == null) { + return null; + } + + assignSharedFieldsForComponentInfo(info, a, pkgSetting); + return info; + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + public static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId, + @Nullable PackageSetting pkgSetting) { + return generateServiceInfo(pkg, s, flags, state, null, userId, pkgSetting); + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + private static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, + @Nullable ApplicationInfo applicationInfo, int userId, + @Nullable PackageSetting pkgSetting) { + if (s == null) return null; + if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting); + } + ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfo(pkg, s, flags, state, + applicationInfo, userId); + if (info == null) { + return null; + } + + assignSharedFieldsForComponentInfo(info, s, pkgSetting); + return info; + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId, + @Nullable PackageSetting pkgSetting) { + return generateProviderInfo(pkg, p, flags, state, null, userId, pkgSetting); + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + private static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, + @Nullable ApplicationInfo applicationInfo, int userId, + @Nullable PackageSetting pkgSetting) { + if (p == null) return null; + if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting); + } + ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfo(pkg, p, flags, state, + applicationInfo, userId); + if (info == null) { + return null; + } + + assignSharedFieldsForComponentInfo(info, p, pkgSetting); + return info; + } + + /** + * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. + */ + @Nullable + public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i, + AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags, int userId, + @Nullable PackageSetting pkgSetting) { + if (i == null) return null; + + InstrumentationInfo info = + PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId); + if (info == null) { + return null; + } + + // TODO(b/135203078): Add setting related state + info.primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting); + info.secondaryCpuAbi = AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting); + info.nativeLibraryDir = pkg.getNativeLibraryDir(); + info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir(); + + assignStateFieldsForPackageItemInfo(info, i, pkgSetting); + + return info; + } + + // TODO(b/135203078): Determine if permission methods need to pass in a non-null PackageSetting + // os that checkUseInstalledOrHidden filter can apply + @Nullable + public static PermissionInfo generatePermissionInfo(ParsedPermission p, + @PackageManager.ComponentInfoFlags int flags) { + // TODO(b/135203078): Remove null checks and make all usages @NonNull + if (p == null) return null; + + // For now, permissions don't have state-adjustable fields; return directly + return PackageInfoWithoutStateUtils.generatePermissionInfo(p, flags); + } + + @Nullable + public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg, + @PackageManager.ComponentInfoFlags int flags) { + if (pg == null) return null; + + // For now, permissions don't have state-adjustable fields; return directly + return PackageInfoWithoutStateUtils.generatePermissionGroupInfo(pg, flags); + } + + @Nullable + public static ArrayMap<String, ProcessInfo> generateProcessInfo( + Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlags int flags) { + if (procs == null) { + return null; + } + + final int numProcs = procs.size(); + ArrayMap<String, ProcessInfo> retProcs = new ArrayMap<>(numProcs); + for (String key : procs.keySet()) { + ParsedProcess proc = procs.get(key); + retProcs.put(proc.getName(), new ProcessInfo(proc.getName(), + new ArraySet<>(proc.getDeniedPermissions()))); + } + return retProcs; + } + + /** + * Returns true if the package is installed and not hidden, or if the caller + * explicitly wanted all uninstalled and hidden packages as well. + */ + private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, + PackageSetting pkgSetting, PackageUserState state, + @PackageManager.PackageInfoFlags int flags) { + // Returns false if the package is hidden system app until installed. + if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0 + && !state.installed + && pkgSetting != null + && pkgSetting.getPkgState().isHiddenUntilInstalled()) { + return false; + } + + // If available for the target user, or trying to match uninstalled packages and it's + // a system app. + return state.isAvailable(flags) + || (pkg.isSystem() + && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0 + || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0)); + } + + private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo, + @NonNull ParsedMainComponent mainComponent, @Nullable PackageSetting pkgSetting) { + assignStateFieldsForPackageItemInfo(componentInfo, mainComponent, pkgSetting); + componentInfo.descriptionRes = mainComponent.getDescriptionRes(); + componentInfo.directBootAware = mainComponent.isDirectBootAware(); + componentInfo.enabled = mainComponent.isEnabled(); + componentInfo.splitName = mainComponent.getSplitName(); + } + + private static void assignStateFieldsForPackageItemInfo( + @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component, + @Nullable PackageSetting pkgSetting) { + // TODO(b/135203078): Add setting related state + } + + @CheckResult + private static int flag(boolean hasFlag, int flag) { + return hasFlag ? flag : 0; + } + + /** @see ApplicationInfo#flags */ + public static int appInfoFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) { + // TODO(b/135203078): Add setting related state + // @formatter:off + int flags = PackageInfoWithoutStateUtils.appInfoFlags(pkg) + | flag(pkg.isSystem(), ApplicationInfo.FLAG_SYSTEM) + | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST); + if (pkgSetting != null) { + flags |= flag(pkgSetting.getPkgState().isUpdatedSystemApp(), ApplicationInfo.FLAG_UPDATED_SYSTEM_APP); + } + return flags; + // @formatter:on + } + + /** @see ApplicationInfo#privateFlags */ + public static int appInfoPrivateFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) { + // TODO(b/135203078): Add setting related state + // @formatter:off + return PackageInfoWithoutStateUtils.appInfoPrivateFlags(pkg) + | flag(pkg.isSystemExt(), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) + | flag(pkg.isPrivileged(), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) + | flag(pkg.isOem(), ApplicationInfo.PRIVATE_FLAG_OEM) + | flag(pkg.isVendor(), ApplicationInfo.PRIVATE_FLAG_VENDOR) + | flag(pkg.isProduct(), ApplicationInfo.PRIVATE_FLAG_PRODUCT) + | flag(pkg.isOdm(), ApplicationInfo.PRIVATE_FLAG_ODM) + | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY); + // @formatter:on + } +} diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java new file mode 100644 index 000000000000..f99791a28f46 --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing; + +import android.annotation.AnyThread; +import android.annotation.Nullable; +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.pm.parsing.result.ParseTypeImpl; +import android.content.res.TypedArray; +import android.os.Build; +import android.os.SystemClock; +import android.util.DisplayMetrics; +import android.util.Slog; + +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + +import java.io.File; + +/** + * The v2 of {@link PackageParser} for use when parsing is initiated in the server and must + * contain state contained by the server. + */ +public class PackageParser2 { + + private static final String TAG = "PackageParser2"; + + private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE; + private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100; + + private ThreadLocal<ParseTypeImpl> mSharedResult = ThreadLocal.withInitial(ParseTypeImpl::new); + + private final String[] mSeparateProcesses; + private final boolean mOnlyCoreApps; + private final DisplayMetrics mDisplayMetrics; + + @Nullable + protected PackageCacher mCacher; + + private ParsingPackageUtils parsingUtils; + + /** + * @param onlyCoreApps Flag indicating this parser should only consider apps with + * {@code coreApp} manifest attribute to be valid apps. This is useful when + * creating a minimalist boot environment. + */ + public PackageParser2(String[] separateProcesses, boolean onlyCoreApps, + DisplayMetrics displayMetrics, @Nullable File cacheDir, Callback callback) { + mSeparateProcesses = separateProcesses; + mOnlyCoreApps = onlyCoreApps; + + if (displayMetrics == null) { + mDisplayMetrics = new DisplayMetrics(); + mDisplayMetrics.setToDefaults(); + } else { + mDisplayMetrics = displayMetrics; + } + + mCacher = cacheDir == null ? null : new PackageCacher(cacheDir); + // TODO(b/135203078): Remove nullability of callback + callback = callback != null ? callback : new Callback() { + @Override + public boolean hasFeature(String feature) { + return false; + } + }; + + parsingUtils = new ParsingPackageUtils(onlyCoreApps, separateProcesses, displayMetrics, callback); + } + + /** + * TODO(b/135203078): Document new package parsing + */ + @AnyThread + public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches) + throws PackageParserException { + if (useCaches && mCacher != null) { + ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags); + if (parsed != null) { + return parsed; + } + } + + long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; + ParseInput input = mSharedResult.get().reset(); + ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags); + if (result.isError()) { + throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(), + result.getException()); + } + + ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed(); + + long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; + if (mCacher != null) { + mCacher.cacheResult(packageFile, flags, parsed); + } + if (LOG_PARSE_TIMINGS) { + parseTime = cacheTime - parseTime; + cacheTime = SystemClock.uptimeMillis() - cacheTime; + if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) { + Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime + + "ms, update_cache=" + cacheTime + " ms"); + } + } + + return parsed; + } + + public static abstract class Callback implements ParsingPackageUtils.Callback { + + @Override + public final ParsingPackage startParsingPackage(String packageName, String baseCodePath, + String codePath, TypedArray manifestArray, boolean isCoreApp) { + return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray, + isCoreApp); + } + } +} diff --git a/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java index 81b4bc574197..ebb96bbbf0e4 100644 --- a/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java +++ b/services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,31 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER; -import android.content.pm.parsing.ParsedPackage; import android.os.Build; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.pm.parsing.pkg.ParsedPackage; /** * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java * and android.hidl.manager-V1.0-java libraries are included by default. * + * TODO(b/135203078): See if this class can be removed, thus removing the isUpdatedSystemApp param + * * @hide */ @VisibleForTesting public class AndroidHidlUpdater extends PackageSharedLibraryUpdater { @Override - public void updatePackage(ParsedPackage parsedPackage) { + public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) { // This was the default <= P and is maintained for backwards compatibility. boolean isLegacy = parsedPackage.getTargetSdkVersion() <= Build.VERSION_CODES.P; // Only system apps use these libraries - boolean isSystem = parsedPackage.isSystemApp() || parsedPackage.isUpdatedSystemApp(); + boolean isSystem = parsedPackage.isSystem() || isUpdatedSystemApp; if (isLegacy && isSystem) { prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_BASE); diff --git a/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java index 5fbe5b9c7250..432394a651a8 100644 --- a/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java +++ b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,16 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.Context; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ParsedPackage; import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; @@ -30,6 +28,8 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.compat.IPlatformCompat; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.ParsedPackage; /** * Updates a package to ensure that if it targets <= Q that the android.test.base library is @@ -73,7 +73,7 @@ public class AndroidTestBaseUpdater extends PackageSharedLibraryUpdater { } @Override - public void updatePackage(ParsedPackage pkg) { + public void updatePackage(ParsedPackage pkg, boolean isUpdatedSystemApp) { // Packages targeted at <= Q expect the classes in the android.test.base library // to be accessible so this maintains backward compatibility by adding the // android.test.base library to those packages. diff --git a/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java index 613a06b636e9..7de457e9374b 100644 --- a/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java +++ b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ParsedPackage; import android.os.Build; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.ParsedPackage; /** * Updates a package to ensure that if it targets < P that the org.apache.http.legacy library is @@ -37,7 +37,7 @@ public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater { } @Override - public void updatePackage(ParsedPackage parsedPackage) { + public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) { // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library // to be accessible so this maintains backward compatibility by adding the // org.apache.http.legacy library to those packages. diff --git a/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java index 1220fc497b04..1d018c485e08 100644 --- a/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java +++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,21 +14,21 @@ * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; -import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.parsing.ParsedPackage; +import android.content.pm.PackageParser; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.pm.parsing.pkg.ParsedPackage; import java.util.ArrayList; import java.util.List; -import java.util.function.Supplier; /** * Modifies {@link ParsedPackage} in order to maintain backwards compatibility. @@ -55,13 +55,7 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { // android.test.mock. packageUpdaters.add(new AndroidTestRunnerSplitUpdater()); - // Attempt to load and add the optional updater that will only be available when - // REMOVE_ATB_FROM_BCP=true. If that could not be found then add the default updater that - // will remove any references to org.apache.http.library from the package so that it does - // not try and load the library when it is on the bootclasspath. - boolean bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters, - "android.content.pm.parsing.library.AndroidTestBaseUpdater", - RemoveUnnecessaryAndroidTestBaseLibrary::new); + boolean bootClassPathContainsATB = !addUpdaterForAndroidTestBase(packageUpdaters); PackageSharedLibraryUpdater[] updaterArray = packageUpdaters .toArray(new PackageSharedLibraryUpdater[0]); @@ -70,41 +64,31 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { } /** - * Add an optional {@link PackageSharedLibraryUpdater} instance to the list, if it could not be - * found then add a default instance instead. + * Attempt to load and add the optional updater that will only be available when + * REMOVE_ATB_FROM_BCP=true. If that could not be found then add the default updater that + * will remove any references to org.apache.http.library from the package so that + * it does not try and load the library when it is on the bootclasspath. * - * @param packageUpdaters the list to update. - * @param className the name of the optional class. - * @param defaultUpdater the supplier of the default instance. - * @return true if the optional updater was added false otherwise. + * TODO:(b/135203078): Find a better way to do this. */ - private static boolean addOptionalUpdater(List<PackageSharedLibraryUpdater> packageUpdaters, - String className, Supplier<PackageSharedLibraryUpdater> defaultUpdater) { - Class<? extends PackageSharedLibraryUpdater> clazz; + private static boolean addUpdaterForAndroidTestBase( + List<PackageSharedLibraryUpdater> packageUpdaters) { + boolean hasClass = false; + String className = "android.content.pm.AndroidTestBaseUpdater"; try { - clazz = (PackageBackwardCompatibility.class.getClassLoader() - .loadClass(className) - .asSubclass(PackageSharedLibraryUpdater.class)); + Class clazz = (PackageParser.class.getClassLoader().loadClass(className)); + hasClass = clazz != null; Log.i(TAG, "Loaded " + className); } catch (ClassNotFoundException e) { Log.i(TAG, "Could not find " + className + ", ignoring"); - clazz = null; } - boolean usedOptional = false; - PackageSharedLibraryUpdater updater; - if (clazz == null) { - updater = defaultUpdater.get(); + if (hasClass) { + packageUpdaters.add(new AndroidTestBaseUpdater()); } else { - try { - updater = clazz.getConstructor().newInstance(); - usedOptional = true; - } catch (ReflectiveOperationException e) { - throw new IllegalStateException("Could not create instance of " + className, e); - } + packageUpdaters.add(new RemoveUnnecessaryAndroidTestBaseLibrary()); } - packageUpdaters.add(updater); - return usedOptional; + return hasClass; } @VisibleForTesting @@ -129,14 +113,15 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { * @param parsedPackage the {@link ParsedPackage} to modify. */ @VisibleForTesting - public static void modifySharedLibraries(ParsedPackage parsedPackage) { - INSTANCE.updatePackage(parsedPackage); + public static void modifySharedLibraries(ParsedPackage parsedPackage, + boolean isUpdatedSystemApp) { + INSTANCE.updatePackage(parsedPackage, isUpdatedSystemApp); } @Override - public void updatePackage(ParsedPackage parsedPackage) { + public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) { for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) { - packageUpdater.updatePackage(parsedPackage); + packageUpdater.updatePackage(parsedPackage, isUpdatedSystemApp); } } @@ -161,7 +146,7 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater { @Override - public void updatePackage(ParsedPackage parsedPackage) { + public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) { // android.test.runner has a dependency on android.test.mock so if android.test.runner // is present but android.test.mock is not then add android.test.mock. prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK); @@ -177,7 +162,7 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { extends PackageSharedLibraryUpdater { @Override - public void updatePackage(ParsedPackage parsedPackage) { + public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) { removeLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY); } @@ -192,7 +177,7 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { extends PackageSharedLibraryUpdater { @Override - public void updatePackage(ParsedPackage parsedPackage) { + public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) { removeLibrary(parsedPackage, ANDROID_TEST_BASE); } } diff --git a/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java b/services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java index 8b27d140a8f4..123b80820708 100644 --- a/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java +++ b/services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.pm.parsing.ParsedPackage; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import com.android.server.pm.parsing.pkg.ParsedPackage; import java.util.ArrayList; import java.util.List; @@ -38,7 +38,7 @@ public abstract class PackageSharedLibraryUpdater { * * @param parsedPackage the package to update. */ - public abstract void updatePackage(ParsedPackage parsedPackage); + public abstract void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp); static void removeLibrary(ParsedPackage parsedPackage, String libraryName) { parsedPackage.removeUsesLibrary(libraryName) diff --git a/core/java/android/content/pm/parsing/library/SharedLibraryNames.java b/services/core/java/com/android/server/pm/parsing/library/SharedLibraryNames.java index 7b691c06718e..f62f01452725 100644 --- a/core/java/android/content/pm/parsing/library/SharedLibraryNames.java +++ b/services/core/java/com/android/server/pm/parsing/library/SharedLibraryNames.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; /** * A set of shared library names diff --git a/core/java/android/content/pm/parsing/AndroidPackage.aidl b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.aidl index ab3cf7cb8c65..ab3cf7cb8c65 100644 --- a/core/java/android/content/pm/parsing/AndroidPackage.aidl +++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.aidl diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java new file mode 100644 index 000000000000..792957935870 --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing.pkg; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageParser; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.ParsingPackageRead; +import android.content.pm.parsing.component.ParsedFeature; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.ArraySet; +import android.util.Pair; + +import com.android.internal.R; + +import java.security.PublicKey; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** + * The last state of a package during parsing/install before it is available in + * {@link com.android.server.pm.PackageManagerService#mPackages}. + * + * It is the responsibility of the caller to understand what data is available at what step of the + * parsing or install process. + * + * TODO(b/135203078): Nullability annotations + * TODO(b/135203078): Remove get/setAppInfo differences + * + * @hide + */ +public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPackageRead, Parcelable { + + /** + * The names of packages to adopt ownership of permissions from, parsed under + * {@link PackageParser#TAG_ADOPT_PERMISSIONS}. + * @see R.styleable#AndroidManifestOriginalPackage_name + */ + @NonNull + List<String> getAdoptPermissions(); + + /** Path of base APK */ + @NonNull + String getBaseCodePath(); + + /** Revision code of base APK */ + int getBaseRevisionCode(); + + /** + * Path where this package was found on disk. For monolithic packages + * this is path to single base APK file; for cluster packages this is + * path to the cluster directory. + */ + @NonNull + String getCodePath(); + + /** + * Permissions requested but not in the manifest. These may have been split or migrated from + * previous versions/definitions. + */ + @NonNull + List<String> getImplicitPermissions(); + + /** + * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in + * {@link PackageParser#TAG_KEY_SETS}. + * @see R.styleable#AndroidManifestKeySet + * @see R.styleable#AndroidManifestPublicKey + */ + @NonNull + Map<String, ArraySet<PublicKey>> getKeySetMapping(); + + /** + * Library names this package is declared as, for use by other packages with "uses-library". + * @see R.styleable#AndroidManifestLibrary + */ + @NonNull + List<String> getLibraryNames(); + + /** + * The package name as declared in the manifest, since the package can be renamed. For example, + * static shared libs use synthetic package names. + */ + @NonNull + String getManifestPackageName(); + + /** + * We store the application meta-data independently to avoid multiple unwanted references + * TODO(b/135203078): What does this comment mean? + * TODO(b/135203078): Make all the Bundles immutable (and non-null by shared empty reference?) + */ + @Nullable + Bundle getMetaData(); + + /** + * For system use to migrate from an old package name to a new one, moving over data + * if available. + * @see R.styleable#AndroidManifestOriginalPackage} + */ + @NonNull + List<String> getOriginalPackages(); + + /** + * Map of overlayable name to actor name. + */ + @NonNull + Map<String, String> getOverlayables(); + + /** + * The name of the package as used to identify it in the system. This may be adjusted by the + * system from the value declared in the manifest, and may not correspond to a Java code + * package. + * @see ApplicationInfo#packageName + * @see PackageInfo#packageName + */ + @NonNull + String getPackageName(); + + /** + * @see PermissionGroupInfo + */ + @NonNull + List<ParsedPermissionGroup> getPermissionGroups(); + + @NonNull + List<ParsedFeature> getFeatures(); + + /** + * Used to determine the default preferred handler of an {@link Intent}. + * + * Map of component className to intent info inside that component. + * TODO(b/135203078): Is this actually used/working? + */ + @NonNull + List<Pair<String, ParsedIntentInfo>> getPreferredActivityFilters(); + + /** + * System protected broadcasts. + * @see R.styleable#AndroidManifestProtectedBroadcast + */ + @NonNull + List<String> getProtectedBroadcasts(); + + /** + * Intents that this package may query or require and thus requires visibility into. + * @see R.styleable#AndroidManifestQueriesIntent + */ + @NonNull + List<Intent> getQueriesIntents(); + + /** + * Other packages that this package may query or require and thus requires visibility into. + * @see R.styleable#AndroidManifestQueriesPackage + */ + @NonNull + List<String> getQueriesPackages(); + + /** + * If a system app declares {@link #getOriginalPackages()}, and the app was previously installed + * under one of those original package names, the {@link #getPackageName()} system identifier + * will be changed to that previously installed name. This will then be non-null, set to the + * manifest package name, for tracking the package under its true name. + * + * TODO(b/135203078): Remove this in favor of checking originalPackages.isEmpty and + * getManifestPackageName + */ + @Nullable + String getRealPackage(); + + /** + * SHA-512 hash of the only APK that can be used to update a system package. + * @see R.styleable#AndroidManifestRestrictUpdate + */ + @Nullable + byte[] getRestrictUpdateHash(); + + /** + * The signature data of all APKs in this package, which must be exactly the same across the + * base and splits. + */ + PackageParser.SigningDetails getSigningDetails(); + + /** + * TODO(b/135203078): Move split stuff to an inner data class + * @see ApplicationInfo#splitNames + * @see PackageInfo#splitNames + */ + @Nullable + String[] getSplitNames(); + + /** Flags of any split APKs; ordered by parsed splitName */ + @Nullable + int[] getSplitFlags(); + + /** @see R.styleable#AndroidManifestStaticLibrary_name */ + @Nullable + String getStaticSharedLibName(); + + /** @see R.styleable#AndroidManifestStaticLibrary_version */ + long getStaticSharedLibVersion(); + + /** + * {@link android.os.storage.StorageManager#convert(String)} version of + * {@link #getVolumeUuid()}. + * TODO(b/135203078): All usages call toString() on this. Can the string be returned directly, + * or does the parsing logic in StorageManager have to run? + */ + UUID getStorageUuid(); + + /** + * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in + * {@link PackageParser#TAG_KEY_SETS}. + * @see R.styleable#AndroidManifestUpgradeKeySet + */ + @NonNull + Set<String> getUpgradeKeySets(); + + /** @see R.styleable#AndroidManifestUsesLibrary */ + @NonNull + List<String> getUsesLibraries(); + + /** + * Like {@link #getUsesLibraries()}, but marked optional by setting + * {@link R.styleable#AndroidManifestUsesLibrary_required} to false . Application is expected + * to handle absence manually. + * @see R.styleable#AndroidManifestUsesLibrary + */ + @NonNull + List<String> getUsesOptionalLibraries(); + + /** + * TODO(b/135203078): Move static library stuff to an inner data class + * @see R.styleable#AndroidManifestUsesStaticLibrary + */ + @NonNull + List<String> getUsesStaticLibraries(); + + /** @see R.styleable#AndroidManifestUsesStaticLibrary_certDigest */ + @Nullable + String[][] getUsesStaticLibrariesCertDigests(); + + /** @see R.styleable#AndroidManifestUsesStaticLibrary_version */ + @Nullable + long[] getUsesStaticLibrariesVersions(); + + /** @see R.styleable#AndroidManifestApplication_forceQueryable */ + boolean isForceQueryable(); + + boolean isCrossProfile(); + + /** + * The install time abi override to choose 32bit abi's when multiple abi's + * are present. This is only meaningfull for multiarch applications. + */ + boolean isUse32BitAbi(); + + /** + * Set if the any of components are visible to instant applications. + * @see R.styleable#AndroidManifestActivity_visibleToInstantApps + * @see R.styleable#AndroidManifestProvider_visibleToInstantApps + * @see R.styleable#AndroidManifestService_visibleToInstantApps + */ + boolean isVisibleToInstantApps(); + + /** + * Generates an {@link ApplicationInfo} object with only the data available in this object. + * + * TODO(b/135203078): Actually add this + * This does not contain any system or user state data, and should be avoided. Prefer + * com.android.server.pm.parsing.PackageInfoUtils#generateApplicationInfo( + * AndroidPackage, int, PackageUserState, int, com.android.server.pm.PackageSetting) + * + * @deprecated Access AndroidPackage fields directly. + */ + @Deprecated + @NonNull + ApplicationInfo toAppInfoWithoutState(); + + /** + * TODO(b/135203078): Remove usages? + * @return a mock of what the previous package.applicationInfo would've returned for logging + * @deprecated don't use this in any new code, just print package name directly + */ + @Deprecated + @NonNull + String toAppInfoToString(); +} diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java new file mode 100644 index 000000000000..780b2347287a --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing.pkg; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.SharedLibraryInfo; +import android.content.pm.VersionedPackage; +import android.content.pm.dex.DexMetadataHelper; +import android.content.pm.parsing.ParsingPackageRead; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; +import android.text.TextUtils; + +import com.android.internal.content.NativeLibraryHelper; +import com.android.internal.util.ArrayUtils; +import com.android.server.SystemConfig; +import com.android.server.pm.PackageSetting; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** @hide */ +public class AndroidPackageUtils { + + private AndroidPackageUtils() { + } + + public static List<String> getAllCodePathsExcludingResourceOnly( + AndroidPackage aPkg) { + PackageImpl pkg = (PackageImpl) aPkg; + ArrayList<String> paths = new ArrayList<>(); + if (pkg.isHasCode()) { + paths.add(pkg.getBaseCodePath()); + } + String[] splitCodePaths = pkg.getSplitCodePaths(); + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + if ((pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { + paths.add(splitCodePaths[i]); + } + } + } + return paths; + } + + /** + * @return a list of the base and split code paths. + */ + public static List<String> getAllCodePaths(AndroidPackage aPkg) { + PackageImpl pkg = (PackageImpl) aPkg; + ArrayList<String> paths = new ArrayList<>(); + paths.add(pkg.getBaseCodePath()); + + String[] splitCodePaths = pkg.getSplitCodePaths(); + if (!ArrayUtils.isEmpty(splitCodePaths)) { + Collections.addAll(paths, splitCodePaths); + } + return paths; + } + + public static SharedLibraryInfo createSharedLibraryForStatic(AndroidPackage pkg) { + return new SharedLibraryInfo(null, pkg.getPackageName(), + AndroidPackageUtils.getAllCodePaths(pkg), + pkg.getStaticSharedLibName(), + pkg.getStaticSharedLibVersion(), + SharedLibraryInfo.TYPE_STATIC, + new VersionedPackage(pkg.getManifestPackageName(), + pkg.getLongVersionCode()), + null, null); + } + + public static SharedLibraryInfo createSharedLibraryForDynamic(AndroidPackage pkg, String name) { + return new SharedLibraryInfo(null, pkg.getPackageName(), + AndroidPackageUtils.getAllCodePaths(pkg), name, + SharedLibraryInfo.VERSION_UNDEFINED, + SharedLibraryInfo.TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(), + pkg.getLongVersionCode()), + null, null); + } + + /** + * Return the dex metadata files for the given package as a map + * [code path -> dex metadata path]. + * + * NOTE: involves I/O checks. + */ + public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) { + return DexMetadataHelper.buildPackageApkToDexMetadataMap + (AndroidPackageUtils.getAllCodePaths(pkg)); + } + + /** + * Validate the dex metadata files installed for the given package. + * + * @throws PackageParserException in case of errors. + */ + public static void validatePackageDexMetadata(AndroidPackage pkg) + throws PackageParserException { + Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values(); + for (String dexMetadata : apkToDexMetadataList) { + DexMetadataHelper.validateDexMetadataFile(dexMetadata); + } + } + + public static NativeLibraryHelper.Handle createNativeLibraryHandle(AndroidPackage pkg) + throws IOException { + return NativeLibraryHelper.Handle.create( + AndroidPackageUtils.getAllCodePaths(pkg), + pkg.isMultiArch(), + pkg.isExtractNativeLibs(), + pkg.isDebuggable() + ); + } + + public static boolean canHaveOatDir(AndroidPackage pkg, boolean isUpdatedSystemApp) { + // The following app types CANNOT have oat directory + // - non-updated system apps + return !pkg.isSystem() || isUpdatedSystemApp; + } + + public static boolean hasComponentClassName(AndroidPackage pkg, String className) { + List<ParsedActivity> activities = pkg.getActivities(); + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + if (Objects.equals(className, activities.get(index).getName())) { + return true; + } + } + + List<ParsedActivity> receivers = pkg.getReceivers(); + int receiversSize = receivers.size(); + for (int index = 0; index < receiversSize; index++) { + if (Objects.equals(className, receivers.get(index).getName())) { + return true; + } + } + + List<ParsedProvider> providers = pkg.getProviders(); + int providersSize = providers.size(); + for (int index = 0; index < providersSize; index++) { + if (Objects.equals(className, providers.get(index).getName())) { + return true; + } + } + + List<ParsedService> services = pkg.getServices(); + int servicesSize = services.size(); + for (int index = 0; index < servicesSize; index++) { + if (Objects.equals(className, services.get(index).getName())) { + return true; + } + } + + List<ParsedInstrumentation> instrumentations = pkg.getInstrumentations(); + int instrumentationsSize = instrumentations.size(); + for (int index = 0; index < instrumentationsSize; index++) { + if (Objects.equals(className, instrumentations.get(index).getName())) { + return true; + } + } + + return false; + } + + public static boolean isEncryptionAware(AndroidPackage pkg) { + return pkg.isDirectBootAware() || pkg.isPartiallyDirectBootAware(); + } + + public static boolean isLibrary(AndroidPackage pkg) { + // TODO(b/135203078): Can parsing just enforce these always match? + return pkg.getStaticSharedLibName() != null || !pkg.getLibraryNames().isEmpty(); + } + + public static int getHiddenApiEnforcementPolicy(AndroidPackage pkg, + @NonNull PackageSetting pkgSetting) { + boolean isAllowedToUseHiddenApis; + if (pkg.isSignedWithPlatformKey()) { + isAllowedToUseHiddenApis = true; + } else if (pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) { + isAllowedToUseHiddenApis = pkg.isUsesNonSdkApi() + || SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains( + pkg.getPackageName()); + } else { + isAllowedToUseHiddenApis = false; + } + + if (isAllowedToUseHiddenApis) { + return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; + } + + // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done + // entirely through ApplicationInfo and shouldn't touch this specific class, but that + // may not always hold true. +// if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) { +// return mHiddenApiPolicy; +// } + return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED; + } + + public static int getIcon(ParsingPackageRead pkg) { + return (PackageParser.sUseRoundIcon && pkg.getRoundIconRes() != 0) + ? pkg.getRoundIconRes() : pkg.getIconRes(); + } + + public static long getLongVersionCode(AndroidPackage pkg) { + return PackageInfo.composeLongVersionCode(pkg.getVersionCodeMajor(), pkg.getVersionCode()); + } + + public static boolean isMatchForSystemOnly(AndroidPackage pkg, int flags) { + if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { + return pkg.isSystem(); + } + return true; + } + + public static String getPrimaryCpuAbi(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) { + if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.primaryCpuAbiString)) { + return pkg.getPrimaryCpuAbi(); + } + + return pkgSetting.primaryCpuAbiString; + } + + public static String getSecondaryCpuAbi(AndroidPackage pkg, + @Nullable PackageSetting pkgSetting) { + if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.secondaryCpuAbiString)) { + return pkg.getSecondaryCpuAbi(); + } + + return pkgSetting.secondaryCpuAbiString; + } + + /** + * Returns the primary ABI as parsed from the package. Used only during parsing and derivation. + * Otherwise prefer {@link #getPrimaryCpuAbi(AndroidPackage, PackageSetting)}. + * + * TODO(b/135203078): Actually hide the method + * Placed in the utility to hide the method on the interface. + */ + public static String getRawPrimaryCpuAbi(AndroidPackage pkg) { + return pkg.getPrimaryCpuAbi(); + } + + /** + * Returns the secondary ABI as parsed from the package. Used only during parsing and + * derivation. Otherwise prefer {@link #getSecondaryCpuAbi(AndroidPackage, PackageSetting)}. + * + * TODO(b/135203078): Actually hide the method + * Placed in the utility to hide the method on the interface. + */ + public static String getRawSecondaryCpuAbi(AndroidPackage pkg) { + return pkg.getSecondaryCpuAbi(); + } + + public static String getSeInfo(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) { + if (pkgSetting != null) { + String overrideSeInfo = pkgSetting.getPkgState().getOverrideSeInfo(); + if (!TextUtils.isEmpty(overrideSeInfo)) { + return overrideSeInfo; + } + } + return pkg.getSeInfo(); + } +} diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java new file mode 100644 index 000000000000..2b508ea3d134 --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java @@ -0,0 +1,752 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing.pkg; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.ParsingPackageImpl; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedMainComponent; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; +import android.content.res.TypedArray; +import android.os.Environment; +import android.os.Parcel; +import android.os.UserHandle; +import android.os.storage.StorageManager; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; +import com.android.server.pm.parsing.PackageInfoUtils; + +import java.util.Comparator; +import java.util.List; +import java.util.UUID; + +/** + * Extensions to {@link ParsingPackageImpl} including fields/state contained in the system server + * and not exposed to the core SDK. + * + * Many of the fields contained here will eventually be moved inside + * {@link com.android.server.pm.PackageSetting} or {@link android.content.pm.PackageUserState}. + * + * @hide + */ +public final class PackageImpl extends ParsingPackageImpl implements ParsedPackage, AndroidPackage { + + public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath, + @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) { + return new PackageImpl(packageName, baseCodePath, codePath, manifestArray, isCoreApp); + } + + /** + * Mock an unavailable {@link AndroidPackage} to use when + * removing + * a package from the system. + * This can occur if the package was installed on a storage device that has since been removed. + * Since the infrastructure uses {@link AndroidPackage}, but + * for + * this case only cares about + * volumeUuid, just fake it rather than having separate method paths. + */ + public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) { + return ((ParsedPackage) PackageImpl.forTesting(packageName) + .setVolumeUuid(volumeUuid) + .hideAsParsed()) + .hideAsFinal(); + } + + @VisibleForTesting + public static ParsingPackage forTesting(String packageName) { + return forTesting(packageName, ""); + } + + @VisibleForTesting + public static ParsingPackage forTesting(String packageName, String baseCodePath) { + return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false); + } + + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + private final String manifestPackageName; + + private boolean stub; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String nativeLibraryDir; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String nativeLibraryRootDir; + + private boolean nativeLibraryRootRequiresIsa; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String primaryCpuAbi; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String secondaryCpuAbi; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String secondaryNativeLibraryDir; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String seInfo; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String seInfoUser; + + private boolean coreApp; + + private boolean system; + private boolean factoryTest; + + private boolean systemExt; + private boolean privileged; + private boolean oem; + private boolean vendor; + private boolean product; + private boolean odm; + + private boolean signedWithPlatformKey; + + /** + * This is an appId, the uid if the userId is == USER_SYSTEM + */ + private int uid = -1; + + @VisibleForTesting + public PackageImpl(@NonNull String packageName, @NonNull String baseCodePath, + @NonNull String codePath, @Nullable TypedArray manifestArray, boolean isCoreApp) { + super(packageName, baseCodePath, codePath, manifestArray); + this.manifestPackageName = this.packageName; + this.coreApp = isCoreApp; + } + + @Override + public ParsedPackage hideAsParsed() { + return this; + } + + @Override + public AndroidPackage hideAsFinal() { + // TODO(b/135203078): Lock as immutable + return this; + } + + @Override + public long getLongVersionCode() { + return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); + } + + @Override + public PackageImpl removePermission(int index) { + this.permissions.remove(index); + return this; + } + + @Override + public PackageImpl addUsesOptionalLibrary(int index, String libraryName) { + this.usesOptionalLibraries = CollectionUtils.add(usesOptionalLibraries, index, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl addUsesLibrary(int index, String libraryName) { + this.usesLibraries = CollectionUtils.add(usesLibraries, index, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl removeUsesLibrary(String libraryName) { + this.usesLibraries = CollectionUtils.remove(this.usesLibraries, libraryName); + return this; + } + + @Override + public PackageImpl removeUsesOptionalLibrary(String libraryName) { + super.removeUsesOptionalLibrary(libraryName); + return this; + } + + @Override + public PackageImpl setSigningDetails(@Nullable PackageParser.SigningDetails value) { + super.setSigningDetails(value); + return this; + } + + @Override + public PackageImpl setRestrictUpdateHash(@Nullable byte... value) { + super.setRestrictUpdateHash(value); + return this; + } + + @Override + public PackageImpl setRealPackage(@Nullable String realPackage) { + super.setRealPackage(realPackage); + return this; + } + + @Override + public PackageImpl setPersistent(boolean value) { + super.setPersistent(value); + return this; + } + + @Override + public PackageImpl setDefaultToDeviceProtectedStorage(boolean value) { + super.setDefaultToDeviceProtectedStorage(value); + return this; + } + + @Override + public PackageImpl setDirectBootAware(boolean value) { + super.setDirectBootAware(value); + return this; + } + + @Override + public PackageImpl clearProtectedBroadcasts() { + protectedBroadcasts.clear(); + return this; + } + + @Override + public PackageImpl clearOriginalPackages() { + originalPackages.clear(); + return this; + } + + @Override + public PackageImpl clearAdoptPermissions() { + adoptPermissions.clear(); + return this; + } + + @Override + public PackageImpl setCodePath(@NonNull String value) { + this.codePath = value; + return this; + } + + // TODO(b/135203078): Move PackageManagerService#renameStaticSharedLibraryPackage + // into initial package parsing + @Override + public PackageImpl setPackageName(@NonNull String packageName) { + this.packageName = TextUtils.safeIntern(packageName); + + int permissionsSize = permissions.size(); + for (int index = 0; index < permissionsSize; index++) { + permissions.get(index).setPackageName(this.packageName); + } + + int permissionGroupsSize = permissionGroups.size(); + for (int index = 0; index < permissionGroupsSize; index++) { + permissionGroups.get(index).setPackageName(this.packageName); + } + + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + activities.get(index).setPackageName(this.packageName); + } + + int receiversSize = receivers.size(); + for (int index = 0; index < receiversSize; index++) { + receivers.get(index).setPackageName(this.packageName); + } + + int providersSize = providers.size(); + for (int index = 0; index < providersSize; index++) { + providers.get(index).setPackageName(this.packageName); + } + + int servicesSize = services.size(); + for (int index = 0; index < servicesSize; index++) { + services.get(index).setPackageName(this.packageName); + } + + int instrumentationsSize = instrumentations.size(); + for (int index = 0; index < instrumentationsSize; index++) { + instrumentations.get(index).setPackageName(this.packageName); + } + + return this; + } + + @Override + public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) { + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + activities.get(index).setDirectBootAware(allComponentsDirectBootAware); + } + + int receiversSize = receivers.size(); + for (int index = 0; index < receiversSize; index++) { + receivers.get(index).setDirectBootAware(allComponentsDirectBootAware); + } + + int providersSize = providers.size(); + for (int index = 0; index < providersSize; index++) { + providers.get(index).setDirectBootAware(allComponentsDirectBootAware); + } + + int servicesSize = services.size(); + for (int index = 0; index < servicesSize; index++) { + services.get(index).setDirectBootAware(allComponentsDirectBootAware); + } + + return this; + } + + @Override + public PackageImpl setBaseCodePath(@NonNull String baseCodePath) { + this.baseCodePath = TextUtils.safeIntern(baseCodePath); + return this; + } + + @Override + public PackageImpl setNativeLibraryDir(@Nullable String nativeLibraryDir) { + this.nativeLibraryDir = TextUtils.safeIntern(nativeLibraryDir); + return this; + } + + @Override + public PackageImpl setNativeLibraryRootDir(@Nullable String nativeLibraryRootDir) { + this.nativeLibraryRootDir = TextUtils.safeIntern(nativeLibraryRootDir); + return this; + } + + @Override + public PackageImpl setPrimaryCpuAbi(@Nullable String primaryCpuAbi) { + this.primaryCpuAbi = TextUtils.safeIntern(primaryCpuAbi); + return this; + } + + @Override + public PackageImpl setSecondaryCpuAbi(@Nullable String secondaryCpuAbi) { + this.secondaryCpuAbi = TextUtils.safeIntern(secondaryCpuAbi); + return this; + } + + @Override + public PackageImpl setSecondaryNativeLibraryDir(@Nullable String secondaryNativeLibraryDir) { + this.secondaryNativeLibraryDir = TextUtils.safeIntern(secondaryNativeLibraryDir); + return this; + } + + @Override + public PackageImpl setSeInfo(@Nullable String seInfo) { + this.seInfo = TextUtils.safeIntern(seInfo); + return this; + } + + @Override + public PackageImpl setSeInfoUser(@Nullable String seInfoUser) { + this.seInfoUser = TextUtils.safeIntern(seInfoUser); + return this; + } + + @Override + public PackageImpl setSplitCodePaths(@Nullable String[] splitCodePaths) { + this.splitCodePaths = splitCodePaths; + if (splitCodePaths != null) { + int size = splitCodePaths.length; + for (int index = 0; index < size; index++) { + this.splitCodePaths[index] = TextUtils.safeIntern(this.splitCodePaths[index]); + } + } + return this; + } + + @Override + public PackageImpl capPermissionPriorities() { + int size = permissionGroups.size(); + for (int index = size - 1; index >= 0; --index) { + // TODO(b/135203078): Builder/immutability + permissionGroups.get(index).setPriority(0); + } + return this; + } + + @Override + public PackageImpl markNotActivitiesAsNotExportedIfSingleUser() { + // ignore export request for single user receivers + int receiversSize = receivers.size(); + for (int index = 0; index < receiversSize; index++) { + ParsedActivity receiver = receivers.get(index); + if ((receiver.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) { + receiver.setExported(false); + } + } + + // ignore export request for single user services + int servicesSize = services.size(); + for (int index = 0; index < servicesSize; index++) { + ParsedService service = services.get(index); + if ((service.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) { + service.setExported(false); + } + } + + // ignore export request for single user providers + int providersSize = providers.size(); + for (int index = 0; index < providersSize; index++) { + ParsedProvider provider = providers.get(index); + if ((provider.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) { + provider.setExported(false); + } + } + + return this; + } + + @Override + public UUID getStorageUuid() { + return StorageManager.convert(volumeUuid); + } + + @Deprecated + @Override + public String toAppInfoToString() { + return "ApplicationInfo{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + getPackageName() + "}"; + } + + @Override + public ParsedPackage setCoreApp(boolean coreApp) { + this.coreApp = coreApp; + return this; + } + + @Override + public ParsedPackage setVersionCode(int versionCode) { + this.versionCode = versionCode; + return this; + } + + @Override + public ParsedPackage setVersionCodeMajor(int versionCodeMajor) { + this.versionCodeMajor = versionCodeMajor; + return this; + } + + @Override + public ApplicationInfo toAppInfoWithoutState() { + ApplicationInfo appInfo = super.toAppInfoWithoutState(); + appInfo.flags = PackageInfoUtils.appInfoFlags(this, null); + appInfo.privateFlags = PackageInfoUtils.appInfoPrivateFlags(this, null); + appInfo.nativeLibraryDir = nativeLibraryDir; + appInfo.nativeLibraryRootDir = nativeLibraryRootDir; + appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; + appInfo.primaryCpuAbi = primaryCpuAbi; + appInfo.secondaryCpuAbi = secondaryCpuAbi; + appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir; + appInfo.seInfo = seInfo; + appInfo.seInfoUser = seInfoUser; + appInfo.uid = uid; + return appInfo; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + sForString.parcel(this.manifestPackageName, dest, flags); + dest.writeBoolean(this.stub); + sForString.parcel(this.nativeLibraryDir, dest, flags); + sForString.parcel(this.nativeLibraryRootDir, dest, flags); + dest.writeBoolean(this.nativeLibraryRootRequiresIsa); + sForString.parcel(this.primaryCpuAbi, dest, flags); + sForString.parcel(this.secondaryCpuAbi, dest, flags); + sForString.parcel(this.secondaryNativeLibraryDir, dest, flags); + sForString.parcel(this.seInfo, dest, flags); + sForString.parcel(this.seInfoUser, dest, flags); + dest.writeInt(this.uid); + dest.writeBoolean(this.coreApp); + dest.writeBoolean(this.system); + dest.writeBoolean(this.factoryTest); + dest.writeBoolean(this.systemExt); + dest.writeBoolean(this.privileged); + dest.writeBoolean(this.oem); + dest.writeBoolean(this.vendor); + dest.writeBoolean(this.product); + dest.writeBoolean(this.odm); + dest.writeBoolean(this.signedWithPlatformKey); + } + + public PackageImpl(Parcel in) { + super(in); + this.manifestPackageName = sForString.unparcel(in); + this.stub = in.readBoolean(); + this.nativeLibraryDir = sForString.unparcel(in); + this.nativeLibraryRootDir = sForString.unparcel(in); + this.nativeLibraryRootRequiresIsa = in.readBoolean(); + this.primaryCpuAbi = sForString.unparcel(in); + this.secondaryCpuAbi = sForString.unparcel(in); + this.secondaryNativeLibraryDir = sForString.unparcel(in); + this.seInfo = sForString.unparcel(in); + this.seInfoUser = sForString.unparcel(in); + this.uid = in.readInt(); + this.coreApp = in.readBoolean(); + this.system = in.readBoolean(); + this.factoryTest = in.readBoolean(); + this.systemExt = in.readBoolean(); + this.privileged = in.readBoolean(); + this.oem = in.readBoolean(); + this.vendor = in.readBoolean(); + this.product = in.readBoolean(); + this.odm = in.readBoolean(); + this.signedWithPlatformKey = in.readBoolean(); + } + + public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() { + @Override + public PackageImpl createFromParcel(Parcel source) { + return new PackageImpl(source); + } + + @Override + public PackageImpl[] newArray(int size) { + return new PackageImpl[size]; + } + }; + + @NonNull + @Override + public String getManifestPackageName() { + return manifestPackageName; + } + + @DataClass.Generated.Member + public boolean isStub() { + return stub; + } + + @Nullable + @Override + public String getNativeLibraryDir() { + return nativeLibraryDir; + } + + @Nullable + @Override + public String getNativeLibraryRootDir() { + return nativeLibraryRootDir; + } + + @Override + public boolean isNativeLibraryRootRequiresIsa() { + return nativeLibraryRootRequiresIsa; + } + + @Nullable + @Override + public String getPrimaryCpuAbi() { + return primaryCpuAbi; + } + + @Nullable + @Override + public String getSecondaryCpuAbi() { + return secondaryCpuAbi; + } + + @Nullable + @Override + public String getSecondaryNativeLibraryDir() { + return secondaryNativeLibraryDir; + } + + @Nullable + @Override + public String getSeInfo() { + return seInfo; + } + + @Nullable + @Override + public String getSeInfoUser() { + return seInfoUser; + } + + @Override + public boolean isCoreApp() { + return coreApp; + } + + @Override + public boolean isSystem() { + return system; + } + + @Override + public boolean isFactoryTest() { + return factoryTest; + } + + @Override + public boolean isSystemExt() { + return systemExt; + } + + @Override + public boolean isPrivileged() { + return privileged; + } + + @Override + public boolean isOem() { + return oem; + } + + @Override + public boolean isVendor() { + return vendor; + } + + @Override + public boolean isProduct() { + return product; + } + + @Override + public boolean isOdm() { + return odm; + } + + @Override + public boolean isSignedWithPlatformKey() { + return signedWithPlatformKey; + } + + /** + * This is an appId, the uid if the userId is == USER_SYSTEM + */ + @Override + public int getUid() { + return uid; + } + + @DataClass.Generated.Member + public PackageImpl setStub(boolean value) { + stub = value; + return this; + } + + @Override + public PackageImpl setNativeLibraryRootRequiresIsa(boolean value) { + nativeLibraryRootRequiresIsa = value; + return this; + } + + @Override + public PackageImpl setSystem(boolean value) { + system = value; + return this; + } + + @Override + public PackageImpl setFactoryTest(boolean value) { + factoryTest = value; + return this; + } + + @Override + public PackageImpl setSystemExt(boolean value) { + systemExt = value; + return this; + } + + @Override + public PackageImpl setPrivileged(boolean value) { + privileged = value; + return this; + } + + @Override + public PackageImpl setOem(boolean value) { + oem = value; + return this; + } + + @Override + public PackageImpl setVendor(boolean value) { + vendor = value; + return this; + } + + @Override + public PackageImpl setProduct(boolean value) { + product = value; + return this; + } + + @Override + public PackageImpl setOdm(boolean value) { + odm = value; + return this; + } + + @Override + public PackageImpl setSignedWithPlatformKey(boolean value) { + signedWithPlatformKey = value; + return this; + } + + /** + * This is an appId, the uid if the userId is == USER_SYSTEM + */ + @Override + public PackageImpl setUid(int value) { + uid = value; + return this; + } + + @DataClass.Generated( + time = 1580517688900L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java", + inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String manifestPackageName\nprivate boolean stub\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String nativeLibraryDir\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String nativeLibraryRootDir\nprivate boolean nativeLibraryRootRequiresIsa\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String primaryCpuAbi\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String secondaryCpuAbi\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String secondaryNativeLibraryDir\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String seInfo\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String seInfoUser\nprivate boolean system\nprivate boolean factoryTest\nprivate boolean systemExt\nprivate boolean privileged\nprivate boolean oem\nprivate boolean vendor\nprivate boolean product\nprivate boolean odm\nprivate boolean signedWithPlatformKey\nprivate int uid\npublic static final com.android.server.pm.parsing.pkg.Creator<com.android.server.pm.parsing.pkg.PackageImpl> CREATOR\npublic static com.android.server.pm.parsing.pkg.PackageImpl forParsing(java.lang.String,java.lang.String,java.lang.String,android.content.res.TypedArray,boolean)\npublic static com.android.server.pm.parsing.pkg.AndroidPackage buildFakeForDeletion(java.lang.String,java.lang.String)\npublic static @com.android.internal.annotations.VisibleForTesting android.content.pm.parsing.ParsingPackage forTesting(java.lang.String)\npublic static @com.android.internal.annotations.VisibleForTesting android.content.pm.parsing.ParsingPackage forTesting(java.lang.String,java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage hideAsParsed()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.AndroidPackage hideAsFinal()\npublic @java.lang.Override long getLongVersionCode()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl removePermission(int)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl addUsesOptionalLibrary(int,java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl addUsesLibrary(int,java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl removeUsesLibrary(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl removeUsesOptionalLibrary(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSigningDetails(android.content.pm.PackageParser.SigningDetails)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setRestrictUpdateHash(byte)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setRealPackage(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setPersistent(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setDefaultToDeviceProtectedStorage(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setDirectBootAware(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl clearProtectedBroadcasts()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl clearOriginalPackages()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl clearAdoptPermissions()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setCodePath(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setPackageName(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setAllComponentsDirectBootAware(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setBaseCodePath(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setNativeLibraryDir(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setNativeLibraryRootDir(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setPrimaryCpuAbi(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSecondaryCpuAbi(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSecondaryNativeLibraryDir(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSeInfo(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSeInfoUser(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSplitCodePaths(java.lang.String[])\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl capPermissionPriorities()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl markNotActivitiesAsNotExportedIfSingleUser()\npublic @java.lang.Override java.util.UUID getStorageUuid()\npublic @java.lang.Deprecated @java.lang.Override java.lang.String toAppInfoToString()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage setCoreApp(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage setVersionCode(int)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage setVersionCodeMajor(int)\npublic @java.lang.Override android.content.pm.ApplicationInfo toAppInfoWithoutState()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass PackageImpl extends android.content.pm.parsing.ParsingPackageImpl implements [com.android.server.pm.parsing.pkg.ParsedPackage, com.android.server.pm.parsing.pkg.AndroidPackage]\n@com.android.internal.util.DataClass(genConstructor=false, genParcelable=false, genAidl=false, genBuilder=false, genHiddenConstructor=false, genCopyConstructor=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/content/pm/parsing/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java index 05cf586522f2..2660f2bda23b 100644 --- a/core/java/android/content/pm/parsing/ParsedPackage.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,9 @@ * limitations under the License. */ -package android.content.pm.parsing; +package com.android.server.pm.parsing.pkg; +import android.annotation.Nullable; import android.content.pm.PackageParser; /** @@ -42,26 +43,10 @@ public interface ParsedPackage extends AndroidPackage { ParsedPackage clearProtectedBroadcasts(); - /** - * TODO(b/135203078): Use non-AppInfo method - * @deprecated use {@link #setCodePath(String)} - */ - @Deprecated - ParsedPackage setApplicationInfoCodePath(String applicationInfoCodePath); - - /** - * TODO(b/135203078): Use non-AppInfo method - * @deprecated use {@link #setCodePath(String)} - */ - @Deprecated - ParsedPackage setApplicationInfoResourcePath(String applicationInfoResourcePath); - ParsedPackage setBaseCodePath(String baseCodePath); ParsedPackage setCodePath(String codePath); - ParsedPackage setCpuAbiOverride(String cpuAbiOverride); - ParsedPackage setNativeLibraryDir(String nativeLibraryDir); ParsedPackage setNativeLibraryRootDir(String nativeLibraryRootDir); @@ -70,9 +55,7 @@ public interface ParsedPackage extends AndroidPackage { ParsedPackage setPrimaryCpuAbi(String primaryCpuAbi); - ParsedPackage setProcessName(String processName); - - ParsedPackage setRealPackage(String realPackage); + ParsedPackage setRealPackage(@Nullable String realPackage); ParsedPackage setSecondaryCpuAbi(String secondaryCpuAbi); @@ -80,8 +63,6 @@ public interface ParsedPackage extends AndroidPackage { ParsedPackage setSplitCodePaths(String[] splitCodePaths); - ParsedPackage initForUser(int userId); - ParsedPackage setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa); ParsedPackage setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware); @@ -104,8 +85,6 @@ public interface ParsedPackage extends AndroidPackage { ParsedPackage setSystemExt(boolean systemExt); - ParsedPackage setUpdatedSystemApp(boolean updatedSystemApp); - ParsedPackage setVendor(boolean vendor); ParsedPackage removePermission(int index); @@ -114,19 +93,9 @@ public interface ParsedPackage extends AndroidPackage { ParsedPackage removeUsesOptionalLibrary(String libraryName); - ParsedPackage setApplicationInfoBaseResourcePath(String applicationInfoBaseResourcePath); - - ParsedPackage setApplicationInfoSplitResourcePaths( - String[] applicationInfoSplitResourcePaths); - - ParsedPackage setApplicationVolumeUuid(String applicationVolumeUuid); - ParsedPackage setCoreApp(boolean coreApp); - ParsedPackage setIsStub(boolean isStub); - - // TODO(b/135203078): Remove entirely - ParsedPackage setPackageSettingCallback(PackageSettingCallback packageSettingCallback); + ParsedPackage setStub(boolean isStub); ParsedPackage setRestrictUpdateHash(byte[] restrictUpdateHash); @@ -148,8 +117,4 @@ public interface ParsedPackage extends AndroidPackage { ParsedPackage setDirectBootAware(boolean directBootAware); ParsedPackage setPersistent(boolean persistent); - - interface PackageSettingCallback { - default void setAndroidPackage(AndroidPackage pkg){} - } } diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java b/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java new file mode 100644 index 000000000000..0cb425f9243b --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing.pkg; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.ApplicationInfo; +import android.util.SparseArray; + +import com.android.internal.R; + +/** + * Container for fields that are eventually exposed through {@link ApplicationInfo}. + * + * Done to separate the meaningless, re-directed JavaDoc for methods and to separate what's + * exposed vs not exposed to core. + * + * @hide + */ +interface PkgAppInfo { + + /** @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE */ + boolean isCantSaveState(); + + /** + * @see ApplicationInfo#appComponentFactory + * @see R.styleable#AndroidManifestApplication_appComponentFactory + */ + @Nullable + String getAppComponentFactory(); + + /** + * @see ApplicationInfo#backupAgentName + * @see R.styleable#AndroidManifestApplication_backupAgent + */ + @Nullable + String getBackupAgentName(); + + /** + * @see ApplicationInfo#banner + * @see R.styleable#AndroidManifestApplication_banner + */ + int getBanner(); + + /** + * @see ApplicationInfo#category + * @see R.styleable#AndroidManifestApplication_appCategory + */ + int getCategory(); + + /** + * @see ApplicationInfo#classLoaderName + * @see R.styleable#AndroidManifestApplication_classLoader + */ + @Nullable + String getClassLoaderName(); + + /** + * @see ApplicationInfo#className + * @see R.styleable#AndroidManifestApplication_name + */ + @Nullable + String getClassName(); + + /** + * @see ApplicationInfo#compatibleWidthLimitDp + * @see R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp + */ + int getCompatibleWidthLimitDp(); + + /** + * @see ApplicationInfo#compileSdkVersion + * @see R.styleable#AndroidManifest_compileSdkVersion + */ + int getCompileSdkVersion(); + + /** + * @see ApplicationInfo#compileSdkVersionCodename + * @see R.styleable#AndroidManifest_compileSdkVersionCodename + */ + @Nullable + String getCompileSdkVersionCodeName(); + + /** + * @see ApplicationInfo#descriptionRes + * @see R.styleable#AndroidManifestApplication_description + */ + int getDescriptionRes(); + + /** + * @see ApplicationInfo#fullBackupContent + * @see R.styleable#AndroidManifestApplication_fullBackupContent + */ + int getFullBackupContent(); + + /** + * @see ApplicationInfo#iconRes + * @see R.styleable#AndroidManifestApplication_icon + */ + int getIconRes(); + + /** + * @see ApplicationInfo#labelRes + * @see R.styleable#AndroidManifestApplication_label + */ + int getLabelRes(); + + /** + * @see ApplicationInfo#largestWidthLimitDp + * @see R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp + */ + int getLargestWidthLimitDp(); + + /** + * @see ApplicationInfo#logo + * @see R.styleable#AndroidManifestApplication_logo + */ + int getLogo(); + + /** + * @see ApplicationInfo#manageSpaceActivityName + * @see R.styleable#AndroidManifestApplication_manageSpaceActivity + */ + @Nullable + String getManageSpaceActivityName(); + + /** + * @see ApplicationInfo#maxAspectRatio + * @see R.styleable#AndroidManifestApplication_maxAspectRatio + */ + float getMaxAspectRatio(); + + /** + * @see ApplicationInfo#minAspectRatio + * @see R.styleable#AndroidManifestApplication_minAspectRatio + */ + float getMinAspectRatio(); + + /** + * @see ApplicationInfo#minSdkVersion + * @see R.styleable#AndroidManifestUsesSdk_minSdkVersion + */ + int getMinSdkVersion(); + + /** @see ApplicationInfo#nativeLibraryDir */ + @Nullable + String getNativeLibraryDir(); + + /** @see ApplicationInfo#nativeLibraryRootDir */ + @Nullable + String getNativeLibraryRootDir(); + + /** + * @see ApplicationInfo#networkSecurityConfigRes + * @see R.styleable#AndroidManifestApplication_networkSecurityConfig + */ + int getNetworkSecurityConfigRes(); + + /** + * If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it. + * Otherwise, it's stored as {@link #getLabelRes()}. + * @see ApplicationInfo#nonLocalizedLabel + * @see R.styleable#AndroidManifestApplication_label + */ + @Nullable + CharSequence getNonLocalizedLabel(); + + /** + * @see ApplicationInfo#permission + * @see R.styleable#AndroidManifestApplication_permission + */ + @Nullable + String getPermission(); + + /** + * TODO(b/135203078): Hide this in the utility, should never be accessed directly + * @see ApplicationInfo#primaryCpuAbi + */ + @Nullable + String getPrimaryCpuAbi(); + + /** + * @see ApplicationInfo#processName + * @see R.styleable#AndroidManifestApplication_process + */ + @NonNull + String getProcessName(); + + /** + * @see ApplicationInfo#requiresSmallestWidthDp + * @see R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp + */ + int getRequiresSmallestWidthDp(); + + /** + * @see ApplicationInfo#roundIconRes + * @see R.styleable#AndroidManifestApplication_roundIcon + */ + int getRoundIconRes(); + + /** @see ApplicationInfo#seInfo */ + @Nullable + String getSeInfo(); + + /** @see ApplicationInfo#seInfoUser */ + @Nullable + String getSeInfoUser(); + + /** @see ApplicationInfo#secondaryCpuAbi */ + @Nullable + String getSecondaryCpuAbi(); + + /** @see ApplicationInfo#secondaryNativeLibraryDir */ + @Nullable + String getSecondaryNativeLibraryDir(); + + /** + * @see ApplicationInfo#installLocation + * @see R.styleable#AndroidManifest_installLocation + */ + int getInstallLocation(); + + /** + * @see ApplicationInfo#splitClassLoaderNames + * @see R.styleable#AndroidManifestApplication_classLoader + */ + @Nullable + String[] getSplitClassLoaderNames(); + + /** @see ApplicationInfo#splitSourceDirs */ + @Nullable + String[] getSplitCodePaths(); + + /** @see ApplicationInfo#splitDependencies */ + @Nullable + SparseArray<int[]> getSplitDependencies(); + + /** + * @see ApplicationInfo#targetSandboxVersion + * @see R.styleable#AndroidManifest_targetSandboxVersion + */ + @Deprecated + int getTargetSandboxVersion(); + + /** + * @see ApplicationInfo#targetSdkVersion + * @see R.styleable#AndroidManifestUsesSdk_targetSdkVersion + */ + int getTargetSdkVersion(); + + /** + * @see ApplicationInfo#taskAffinity + * @see R.styleable#AndroidManifestApplication_taskAffinity + */ + @Nullable + String getTaskAffinity(); + + /** + * @see ApplicationInfo#theme + * @see R.styleable#AndroidManifestApplication_theme + */ + int getTheme(); + + /** + * @see ApplicationInfo#uiOptions + * @see R.styleable#AndroidManifestApplication_uiOptions + */ + int getUiOptions(); + + /** @see ApplicationInfo#uid */ + int getUid(); + + /** @see ApplicationInfo#longVersionCode */ + long getLongVersionCode(); + + /** @see ApplicationInfo#versionCode */ + @Deprecated + int getVersionCode(); + + /** @see ApplicationInfo#volumeUuid */ + @Nullable + String getVolumeUuid(); + + /** @see ApplicationInfo#zygotePreloadName */ + @Nullable + String getZygotePreloadName(); + + /** @see ApplicationInfo#FLAG_HAS_CODE */ + boolean isHasCode(); + + /** @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING */ + boolean isAllowTaskReparenting(); + + /** @see ApplicationInfo#FLAG_MULTIARCH */ + boolean isMultiArch(); + + /** @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS */ + boolean isExtractNativeLibs(); + + /** @see ApplicationInfo#FLAG_DEBUGGABLE */ + boolean isDebuggable(); + + /** @see ApplicationInfo#FLAG_VM_SAFE_MODE */ + boolean isVmSafeMode(); + + /** @see ApplicationInfo#FLAG_PERSISTENT */ + boolean isPersistent(); + + /** @see ApplicationInfo#FLAG_ALLOW_BACKUP */ + boolean isAllowBackup(); + + /** @see ApplicationInfo#FLAG_TEST_ONLY */ + boolean isTestOnly(); + + /** @see ApplicationInfo#PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION */ + boolean isResizeableActivityViaSdkVersion(); + + /** @see ApplicationInfo#PRIVATE_FLAG_HAS_DOMAIN_URLS */ + boolean isHasDomainUrls(); + + /** @see ApplicationInfo#PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE */ + boolean isRequestLegacyExternalStorage(); + + /** @see ApplicationInfo#FLAG_HARDWARE_ACCELERATED */ + boolean isBaseHardwareAccelerated(); + + /** @see ApplicationInfo#PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE */ + boolean isDefaultToDeviceProtectedStorage(); + + /** @see ApplicationInfo#PRIVATE_FLAG_DIRECT_BOOT_AWARE */ + boolean isDirectBootAware(); + + /** @see ApplicationInfo#PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE */ + boolean isPartiallyDirectBootAware(); + + /** @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX */ + boolean isUseEmbeddedDex(); + + /** @see ApplicationInfo#FLAG_EXTERNAL_STORAGE */ + boolean isExternalStorage(); + + /** @see ApplicationInfo#nativeLibraryRootRequiresIsa */ + boolean isNativeLibraryRootRequiresIsa(); + + /** @see ApplicationInfo#PRIVATE_FLAG_ODM */ + boolean isOdm(); + + /** @see ApplicationInfo#PRIVATE_FLAG_OEM */ + boolean isOem(); + + /** @see ApplicationInfo#PRIVATE_FLAG_PRIVILEGED */ + boolean isPrivileged(); + + /** @see ApplicationInfo#PRIVATE_FLAG_PRODUCT */ + boolean isProduct(); + + /** @see ApplicationInfo#PRIVATE_FLAG_PROFILEABLE_BY_SHELL */ + boolean isProfileableByShell(); + + /** @see ApplicationInfo#PRIVATE_FLAG_STATIC_SHARED_LIBRARY */ + boolean isStaticSharedLibrary(); + + /** @see ApplicationInfo#FLAG_SYSTEM */ + boolean isSystem(); + + /** @see ApplicationInfo#PRIVATE_FLAG_SYSTEM_EXT */ + boolean isSystemExt(); + + /** @see ApplicationInfo#PRIVATE_FLAG_VENDOR */ + boolean isVendor(); + + /** @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING */ + boolean isIsolatedSplitLoading(); + + /** + * @see ApplicationInfo#enabled + * @see R.styleable#AndroidManifestApplication_enabled + */ + boolean isEnabled(); + + /** + * @see ApplicationInfo#PRIVATE_FLAG_IS_RESOURCE_OVERLAY + * @see ApplicationInfo#isResourceOverlay() + */ + boolean isOverlay(); + + /** @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API */ + boolean isUsesNonSdkApi(); + + /** @see ApplicationInfo#PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY */ + boolean isSignedWithPlatformKey(); + + /** @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE */ + boolean isKillAfterRestore(); + + /** @see ApplicationInfo#FLAG_RESTORE_ANY_VERSION */ + boolean isRestoreAnyVersion(); + + /** @see ApplicationInfo#FLAG_FULL_BACKUP_ONLY */ + boolean isFullBackupOnly(); + + /** @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA */ + boolean isAllowClearUserData(); + + /** @see ApplicationInfo#FLAG_LARGE_HEAP */ + boolean isLargeHeap(); + + /** @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC */ + boolean isUsesCleartextTraffic(); + + /** @see ApplicationInfo#FLAG_SUPPORTS_RTL */ + boolean isSupportsRtl(); + + /** @see ApplicationInfo#FLAG_IS_GAME */ + @Deprecated + boolean isGame(); + + /** @see ApplicationInfo#FLAG_FACTORY_TEST */ + boolean isFactoryTest(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#DONUT}. + * @see R.styleable#AndroidManifestSupportsScreens_smallScreens + * @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS + */ + boolean isSupportsSmallScreens(); + + /** + * If omitted from manifest, returns true. + * @see R.styleable#AndroidManifestSupportsScreens_normalScreens + * @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS + */ + boolean isSupportsNormalScreens(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#DONUT}. + * @see R.styleable#AndroidManifestSupportsScreens_largeScreens + * @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS + */ + boolean isSupportsLargeScreens(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#GINGERBREAD}. + * @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens + * @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS + */ + boolean isSupportsExtraLargeScreens(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#DONUT}. + * @see R.styleable#AndroidManifestSupportsScreens_resizeable + * @see ApplicationInfo#FLAG_RESIZEABLE_FOR_SCREENS + */ + boolean isResizeable(); + + /** + * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= + * {@link android.os.Build.VERSION_CODES#DONUT}. + * @see R.styleable#AndroidManifestSupportsScreens_anyDensity + * @see ApplicationInfo#FLAG_SUPPORTS_SCREEN_DENSITIES + */ + boolean isAnyDensity(); + + /** @see ApplicationInfo#PRIVATE_FLAG_BACKUP_IN_FOREGROUND */ + boolean isBackupInForeground(); + + /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE */ + boolean isAllowClearUserDataOnFailedRestore(); + + /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE */ + boolean isAllowAudioPlaybackCapture(); + + /** @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA */ + boolean isHasFragileUserData(); +} diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java b/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java new file mode 100644 index 000000000000..89330a9894d6 --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing.pkg; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.ActivityInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PermissionInfo; +import android.content.pm.ProviderInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; + +import com.android.internal.R; + +import java.util.List; + +/** + * Container for fields that are eventually exposed through {@link PackageInfo}. + * + * Done to separate the meaningless, re-directed JavaDoc for methods and to separate what's + * exposed vs not exposed to core. + * + * @hide + */ +interface PkgPackageInfo { + + /** + * @see PackageInfo#overlayCategory + * @see R.styleable#AndroidManifestResourceOverlay_category + */ + @Nullable + String getOverlayCategory(); + + /** + * @see PackageInfo#overlayPriority + * @see R.styleable#AndroidManifestResourceOverlay_priority + */ + int getOverlayPriority(); + + /** + * @see PackageInfo#overlayTarget + * @see R.styleable#AndroidManifestResourceOverlay_targetPackage + */ + @Nullable + String getOverlayTarget(); + + /** + * @see PackageInfo#targetOverlayableName + * @see R.styleable#AndroidManifestResourceOverlay_targetName + */ + @Nullable + String getOverlayTargetName(); + + /** + * @see PackageInfo#sharedUserId + * @see R.styleable#AndroidManifest_sharedUserId + */ + @Deprecated + @Nullable + String getSharedUserId(); + + /** + * @see PackageInfo#sharedUserLabel + * @see R.styleable#AndroidManifest_sharedUserLabel + */ + @Deprecated + int getSharedUserLabel(); + + /** + * The required account type without which this application will not function. + * + * @see PackageInfo#requiredAccountType + * @see R.styleable#AndroidManifestApplication_requiredAccountType + */ + @Nullable + String getRequiredAccountType(); + + /** + * The restricted account authenticator type that is used by this application + * + * @see PackageInfo#restrictedAccountType + * @see R.styleable#AndroidManifestApplication_restrictedAccountType + */ + @Nullable + String getRestrictedAccountType(); + + /** @see PackageInfo#splitRevisionCodes */ + int[] getSplitRevisionCodes(); + + /** @see PackageInfo#getLongVersionCode() */ + long getLongVersionCode(); + + /** @see PackageInfo#versionCode */ + @Deprecated + int getVersionCode(); + + /** @see PackageInfo#versionCodeMajor */ + int getVersionCodeMajor(); + + /** @see PackageInfo#versionName */ + @Nullable + String getVersionName(); + + /** @see PackageInfo#mOverlayIsStatic */ + boolean isOverlayIsStatic(); + + /** + * @see PackageInfo#requiredForAllUsers + * @see R.styleable#AndroidManifestApplication_requiredForAllUsers + */ + boolean isRequiredForAllUsers(); + + /** + * @see PackageInfo#reqFeatures + * @see R.styleable#AndroidManifestUsesFeature + */ + @NonNull + List<FeatureInfo> getReqFeatures(); + + /** + * @see PackageInfo#configPreferences + * @see R.styleable#AndroidManifestUsesConfiguration + */ + @NonNull + List<ConfigurationInfo> getConfigPreferences(); + + /** + * @see PackageInfo#featureGroups + * @see R.styleable#AndroidManifestUsesFeature + */ + @NonNull + List<FeatureGroupInfo> getFeatureGroups(); + + /** + * Whether or not the package is a stub and must be replaced by the full version. + * + * @see PackageInfo#isStub + */ + boolean isStub(); + + /** + * For marking packages required for a minimal boot state, through the "coreApp" manifest + * attribute. + * @see PackageInfo#coreApp + */ + boolean isCoreApp(); + + /** + * All the permissions declared. This is an effective set, and may include permissions + * transformed from split/migrated permissions from previous versions, so may not be exactly + * what the package declares in its manifest. + * @see PackageInfo#requestedPermissions + * @see R.styleable#AndroidManifestUsesPermission + */ + @NonNull + List<String> getRequestedPermissions(); + + /** + * @see ActivityInfo + * @see PackageInfo#activities + */ + @NonNull + List<ParsedActivity> getActivities(); + + /** + * @see InstrumentationInfo + * @see PackageInfo#instrumentation + */ + @NonNull + List<ParsedInstrumentation> getInstrumentations(); + + /** + * @see PermissionInfo + * @see PackageInfo#permissions + */ + @NonNull + List<ParsedPermission> getPermissions(); + + /** + * @see ProviderInfo + * @see PackageInfo#providers + */ + @NonNull + List<ParsedProvider> getProviders(); + + /** + * Since they share several attributes, receivers are parsed as {@link ParsedActivity}, even + * though they represent different functionality. + * TODO(b/135203078): Reconsider this and maybe make ParsedReceiver so it's not so confusing + * @see ActivityInfo + * @see PackageInfo#receivers + */ + @NonNull + List<ParsedActivity> getReceivers(); + + /** + * @see ServiceInfo + * @see PackageInfo#services + */ + @NonNull + List<ParsedService> getServices(); +} diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index e323c9869afb..f8e5082ddfa5 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -32,9 +32,7 @@ import android.annotation.Nullable; import android.content.pm.PackageManagerInternal; import android.content.pm.PermissionInfo; import android.content.pm.Signature; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; -import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.component.ParsedPermission; import android.os.UserHandle; import android.util.Log; import android.util.Slog; @@ -43,6 +41,8 @@ import com.android.server.pm.DumpState; import com.android.server.pm.PackageManagerService; import com.android.server.pm.PackageSetting; import com.android.server.pm.PackageSettingBase; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlSerializer; @@ -172,12 +172,12 @@ public final class BasePermission { return 0; } - public boolean isPermission(@NonNull ParsedPermission perm) { + public boolean isPermission(ParsedPermission perm) { if (this.perm == null) { return false; } return Objects.equals(this.perm.getPackageName(), perm.getPackageName()) - && Objects.equals(this.perm.className, perm.className); + && Objects.equals(this.perm.getName(), perm.getName()); } public boolean isDynamic() { @@ -195,24 +195,24 @@ public final class BasePermission { } public boolean isRemoved() { - return perm != null && (perm.flags & PermissionInfo.FLAG_REMOVED) != 0; + return perm != null && (perm.getFlags() & PermissionInfo.FLAG_REMOVED) != 0; } public boolean isSoftRestricted() { - return perm != null && (perm.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0; + return perm != null && (perm.getFlags() & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0; } public boolean isHardRestricted() { - return perm != null && (perm.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0; + return perm != null && (perm.getFlags() & PermissionInfo.FLAG_HARD_RESTRICTED) != 0; } public boolean isHardOrSoftRestricted() { - return perm != null && (perm.flags & (PermissionInfo.FLAG_HARD_RESTRICTED + return perm != null && (perm.getFlags() & (PermissionInfo.FLAG_HARD_RESTRICTED | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0; } public boolean isImmutablyRestricted() { - return perm != null && (perm.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0; + return perm != null && (perm.getFlags() & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0; } public boolean isSignature() { @@ -326,15 +326,8 @@ public final class BasePermission { final BasePermission tree = findPermissionTree(permissionTrees, name); if (tree != null && tree.perm != null) { sourcePackageSetting = tree.sourcePackageSetting; - perm = new ParsedPermission(tree.perm); - perm.protectionLevel = pendingPermissionInfo.protectionLevel; - perm.flags = pendingPermissionInfo.flags; - perm.setGroup(pendingPermissionInfo.group); - perm.backgroundPermission = pendingPermissionInfo.backgroundPermission; - perm.descriptionRes = pendingPermissionInfo.descriptionRes; - perm.requestRes = pendingPermissionInfo.requestRes; - perm.setPackageName(tree.perm.getPackageName()); - perm.setName(name); + perm = new ParsedPermission(tree.perm, pendingPermissionInfo, + tree.perm.getPackageName(), name); uid = tree.uid; } } @@ -364,7 +357,7 @@ public final class BasePermission { if (pkg.isSystem()) { if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) { // It's a built-in permission and no owner, take ownership now - p.flags |= PermissionInfo.FLAG_INSTALLED; + p.setFlags(p.getFlags() | PermissionInfo.FLAG_INSTALLED); bp.sourcePackageSetting = pkgSetting; bp.perm = p; bp.uid = pkg.getUid(); @@ -387,7 +380,7 @@ public final class BasePermission { final BasePermission tree = findPermissionTree(permissionTrees, p.getName()); if (tree == null || tree.sourcePackageName.equals(p.getPackageName())) { - p.flags |= PermissionInfo.FLAG_INSTALLED; + p.setFlags(p.getFlags() | PermissionInfo.FLAG_INSTALLED); bp.sourcePackageSetting = pkgSetting; bp.perm = p; bp.uid = pkg.getUid(); @@ -421,8 +414,8 @@ public final class BasePermission { r.append(p.getName()); } if (bp.perm != null && Objects.equals(bp.perm.getPackageName(), p.getPackageName()) - && Objects.equals(bp.perm.className, p.className)) { - bp.protectionLevel = p.protectionLevel; + && Objects.equals(bp.perm.getName(), p.getName())) { + bp.protectionLevel = p.getProtectionLevel(); } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { Log.d(TAG, " Permissions: " + r); @@ -572,9 +565,9 @@ public final class BasePermission { if (type == BasePermission.TYPE_DYNAMIC) { if (perm != null || pendingPermissionInfo != null) { serializer.attribute(null, "type", "dynamic"); - int icon = perm != null ? perm.icon : pendingPermissionInfo.icon; + int icon = perm != null ? perm.getIcon() : pendingPermissionInfo.icon; CharSequence nonLocalizedLabel = perm != null - ? perm.nonLocalizedLabel + ? perm.getNonLocalizedLabel() : pendingPermissionInfo.nonLocalizedLabel; if (icon != 0) { @@ -602,11 +595,11 @@ public final class BasePermission { } private static boolean comparePermissionInfos(ParsedPermission pi1, PermissionInfo pi2) { - if (pi1.icon != pi2.icon) return false; - if (pi1.logo != pi2.logo) return false; - if (pi1.protectionLevel != pi2.protectionLevel) return false; + if (pi1.getIcon() != pi2.icon) return false; + if (pi1.getLogo() != pi2.logo) return false; + if (pi1.getProtectionLevel() != pi2.protectionLevel) return false; if (!compareStrings(pi1.getName(), pi2.name)) return false; - if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false; + if (!compareStrings(pi1.getNonLocalizedLabel(), pi2.nonLocalizedLabel)) return false; // We'll take care of setting this one. if (!compareStrings(pi1.getPackageName(), pi2.packageName)) return false; // These are not currently stored in settings. @@ -644,9 +637,9 @@ public final class BasePermission { pw.println(PermissionInfo.protectionToString(protectionLevel)); if (perm != null) { pw.print(" perm="); pw.println(perm); - if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0 - || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) { - pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.flags)); + if ((perm.getFlags() & PermissionInfo.FLAG_INSTALLED) == 0 + || (perm.getFlags() & PermissionInfo.FLAG_REMOVED) != 0) { + pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.getFlags())); } } if (sourcePackageSetting != null) { diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index e6eaf211a86a..9c945d5a7ea8 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -150,6 +150,12 @@ public final class DefaultPermissionGrantPolicy { ALWAYS_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION); } + private static final Set<String> FOREGROUND_LOCATION_PERMISSIONS = new ArraySet<>(); + static { + ALWAYS_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION); + ALWAYS_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION); + } + private static final Set<String> COARSE_BACKGROUND_LOCATION_PERMISSIONS = new ArraySet<>(); static { COARSE_BACKGROUND_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION); @@ -587,11 +593,6 @@ public final class DefaultPermissionGrantPolicy { DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId), userId, CONTACTS_PERMISSIONS); - // Maps - grantPermissionsToSystemPackage( - getDefaultSystemHandlerActivityPackageForCategory(Intent.CATEGORY_APP_MAPS, userId), - userId, ALWAYS_LOCATION_PERMISSIONS); - // Email grantPermissionsToSystemPackage( getDefaultSystemHandlerActivityPackageForCategory( @@ -609,7 +610,7 @@ public final class DefaultPermissionGrantPolicy { } } grantPermissionsToPackage(browserPackage, userId, false /* ignoreSystemPackage */, - true /*whitelistRestrictedPermissions*/, ALWAYS_LOCATION_PERMISSIONS); + true /*whitelistRestrictedPermissions*/, FOREGROUND_LOCATION_PERMISSIONS); // Voice interaction if (voiceInteractPackageNames != null) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 36697f9b6d60..980aaed95f2a 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -71,10 +71,8 @@ import android.content.pm.PackageParser; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; -import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedPermissionGroup; import android.content.pm.permission.SplitPermissionInfoParcelable; import android.metrics.LogMaker; import android.os.Binder; @@ -129,6 +127,8 @@ import com.android.server.pm.PackageManagerServiceUtils; import com.android.server.pm.PackageSetting; import com.android.server.pm.SharedUserSetting; import com.android.server.pm.UserManagerService; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultBrowserProvider; import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultDialerProvider; import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultHomeProvider; @@ -1282,7 +1282,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext, - pkg.toAppInfoWithoutState(), UserHandle.of(userId), permName) + pkg.toAppInfoWithoutState(), pkg, UserHandle.of(userId), permName) .mayGrantPermission()) { Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package " + packageName); @@ -2082,9 +2082,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = 0; i < numOldPackagePermissions; i++) { final ParsedPermission permission = oldPackage.getPermissions().get(i); - if (permission.parsedPermissionGroup != null) { + if (permission.getParsedPermissionGroup() != null) { oldPermissionNameToGroupName.put(permission.getName(), - permission.parsedPermissionGroup.getName()); + permission.getParsedPermissionGroup().getName()); } } @@ -2098,8 +2098,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) { final String permissionName = newPermission.getName(); - final String newPermissionGroupName = newPermission.parsedPermissionGroup == null - ? null : newPermission.parsedPermissionGroup.getName(); + final String newPermissionGroupName = + newPermission.getParsedPermissionGroup() == null + ? null : newPermission.getParsedPermissionGroup().getName(); final String oldPermissionGroupName = oldPermissionNameToGroupName.get( permissionName); @@ -2144,7 +2145,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { ParsedPermission p = pkg.getPermissions().get(i); // Assume by default that we did not install this permission into the system. - p.flags &= ~PermissionInfo.FLAG_INSTALLED; + p.setFlags(p.getFlags() & ~PermissionInfo.FLAG_INSTALLED); synchronized (PermissionManagerService.this.mLock) { // Now that permission groups have a special meaning, we ignore permission @@ -2152,16 +2153,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { // permissions for one app being granted to someone just because they happen // to be in a group defined by another app (before this had no implications). if (pkg.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) { - p.parsedPermissionGroup = mSettings.mPermissionGroups.get(p.getGroup()); + p.setParsedPermissionGroup(mSettings.mPermissionGroups.get(p.getGroup())); // Warn for a permission in an unknown group. if (DEBUG_PERMISSIONS - && p.getGroup() != null && p.parsedPermissionGroup == null) { + && p.getGroup() != null && p.getParsedPermissionGroup() == null) { Slog.i(TAG, "Permission " + p.getName() + " from package " + p.getPackageName() + " in an unknown group " + p.getGroup()); } } - if (p.tree) { + if (p.isTree()) { final BasePermission bp = BasePermission.createOrUpdate( mPackageManagerInt, mSettings.getPermissionTreeLocked(p.getName()), p, pkg, @@ -2409,14 +2410,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } + // TODO(b/140256621): The package instant app method has been removed + // as part of work in b/135203078, so this has been commented out in the meantime // Limit ephemeral apps to ephemeral allowed permissions. - if (pkg.isInstantApp() && !bp.isInstant()) { - if (DEBUG_PERMISSIONS) { - Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() - + " for package " + pkg.getPackageName()); - } - continue; - } +// if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) { +// if (DEBUG_PERMISSIONS) { +// Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() +// + " for package " + pkg.getPackageName()); +// } +// continue; +// } if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) { if (DEBUG_PERMISSIONS) { @@ -2450,7 +2453,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } else if (bp.isSignature()) { // For all apps signature permissions are install time ones. - allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions); + allowedSig = grantSignaturePermission(perm, pkg, ps, bp, origPermissions); if (allowedSig) { grant = GRANT_INSTALL; } @@ -2764,7 +2767,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { Slog.i(TAG, "Un-granting permission " + perm + " from package " + pkg.getPackageName() + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" + Integer.toHexString(pkg.getFlags()) + + " flags=0x" + + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps)) + ")"); } } else if (bp.isAppOp()) { @@ -2776,7 +2780,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { Slog.i(TAG, "Not granting permission " + perm + " to package " + pkg.getPackageName() + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" + Integer.toHexString(pkg.getFlags()) + + " flags=0x" + + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps)) + ")"); } } @@ -2784,7 +2789,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() && - !ps.isSystem() || ps.isUpdatedSystem()) { + !ps.isSystem() || !ps.getPkgState().isUpdatedSystemApp()) { // This is the first that we have heard about this package, so the // permissions we have now selected are fixed until explicitly // changed. @@ -2934,7 +2939,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { */ private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated( @NonNull AndroidPackage pkg, boolean replace, @NonNull int[] updatedUserIds) { - if (replace && pkg.hasRequestedLegacyExternalStorage() && ( + if (replace && pkg.isRequestLegacyExternalStorage() && ( pkg.getRequestedPermissions().contains(READ_EXTERNAL_STORAGE) || pkg.getRequestedPermissions().contains(WRITE_EXTERNAL_STORAGE))) { return UserManagerService.getInstance().getUserIds(); @@ -3127,7 +3132,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private boolean grantSignaturePermission(String perm, AndroidPackage pkg, - BasePermission bp, PermissionsState origPermissions) { + PackageSetting pkgSetting, BasePermission bp, PermissionsState origPermissions) { boolean oemPermission = bp.isOEM(); boolean vendorPrivilegedPermission = bp.isVendorPrivileged(); boolean privilegedPermission = bp.isPrivileged() || bp.isVendorPrivileged(); @@ -3139,7 +3144,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { && !platformPackage && platformPermission) { if (!hasPrivappWhitelistEntry(perm, pkg)) { // Only report violations for apps on system image - if (!mSystemReady && !pkg.isUpdatedSystemApp()) { + if (!mSystemReady && !pkgSetting.getPkgState().isUpdatedSystemApp()) { // it's only a reportable violation if the permission isn't explicitly denied ArraySet<String> deniedPermissions = null; if (pkg.isVendor()) { @@ -3205,8 +3210,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (pkg.isSystem()) { // For updated system applications, a privileged/oem permission // is granted only if it had been defined by the original application. - if (pkg.isUpdatedSystemApp()) { - final PackageSetting disabledPs = (PackageSetting) mPackageManagerInt + if (pkgSetting.getPkgState().isUpdatedSystemApp()) { + final PackageSetting disabledPs = mPackageManagerInt .getDisabledSystemPackage(pkg.getPackageName()); final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg; if (disabledPs != null @@ -3612,7 +3617,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return EmptyArray.INT; } for (AndroidPackage pkg : pkgList) { - if (pkg.getRequestedPermissions() == null) { + if (pkg.getRequestedPermissions().isEmpty()) { continue; } final int requestedPermCount = pkg.getRequestedPermissions().size(); @@ -3720,9 +3725,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Only system declares background permissions, hence mapping does never change. mBackgroundPermissions = new ArrayMap<>(); for (BasePermission bp : mSettings.getAllPermissionsLocked()) { - if (bp.perm != null && bp.perm.backgroundPermission != null) { + if (bp.perm != null && bp.perm.getBackgroundPermission() != null) { String fgPerm = bp.name; - String bgPerm = bp.perm.backgroundPermission; + String bgPerm = bp.perm.getBackgroundPermission(); List<String> fgPerms = mBackgroundPermissions.get(bgPerm); if (fgPerms == null) { @@ -4234,7 +4239,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (pkg == null) { return StorageManager.UUID_PRIVATE_INTERNAL; } - if (pkg.isExternal()) { + if (pkg.isExternalStorage()) { if (TextUtils.isEmpty(pkg.getVolumeUuid())) { return StorageManager.UUID_PRIMARY_PHYSICAL; } else { @@ -4246,7 +4251,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private static boolean hasPermission(AndroidPackage pkg, String permName) { - if (pkg.getPermissions() == null) { + if (pkg.getPermissions().isEmpty()) { return false; } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 58a9f42f372d..048e487fdaeb 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -22,9 +22,10 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; -import android.content.pm.parsing.AndroidPackage; import android.permission.PermissionManagerInternal; +import com.android.server.pm.parsing.pkg.AndroidPackage; + import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java index 254b720c57a0..355e24326c8e 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java +++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java @@ -18,7 +18,7 @@ package com.android.server.pm.permission; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.component.ParsedPermissionGroup; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -65,7 +65,7 @@ public class PermissionSettings { * name to permission group object. */ @GuardedBy("mLock") - final ArrayMap<String, ComponentParseUtils.ParsedPermissionGroup> mPermissionGroups = + final ArrayMap<String, ParsedPermissionGroup> mPermissionGroups = new ArrayMap<>(); /** diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java new file mode 100644 index 000000000000..c008d93ca91a --- /dev/null +++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.pkg; + +import static java.util.Collections.emptyList; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.SharedLibraryInfo; + +import com.android.internal.util.DataClass; +import com.android.server.pm.PackageSetting; + +import java.util.List; + +/** + * For use by {@link PackageSetting} to maintain functionality that used to exist in + * {@link PackageParser.Package}. + * + * It is assumed that anything inside the package was not cached or written to disk, so none of + * these fields are either. They must be set on every boot from other state on the device. + */ +@DataClass(genSetters = true, genConstructor = false, genBuilder = false) +public class PackageStateUnserialized { + + private boolean hiddenUntilInstalled; + + @NonNull + private List<SharedLibraryInfo> usesLibraryInfos = emptyList(); + + @NonNull + private List<String> usesLibraryFiles = emptyList(); + + private boolean updatedSystemApp; + + @NonNull + private volatile long[] lastPackageUsageTimeInMills; + + @Nullable + private String overrideSeInfo; + + private long[] lazyInitLastPackageUsageTimeInMills() { + return new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT]; + } + + public PackageStateUnserialized setLastPackageUsageTimeInMills(int reason, long time) { + getLastPackageUsageTimeInMills()[reason] = time; + return this; + } + + public long getLatestPackageUseTimeInMills() { + long latestUse = 0L; + for (long use : getLastPackageUsageTimeInMills()) { + latestUse = Math.max(latestUse, use); + } + return latestUse; + } + + public long getLatestForegroundPackageUseTimeInMills() { + int[] foregroundReasons = { + PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY, + PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE + }; + + long latestUse = 0L; + for (int reason : foregroundReasons) { + latestUse = Math.max(latestUse, getLastPackageUsageTimeInMills()[reason]); + } + return latestUse; + } + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public boolean isHiddenUntilInstalled() { + return hiddenUntilInstalled; + } + + @DataClass.Generated.Member + public @NonNull List<SharedLibraryInfo> getUsesLibraryInfos() { + return usesLibraryInfos; + } + + @DataClass.Generated.Member + public @NonNull List<String> getUsesLibraryFiles() { + return usesLibraryFiles; + } + + @DataClass.Generated.Member + public boolean isUpdatedSystemApp() { + return updatedSystemApp; + } + + @DataClass.Generated.Member + public @NonNull long[] getLastPackageUsageTimeInMills() { + long[] _lastPackageUsageTimeInMills = lastPackageUsageTimeInMills; + if (_lastPackageUsageTimeInMills == null) { + synchronized(this) { + _lastPackageUsageTimeInMills = lastPackageUsageTimeInMills; + if (_lastPackageUsageTimeInMills == null) { + _lastPackageUsageTimeInMills = lastPackageUsageTimeInMills = lazyInitLastPackageUsageTimeInMills(); + } + } + } + return _lastPackageUsageTimeInMills; + } + + @DataClass.Generated.Member + public @Nullable String getOverrideSeInfo() { + return overrideSeInfo; + } + + @DataClass.Generated.Member + public PackageStateUnserialized setHiddenUntilInstalled(boolean value) { + hiddenUntilInstalled = value; + return this; + } + + @DataClass.Generated.Member + public PackageStateUnserialized setUsesLibraryInfos(@NonNull List<SharedLibraryInfo> value) { + usesLibraryInfos = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, usesLibraryInfos); + return this; + } + + @DataClass.Generated.Member + public PackageStateUnserialized setUsesLibraryFiles(@NonNull List<String> value) { + usesLibraryFiles = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, usesLibraryFiles); + return this; + } + + @DataClass.Generated.Member + public PackageStateUnserialized setUpdatedSystemApp(boolean value) { + updatedSystemApp = value; + return this; + } + + @DataClass.Generated.Member + public PackageStateUnserialized setLastPackageUsageTimeInMills(@NonNull long... value) { + lastPackageUsageTimeInMills = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, lastPackageUsageTimeInMills); + return this; + } + + @DataClass.Generated.Member + public PackageStateUnserialized setOverrideSeInfo(@Nullable String value) { + overrideSeInfo = value; + return this; + } + + @DataClass.Generated( + time = 1580422870209L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java", + inputSignatures = "private boolean hiddenUntilInstalled\nprivate @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> usesLibraryInfos\nprivate @android.annotation.NonNull java.util.List<java.lang.String> usesLibraryFiles\nprivate boolean updatedSystemApp\nprivate volatile @android.annotation.NonNull long[] lastPackageUsageTimeInMills\n @android.annotation.Nullable java.lang.String overrideSeInfo\nprivate long[] lazyInitLastPackageUsageTimeInMills()\npublic com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(int,long)\npublic long getLatestPackageUseTimeInMills()\npublic long getLatestForegroundPackageUseTimeInMills()\nclass PackageStateUnserialized extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genConstructor=false, genBuilder=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index ec8e1a05852e..139c844256fa 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -39,7 +39,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PermissionInfo; -import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.Process; import android.os.RemoteException; @@ -65,6 +64,7 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.SystemService; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback; @@ -163,7 +163,7 @@ public final class PermissionPolicyService extends SystemService { if (perm.isSoftRestricted()) { SoftRestrictedPermissionPolicy policy = SoftRestrictedPermissionPolicy.forPermission(null, null, null, - perm.name); + null, perm.name); int extraAppOp = policy.getExtraAppOpCode(); if (extraAppOp != OP_NONE) { appOpsService.startWatchingMode(extraAppOp, null, mAppOpsCallback); @@ -506,17 +506,18 @@ public final class PermissionPolicyService extends SystemService { /** * Note: Called with the package lock held. Do <u>not</u> call into app-op manager. */ - private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull String permissionName) { + private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, + @NonNull String permissionName) { PermissionInfo permissionInfo = mRuntimePermissionInfos.get(permissionName); if (permissionInfo == null) { return; } - addPermissionAppOp(packageInfo, permissionInfo); - addExtraAppOp(packageInfo, permissionInfo); + addPermissionAppOp(packageInfo, pkg, permissionInfo); + addExtraAppOp(packageInfo, pkg, permissionInfo); } private void addPermissionAppOp(@NonNull PackageInfo packageInfo, - @NonNull PermissionInfo permissionInfo) { + @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) { if (!permissionInfo.isRuntime()) { return; } @@ -539,13 +540,13 @@ public final class PermissionPolicyService extends SystemService { } int appOpMode; - boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, permissionInfo); + boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, pkg, permissionInfo); if (shouldGrantAppOp) { if (permissionInfo.backgroundPermission != null) { PermissionInfo backgroundPermissionInfo = mRuntimePermissionInfos.get( permissionInfo.backgroundPermission); boolean shouldGrantBackgroundAppOp = backgroundPermissionInfo != null - && shouldGrantAppOp(packageInfo, backgroundPermissionInfo); + && shouldGrantAppOp(packageInfo, pkg, backgroundPermissionInfo); appOpMode = shouldGrantBackgroundAppOp ? MODE_ALLOWED : MODE_FOREGROUND; } else { appOpMode = MODE_ALLOWED; @@ -570,7 +571,7 @@ public final class PermissionPolicyService extends SystemService { } private boolean shouldGrantAppOp(@NonNull PackageInfo packageInfo, - @NonNull PermissionInfo permissionInfo) { + @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) { String permissionName = permissionInfo.name; String packageName = packageInfo.packageName; boolean isGranted = mPackageManager.checkPermission(permissionName, packageName) @@ -595,14 +596,15 @@ public final class PermissionPolicyService extends SystemService { } else if (permissionInfo.isSoftRestricted()) { SoftRestrictedPermissionPolicy policy = SoftRestrictedPermissionPolicy.forPermission(mContext, - packageInfo.applicationInfo, mContext.getUser(), permissionName); + packageInfo.applicationInfo, pkg, mContext.getUser(), + permissionName); return policy.mayGrantPermission(); } else { return true; } } - private void addExtraAppOp(@NonNull PackageInfo packageInfo, + private void addExtraAppOp(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) { if (!permissionInfo.isSoftRestricted()) { return; @@ -611,7 +613,7 @@ public final class PermissionPolicyService extends SystemService { String permissionName = permissionInfo.name; SoftRestrictedPermissionPolicy policy = SoftRestrictedPermissionPolicy.forPermission(mContext, - packageInfo.applicationInfo, mContext.getUser(), permissionName); + packageInfo.applicationInfo, pkg, mContext.getUser(), permissionName); int extraOpCode = policy.getExtraAppOpCode(); if (extraOpCode == OP_NONE) { return; @@ -639,19 +641,23 @@ public final class PermissionPolicyService extends SystemService { * @param pkgName The package to add for later processing. */ void addPackage(@NonNull String pkgName) { - final PackageInfo pkg; + PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); + final PackageInfo pkgInfo; + final AndroidPackage pkg; try { - pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS); + pkgInfo = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS); + pkg = pmInternal.getPackage(pkgName); } catch (NameNotFoundException e) { return; } - if (pkg.requestedPermissions == null) { + if (pkgInfo == null || pkg == null || pkgInfo.requestedPermissions == null) { return; } - for (String permission : pkg.requestedPermissions) { - addAppOps(pkg, permission); + for (String permission : pkgInfo.requestedPermissions) { + addAppOps(pkgInfo, pkg, permission); } } diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java index 740472e6b211..90babcd2a100 100644 --- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java +++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java @@ -35,7 +35,6 @@ import android.compat.annotation.EnabledAfter; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -46,6 +45,7 @@ import android.util.Log; import com.android.internal.compat.IPlatformCompat; import com.android.server.LocalServices; +import com.android.server.pm.parsing.pkg.AndroidPackage; /** * The behavior of soft restricted permissions is different for each permission. This class collects @@ -100,8 +100,8 @@ public abstract class SoftRestrictedPermissionPolicy { * @return The policy for this permission */ public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context, - @Nullable ApplicationInfo appInfo, @Nullable UserHandle user, - @NonNull String permission) { + @Nullable ApplicationInfo appInfo, @Nullable AndroidPackage pkg, + @Nullable UserHandle user, @NonNull String permission) { switch (permission) { // Storage uses a special app op to decide the mount state and supports soft restriction // where the restricted state allows the permission but only for accessing the medial @@ -116,8 +116,6 @@ public abstract class SoftRestrictedPermissionPolicy { if (appInfo != null) { PackageManager pm = context.getPackageManager(); - PackageManagerInternal pmInternal = - LocalServices.getService(PackageManagerInternal.class); StorageManagerInternal smInternal = LocalServices.getService(StorageManagerInternal.class); int flags = pm.getPermissionFlags(permission, appInfo.packageName, user); @@ -131,8 +129,7 @@ public abstract class SoftRestrictedPermissionPolicy { isScopedStorageEnabled = isChangeEnabledForUid(context, appInfo, user, ENABLE_SCOPED_STORAGE) || isScopedStorageRequired; - shouldPreserveLegacyExternalStorage = pmInternal.getPackage( - appInfo.packageName).hasPreserveLegacyExternalStorage() + shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage() && smInternal.hasLegacyExternalStorage(appInfo.uid); shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0 || (isScopedStorageRequired && !shouldPreserveLegacyExternalStorage); diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java index 9f4ca3c6c4ea..97ce6bd7f369 100644 --- a/services/core/java/com/android/server/role/RoleUserState.java +++ b/services/core/java/com/android/server/role/RoleUserState.java @@ -364,12 +364,12 @@ public class RoleUserState { (Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked()); } - mPersistence.write(roles, UserHandle.of(mUserId)); + mPersistence.writeAsUser(roles, UserHandle.of(mUserId)); } private void readFile() { synchronized (mLock) { - RolesState roles = mPersistence.read(UserHandle.of(mUserId)); + RolesState roles = mPersistence.readAsUser(UserHandle.of(mUserId)); if (roles == null) { readLegacyFileLocked(); scheduleWriteFileLocked(); @@ -545,7 +545,7 @@ public class RoleUserState { throw new IllegalStateException("This RoleUserState has already been destroyed"); } mWriteHandler.removeCallbacksAndMessages(null); - mPersistence.delete(UserHandle.of(mUserId)); + mPersistence.deleteAsUser(UserHandle.of(mUserId)); mDestroyed = true; } } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java new file mode 100644 index 000000000000..870d909fbbcc --- /dev/null +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.soundtrigger_middleware; + +import android.hardware.soundtrigger.V2_1.ISoundTriggerHw; +import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback; +import android.hardware.soundtrigger.V2_3.ModelParameterRange; +import android.hardware.soundtrigger.V2_3.Properties; +import android.hardware.soundtrigger.V2_3.RecognitionConfig; +import android.os.IHwBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.HashMap; +import java.util.Map; + +/** + * A decorator around a HAL, which adds some checks that the HAL is behaving as expected. + * This is not necessarily a strict enforcement for the HAL contract, but a place to add checks for + * common HAL malfunctions, to help track them and assist in debugging. + * + * The class is not thread-safe. + */ +public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { + static final String TAG = "SoundTriggerHw2Enforcer"; + + final ISoundTriggerHw2 mUnderlying; + Map<Integer, Boolean> mModelStates = new HashMap<>(); + + public SoundTriggerHw2Enforcer( + ISoundTriggerHw2 underlying) { + mUnderlying = underlying; + } + + @Override + public Properties getProperties() { + return mUnderlying.getProperties(); + } + + @Override + public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, Callback callback, + int cookie) { + int handle = mUnderlying.loadSoundModel(soundModel, new CallbackEnforcer(callback), cookie); + mModelStates.put(handle, false); + return handle; + } + + @Override + public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, Callback callback, + int cookie) { + int handle = mUnderlying.loadPhraseSoundModel(soundModel, new CallbackEnforcer(callback), + cookie); + mModelStates.put(handle, false); + return handle; + } + + @Override + public void unloadSoundModel(int modelHandle) { + mUnderlying.unloadSoundModel(modelHandle); + mModelStates.remove(modelHandle); + } + + @Override + public void stopRecognition(int modelHandle) { + mUnderlying.stopRecognition(modelHandle); + mModelStates.replace(modelHandle, false); + } + + @Override + public void stopAllRecognitions() { + mUnderlying.stopAllRecognitions(); + for (Map.Entry<Integer, Boolean> entry : mModelStates.entrySet()) { + entry.setValue(false); + } + } + + @Override + public void startRecognition(int modelHandle, RecognitionConfig config, Callback callback, + int cookie) { + mUnderlying.startRecognition(modelHandle, config, new CallbackEnforcer(callback), cookie); + mModelStates.replace(modelHandle, true); + } + + @Override + public void getModelState(int modelHandle) { + mUnderlying.getModelState(modelHandle); + } + + @Override + public int getModelParameter(int modelHandle, int param) { + return mUnderlying.getModelParameter(modelHandle, param); + } + + @Override + public void setModelParameter(int modelHandle, int param, int value) { + mUnderlying.setModelParameter(modelHandle, param, value); + } + + @Override + public ModelParameterRange queryParameter(int modelHandle, int param) { + return mUnderlying.queryParameter(modelHandle, param); + } + + @Override + public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) { + return mUnderlying.linkToDeath(recipient, cookie); + } + + @Override + public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) { + return mUnderlying.unlinkToDeath(recipient); + } + + @Override + public String interfaceDescriptor() throws RemoteException { + return mUnderlying.interfaceDescriptor(); + } + + private class CallbackEnforcer implements Callback { + private final Callback mUnderlying; + + private CallbackEnforcer( + Callback underlying) { + mUnderlying = underlying; + } + + @Override + public void recognitionCallback(ISoundTriggerHwCallback.RecognitionEvent event, + int cookie) { + int model = event.header.model; + if (!mModelStates.getOrDefault(model, false)) { + Log.wtfStack(TAG, "Unexpected recognition event for model: " + model); + } + if (event.header.status + != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) { + mModelStates.replace(model, false); + } + mUnderlying.recognitionCallback(event, cookie); + } + + @Override + public void phraseRecognitionCallback(ISoundTriggerHwCallback.PhraseRecognitionEvent event, + int cookie) { + int model = event.common.header.model; + if (!mModelStates.getOrDefault(model, false)) { + Log.wtfStack(TAG, "Unexpected recognition event for model: " + model); + } + if (event.common.header.status + != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) { + mModelStates.replace(model, false); + } + mUnderlying.phraseRecognitionCallback(event, cookie); + } + } +} diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java index cd5e360acd1f..aa1558ebfc70 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java @@ -191,7 +191,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { * Attached to the HAL service via factory. */ private void attachToHal() { - mHalService = new SoundTriggerHw2Compat(mHalFactory.create()); + mHalService = new SoundTriggerHw2Enforcer(new SoundTriggerHw2Compat(mHalFactory.create())); mHalService.linkToDeath(this, 0); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index e443fe42a82e..f02a9dd61107 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -131,7 +131,6 @@ import android.graphics.Rect; import android.graphics.Region; import android.hardware.input.InputManager; import android.hardware.power.V1_0.PowerHint; -import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -304,6 +303,8 @@ public class DisplayPolicy { private boolean mIsFreeformWindowOverlappingWithNavBar; + private boolean mLastImmersiveMode; + private final StatusBarController mStatusBarController; private final BarController mNavigationBarController; @@ -3182,8 +3183,8 @@ public class DisplayPolicy { if (nb) mNavigationBarController.showTransient(); updateSystemUiVisibilityLw(); } - mImmersiveModeConfirmation.confirmCurrentPrompt(); } + mImmersiveModeConfirmation.confirmCurrentPrompt(); } } @@ -3210,7 +3211,7 @@ public class DisplayPolicy { updateSystemUiVisibilityLw(); } - private int updateSystemUiVisibilityLw() { + int updateSystemUiVisibilityLw() { // If there is no window focused, there will be nobody to handle the events // anyway, so just hang on in whatever state we're in until things settle down. WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow @@ -3566,9 +3567,11 @@ public class DisplayPolicy { vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis); // update navigation bar - boolean oldImmersiveMode = isImmersiveMode(oldVis); - boolean newImmersiveMode = isImmersiveMode(vis); + boolean newInsetsMode = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL; + boolean oldImmersiveMode = newInsetsMode ? mLastImmersiveMode : isImmersiveMode(oldVis); + boolean newImmersiveMode = newInsetsMode ? isImmersiveMode(win) : isImmersiveMode(vis); if (oldImmersiveMode != newImmersiveMode) { + mLastImmersiveMode = newImmersiveMode; final String pkg = win.getOwningPackage(); mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode, mService.mPolicy.isUserSetupComplete(), @@ -3673,6 +3676,7 @@ public class DisplayPolicy { } } + // TODO(b/118118435): Remove this after migration private boolean isImmersiveMode(int vis) { final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; return mNavigationBar != null @@ -3681,6 +3685,16 @@ public class DisplayPolicy { && canHideNavigationBar(); } + private boolean isImmersiveMode(WindowState win) { + final int behavior = win.mAttrs.insetsFlags.behavior; + return mNavigationBar != null + && canHideNavigationBar() + && (behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE + || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) + && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR) + && win != getNotificationShade(); + } + /** * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar */ diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index a8fe34953cee..b3890cd84196 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -182,6 +182,7 @@ class InsetsStateController { } if (changed) { notifyInsetsChanged(); + mDisplayContent.getDisplayPolicy().updateSystemUiVisibilityLw(); } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index c7f2cc7f3692..5554b1d62405 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -422,6 +422,8 @@ class Task extends WindowContainer<WindowContainer> { /** When set, will force the task to report as invisible. */ boolean mForceHidden = false; + SurfaceControl.Transaction mMainWindowSizeChangeTransaction; + private final FindRootHelper mFindRootHelper = new FindRootHelper(); private class FindRootHelper { private ActivityRecord mRoot; @@ -3979,4 +3981,17 @@ class Task extends WindowContainer<WindowContainer> { mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged( this, true /* force */); } + + /** + * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this + * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy + * to resize, and it will defer the transaction until that resize frame completes. + */ + void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) { + mMainWindowSizeChangeTransaction = t; + } + + SurfaceControl.Transaction getMainWindowSizeChangeTransaction() { + return mMainWindowSizeChangeTransaction; + } } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 4d5621cd5b32..202e089eea3b 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -557,6 +557,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub WindowContainerTransaction.Change c) { int effects = sanitizeAndApplyChange(wc, c); + final SurfaceControl.Transaction t = c.getBoundsChangeTransaction(); + if (t != null) { + Task tr = (Task) wc; + tr.setMainWindowSizeChangeTransaction(t); + } + Rect enterPipBounds = c.getEnterPipBounds(); if (enterPipBounds != null) { Task tr = (Task) wc; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 9552df7b5899..a1a9af680e92 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -873,6 +873,14 @@ class WindowStateAnimator { clipRect = mTmpClipRect; } + if (mSurfaceResized && (mAttrType == TYPE_BASE_APPLICATION) && + (task != null) && (task.getMainWindowSizeChangeTransaction() != null)) { + mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(), + mWin.getFrameNumber()); + SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction()); + task.setMainWindowSizeChangeTransaction(null); + } + float surfaceWidth = mSurfaceController.getWidth(); float surfaceHeight = mSurfaceController.getHeight(); diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index e1615afa8db3..336934e5fb03 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -55,10 +55,9 @@ static jclass class_location; static jclass class_gnssNavigationMessage; static jclass class_gnssClock; static jclass class_gnssConfiguration_halInterfaceVersion; -static jclass class_gnssAntennaInfo; -static jclass class_phaseCenterOffsetCoordinates; -static jclass class_phaseCenterVariationCorrections; -static jclass class_signalGainCorrections; +static jclass class_gnssAntennaInfoBuilder; +static jclass class_phaseCenterOffset; +static jclass class_sphericalCorrections; static jclass class_arrayList; static jclass class_doubleArray; @@ -122,12 +121,16 @@ static jmethodID method_gnssNavigationMessageCtor; static jmethodID method_gnssClockCtor; static jmethodID method_gnssMeasurementCtor; static jmethodID method_halInterfaceVersionCtor; -static jmethodID method_gnssAntennaInfoCtor; -static jmethodID method_phaseCenterOffsetCoordinatesCtor; -static jmethodID method_phaseCenterVariationCorrectionsCtor; -static jmethodID method_signalGainCorrectionsCtor; +static jmethodID method_gnssAntennaInfoBuilderCtor; +static jmethodID method_phaseCenterOffsetCtor; +static jmethodID method_sphericalCorrectionsCtor; static jmethodID method_arrayListCtor; static jmethodID method_arrayListAdd; +static jmethodID method_gnssAntennaInfoBuilderSetCarrierFrequencyMHz; +static jmethodID method_gnssAntennaInfoBuilderSetPhaseCenterOffset; +static jmethodID method_gnssAntennaInfoBuilderSetPhaseCenterVariationCorrections; +static jmethodID method_gnssAntennaInfoBuilderSetSignalGainCorrections; +static jmethodID method_gnssAntennaInfoBuilderBuild; /* * Save a pointer to JavaVm to attach/detach threads executing @@ -163,7 +166,10 @@ using android::hardware::gnss::V2_0::ElapsedRealtimeFlags; using MeasurementCorrections_V1_0 = android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections; using MeasurementCorrections_V1_1 = android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections; -using android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection; +using SingleSatCorrection_V1_0 = + android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection; +using SingleSatCorrection_V1_1 = + android::hardware::gnss::measurement_corrections::V1_1::SingleSatCorrection; using android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane; using android::hidl::base::V1_0::IBase; @@ -1088,7 +1094,7 @@ private: const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos); jobject translateSingleGnssAntennaInfo( JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo); - jobject translatePhaseCenterOffsetCoordinates( + jobject translatePhaseCenterOffset( JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo); jobject translatePhaseCenterVariationCorrections( JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo); @@ -1150,11 +1156,10 @@ jobject GnssAntennaInfoCallback::translateAllGnssAntennaInfos( return arrayList; } -jobject GnssAntennaInfoCallback::translatePhaseCenterOffsetCoordinates( +jobject GnssAntennaInfoCallback::translatePhaseCenterOffset( JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo) { - jobject phaseCenterOffsetCoordinates = - env->NewObject(class_phaseCenterOffsetCoordinates, - method_phaseCenterOffsetCoordinatesCtor, + jobject phaseCenterOffset = + env->NewObject(class_phaseCenterOffset, method_phaseCenterOffsetCtor, gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.x, gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.xUncertainty, gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.y, @@ -1162,7 +1167,7 @@ jobject GnssAntennaInfoCallback::translatePhaseCenterOffsetCoordinates( gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.z, gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.zUncertainty); - return phaseCenterOffsetCoordinates; + return phaseCenterOffset; } jobject GnssAntennaInfoCallback::translatePhaseCenterVariationCorrections( @@ -1185,8 +1190,7 @@ jobject GnssAntennaInfoCallback::translatePhaseCenterVariationCorrections( } jobject phaseCenterVariationCorrections = - env->NewObject(class_phaseCenterVariationCorrections, - method_phaseCenterVariationCorrectionsCtor, + env->NewObject(class_sphericalCorrections, method_sphericalCorrectionsCtor, phaseCenterVariationCorrectionsArray, phaseCenterVariationCorrectionsUncertaintiesArray); @@ -1212,7 +1216,7 @@ jobject GnssAntennaInfoCallback::translateSignalGainCorrections( } jobject signalGainCorrections = - env->NewObject(class_signalGainCorrections, method_signalGainCorrectionsCtor, + env->NewObject(class_sphericalCorrections, method_sphericalCorrectionsCtor, signalGainCorrectionsArray, signalGainCorrectionsUncertaintiesArray); env->DeleteLocalRef(signalGainCorrectionsArray); @@ -1223,8 +1227,7 @@ jobject GnssAntennaInfoCallback::translateSignalGainCorrections( jobject GnssAntennaInfoCallback::translateSingleGnssAntennaInfo( JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo) { - jobject phaseCenterOffsetCoordinates = - translatePhaseCenterOffsetCoordinates(env, gnssAntennaInfo); + jobject phaseCenterOffset = translatePhaseCenterOffset(env, gnssAntennaInfo); // Nullable jobject phaseCenterVariationCorrections = @@ -1233,13 +1236,29 @@ jobject GnssAntennaInfoCallback::translateSingleGnssAntennaInfo( // Nullable jobject signalGainCorrections = translateSignalGainCorrections(env, gnssAntennaInfo); + // Get builder + jobject gnssAntennaInfoBuilderObject = + env->NewObject(class_gnssAntennaInfoBuilder, method_gnssAntennaInfoBuilderCtor); + + // Set fields + env->CallObjectMethod(gnssAntennaInfoBuilderObject, + method_gnssAntennaInfoBuilderSetCarrierFrequencyMHz, + gnssAntennaInfo.carrierFrequencyMHz); + env->CallObjectMethod(gnssAntennaInfoBuilderObject, + method_gnssAntennaInfoBuilderSetPhaseCenterOffset, phaseCenterOffset); + env->CallObjectMethod(gnssAntennaInfoBuilderObject, + method_gnssAntennaInfoBuilderSetPhaseCenterVariationCorrections, + phaseCenterVariationCorrections); + env->CallObjectMethod(gnssAntennaInfoBuilderObject, + method_gnssAntennaInfoBuilderSetSignalGainCorrections, + signalGainCorrections); + + // build jobject gnssAntennaInfoObject = - env->NewObject(class_gnssAntennaInfo, method_gnssAntennaInfoCtor, - gnssAntennaInfo.carrierFrequencyMHz, phaseCenterOffsetCoordinates, - phaseCenterVariationCorrections, signalGainCorrections); + env->CallObjectMethod(gnssAntennaInfoBuilderObject, method_gnssAntennaInfoBuilderBuild); // Delete Local Refs - env->DeleteLocalRef(phaseCenterOffsetCoordinates); + env->DeleteLocalRef(phaseCenterOffset); env->DeleteLocalRef(phaseCenterVariationCorrections); env->DeleteLocalRef(signalGainCorrections); @@ -2004,35 +2023,38 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, class_gnssMeasurement = (jclass) env->NewGlobalRef(gnssMeasurementClass); method_gnssMeasurementCtor = env->GetMethodID(class_gnssMeasurement, "<init>", "()V"); - jclass gnssAntennaInfoClass = env->FindClass("android/location/GnssAntennaInfo"); - class_gnssAntennaInfo = (jclass)env->NewGlobalRef(gnssAntennaInfoClass); - method_gnssAntennaInfoCtor = - env->GetMethodID(class_gnssAntennaInfo, "<init>", - "(D" - "Landroid/location/GnssAntennaInfo$PhaseCenterOffsetCoordinates;" - "Landroid/location/GnssAntennaInfo$PhaseCenterVariationCorrections;" - "Landroid/location/GnssAntennaInfo$SignalGainCorrections;" - ")V"); - - jclass phaseCenterOffsetCoordinatesClass = - env->FindClass("android/location/GnssAntennaInfo$PhaseCenterOffsetCoordinates"); - class_phaseCenterOffsetCoordinates = - (jclass)env->NewGlobalRef(phaseCenterOffsetCoordinatesClass); - method_phaseCenterOffsetCoordinatesCtor = - env->GetMethodID(class_phaseCenterOffsetCoordinates, "<init>", "(DDDDDD)V"); - - jclass phaseCenterVariationCorrectionsClass = - env->FindClass("android/location/GnssAntennaInfo$PhaseCenterVariationCorrections"); - class_phaseCenterVariationCorrections = - (jclass)env->NewGlobalRef(phaseCenterVariationCorrectionsClass); - method_phaseCenterVariationCorrectionsCtor = - env->GetMethodID(class_phaseCenterVariationCorrections, "<init>", "([[D[[D)V"); - - jclass signalGainCorrectionsClass = - env->FindClass("android/location/GnssAntennaInfo$SignalGainCorrections"); - class_signalGainCorrections = (jclass)env->NewGlobalRef(signalGainCorrectionsClass); - method_signalGainCorrectionsCtor = - env->GetMethodID(class_signalGainCorrections, "<init>", "([[D[[D)V"); + jclass gnssAntennaInfoBuilder = env->FindClass("android/location/GnssAntennaInfo$Builder"); + class_gnssAntennaInfoBuilder = (jclass)env->NewGlobalRef(gnssAntennaInfoBuilder); + method_gnssAntennaInfoBuilderCtor = + env->GetMethodID(class_gnssAntennaInfoBuilder, "<init>", "()V"); + method_gnssAntennaInfoBuilderSetCarrierFrequencyMHz = + env->GetMethodID(class_gnssAntennaInfoBuilder, "setCarrierFrequencyMHz", + "(D)Landroid/location/GnssAntennaInfo$Builder;"); + method_gnssAntennaInfoBuilderSetPhaseCenterOffset = + env->GetMethodID(class_gnssAntennaInfoBuilder, "setPhaseCenterOffset", + "(Landroid/location/GnssAntennaInfo$PhaseCenterOffset;)" + "Landroid/location/GnssAntennaInfo$Builder;"); + method_gnssAntennaInfoBuilderSetPhaseCenterVariationCorrections = + env->GetMethodID(class_gnssAntennaInfoBuilder, "setPhaseCenterVariationCorrections", + "(Landroid/location/GnssAntennaInfo$SphericalCorrections;)" + "Landroid/location/GnssAntennaInfo$Builder;"); + method_gnssAntennaInfoBuilderSetSignalGainCorrections = + env->GetMethodID(class_gnssAntennaInfoBuilder, "setSignalGainCorrections", + "(Landroid/location/GnssAntennaInfo$SphericalCorrections;)" + "Landroid/location/GnssAntennaInfo$Builder;"); + method_gnssAntennaInfoBuilderBuild = env->GetMethodID(class_gnssAntennaInfoBuilder, "build", + "()Landroid/location/GnssAntennaInfo;"); + + jclass phaseCenterOffsetClass = + env->FindClass("android/location/GnssAntennaInfo$PhaseCenterOffset"); + class_phaseCenterOffset = (jclass)env->NewGlobalRef(phaseCenterOffsetClass); + method_phaseCenterOffsetCtor = env->GetMethodID(class_phaseCenterOffset, "<init>", "(DDDDDD)V"); + + jclass sphericalCorrectionsClass = + env->FindClass("android/location/GnssAntennaInfo$SphericalCorrections"); + class_sphericalCorrections = (jclass)env->NewGlobalRef(sphericalCorrectionsClass); + method_sphericalCorrectionsCtor = + env->GetMethodID(class_sphericalCorrections, "<init>", "([[D[[D)V"); jclass locationClass = env->FindClass("android/location/Location"); class_location = (jclass) env->NewGlobalRef(locationClass); @@ -3105,6 +3127,91 @@ static jboolean return JNI_FALSE; } +static SingleSatCorrection_V1_0 getSingleSatCorrection_1_0_withoutConstellation( + JNIEnv* env, jobject singleSatCorrectionObj) { + jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags); + jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId); + jfloat carrierFreqHz = + env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq); + jfloat probSatIsLos = + env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb); + jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl); + jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc); + uint16_t corrFlags = static_cast<uint16_t>(correctionFlags); + jobject reflectingPlaneObj; + bool has_ref_plane = (corrFlags & GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE) != 0; + if (has_ref_plane) { + reflectingPlaneObj = + env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane); + } + + ReflectingPlane reflectingPlane; + if (has_ref_plane) { + jdouble latitudeDegreesRefPlane = + env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg); + jdouble longitudeDegreesRefPlane = + env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLngDeg); + jdouble altitudeDegreesRefPlane = + env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAltDeg); + jdouble azimuthDegreeRefPlane = + env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAzimDeg); + reflectingPlane = { + .latitudeDegrees = latitudeDegreesRefPlane, + .longitudeDegrees = longitudeDegreesRefPlane, + .altitudeMeters = altitudeDegreesRefPlane, + .azimuthDegrees = azimuthDegreeRefPlane, + }; + } + + SingleSatCorrection_V1_0 singleSatCorrection = { + .singleSatCorrectionFlags = corrFlags, + .svid = static_cast<uint16_t>(satId), + .carrierFrequencyHz = carrierFreqHz, + .probSatIsLos = probSatIsLos, + .excessPathLengthMeters = eplMeters, + .excessPathLengthUncertaintyMeters = eplUncMeters, + .reflectingPlane = reflectingPlane, + }; + + return singleSatCorrection; +} + +static void getSingleSatCorrectionList_1_1(JNIEnv* env, jobject singleSatCorrectionList, + hidl_vec<SingleSatCorrection_V1_1>& list) { + for (uint16_t i = 0; i < list.size(); ++i) { + jobject singleSatCorrectionObj = + env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i); + + SingleSatCorrection_V1_0 singleSatCorrection_1_0 = + getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj); + + jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType); + + SingleSatCorrection_V1_1 singleSatCorrection_1_1 = { + .v1_0 = singleSatCorrection_1_0, + .constellation = static_cast<GnssConstellationType_V2_0>(constType), + }; + + list[i] = singleSatCorrection_1_1; + } +} + +static void getSingleSatCorrectionList_1_0(JNIEnv* env, jobject singleSatCorrectionList, + hidl_vec<SingleSatCorrection_V1_0>& list) { + for (uint16_t i = 0; i < list.size(); ++i) { + jobject singleSatCorrectionObj = + env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i); + + SingleSatCorrection_V1_0 singleSatCorrection = + getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj); + + jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType); + + singleSatCorrection.constellation = static_cast<GnssConstellationType_V1_0>(constType), + + list[i] = singleSatCorrection; + } +} static jboolean android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections( JNIEnv* env, @@ -3127,64 +3234,6 @@ static jboolean ALOGI("Empty correction list injected....Returning with no HAL injection"); return JNI_TRUE; } - hidl_vec<SingleSatCorrection> list(len); - - for (uint16_t i = 0; i < len; ++i) { - jobject singleSatCorrectionObj = env->CallObjectMethod( - singleSatCorrectionList, method_correctionListGet, i); - - jint correctionFlags = - env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags); - jint constType = env->CallIntMethod(singleSatCorrectionObj, - method_correctionSatConstType); - jint satId = - env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId); - jfloat carrierFreqHz = env->CallFloatMethod( - singleSatCorrectionObj, method_correctionSatCarrierFreq); - jfloat probSatIsLos = env->CallFloatMethod(singleSatCorrectionObj, - method_correctionSatIsLosProb); - jfloat eplMeters = - env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl); - jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, - method_correctionSatEplUnc); - uint16_t corrFlags = static_cast<uint16_t>(correctionFlags); - jobject reflectingPlaneObj; - bool has_ref_plane = (corrFlags & GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE) != 0; - if (has_ref_plane) { - reflectingPlaneObj = env->CallObjectMethod( - singleSatCorrectionObj, method_correctionSatRefPlane); - } - - ReflectingPlane reflectingPlane; - if (has_ref_plane) { - jdouble latitudeDegreesRefPlane = env->CallDoubleMethod( - reflectingPlaneObj, method_correctionPlaneLatDeg); - jdouble longitudeDegreesRefPlane = env->CallDoubleMethod( - reflectingPlaneObj, method_correctionPlaneLngDeg); - jdouble altitudeDegreesRefPlane = env->CallDoubleMethod( - reflectingPlaneObj, method_correctionPlaneAltDeg); - jdouble azimuthDegreeRefPlane = env->CallDoubleMethod( - reflectingPlaneObj, method_correctionPlaneAzimDeg); - reflectingPlane = { - .latitudeDegrees = latitudeDegreesRefPlane, - .longitudeDegrees = longitudeDegreesRefPlane, - .altitudeMeters = altitudeDegreesRefPlane, - .azimuthDegrees = azimuthDegreeRefPlane, - }; - } - - SingleSatCorrection singleSatCorrection = { - .singleSatCorrectionFlags = corrFlags, - .constellation = static_cast<GnssConstellationType_V1_0>(constType), - .svid = static_cast<uint16_t>(satId), - .carrierFrequencyHz = carrierFreqHz, - .probSatIsLos = probSatIsLos, - .excessPathLengthMeters = eplMeters, - .excessPathLengthUncertaintyMeters = eplUncMeters, - .reflectingPlane = reflectingPlane, - }; - list[i] = singleSatCorrection; - } jdouble latitudeDegreesCorr = env->CallDoubleMethod( correctionsObj, method_correctionsGetLatitudeDegrees); @@ -3206,7 +3255,6 @@ static jboolean .horizontalPositionUncertaintyMeters = horizontalPositionUncertaintyMeters, .verticalPositionUncertaintyMeters = verticalPositionUncertaintyMeters, .toaGpsNanosecondsOfWeek = static_cast<uint64_t>(toaGpsNanosOfWeek), - .satCorrections = list, }; if (gnssCorrectionsIface_V1_1 != nullptr) { @@ -3218,17 +3266,25 @@ static jboolean jfloat environmentBearingUncertaintyDegreesCorr = env->CallFloatMethod( correctionsObj, method_correctionsGetEnvironmentBearingUncertaintyDegrees); + hidl_vec<SingleSatCorrection_V1_1> list(len); + getSingleSatCorrectionList_1_1(env, singleSatCorrectionList, list); + MeasurementCorrections_V1_1 measurementCorrections_1_1 = { - .v1_0 = measurementCorrections_1_0, - .hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr), - .environmentBearingDegrees = environmentBearingDegreesCorr, - .environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr, + .v1_0 = measurementCorrections_1_0, + .hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr), + .environmentBearingDegrees = environmentBearingDegreesCorr, + .environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr, + .satCorrections = list, }; auto result = gnssCorrectionsIface_V1_1->setCorrections_1_1(measurementCorrections_1_1); return checkHidlReturn(result, "IMeasurementCorrections 1.1 setCorrections() failed."); } + hidl_vec<SingleSatCorrection_V1_0> list(len); + getSingleSatCorrectionList_1_0(env, singleSatCorrectionList, list); + measurementCorrections_1_0.satCorrections = list; + auto result = gnssCorrectionsIface_V1_0->setCorrections(measurementCorrections_1_0); return checkHidlReturn(result, "IMeasurementCorrections 1.0 setCorrections() failed."); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index 9b85a7b55c94..eff222a2051a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -82,4 +82,8 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public long getManagedProfileMaximumTimeOff(ComponentName admin) { return 0; } + + public boolean canProfileOwnerResetPasswordWhenLocked(int userId) { + return false; + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index cfe52e9994e4..012fdfc5bbd0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -48,6 +48,7 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_ import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING; import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS; import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT; +import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER; import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO; import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI; import static android.app.admin.DevicePolicyManager.ID_TYPE_INDIVIDUAL_ATTESTATION; @@ -179,7 +180,6 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.StringParceledListSlice; import android.content.pm.UserInfo; -import android.content.pm.parsing.AndroidPackage; import android.content.res.Resources; import android.database.ContentObserver; import android.database.Cursor; @@ -289,6 +289,7 @@ import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.Tr import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.UserRestrictionsUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; @@ -447,7 +448,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * System property whose value is either "true" or "false", indicating whether * device owner is present. */ - private static final String PROPERTY_DEVICE_OWNER_PRESENT = "ro.device_owner"; + private static final String PROPERTY_DEVICE_OWNER_PRESENT = "ro.organization_owned"; private static final int STATUS_BAR_DISABLE_MASK = StatusBarManager.DISABLE_EXPAND | @@ -1072,7 +1073,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps"; private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile-max-time-off"; private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline"; - + private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package"; + private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown"; DeviceAdminInfo info; @@ -1201,6 +1203,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Time by which the profile should be turned on according to System.currentTimeMillis(). long mProfileOffDeadline = 0; + public String mAlwaysOnVpnPackage; + public boolean mAlwaysOnVpnLockdown; + ActiveAdmin(DeviceAdminInfo _info, boolean parent) { info = _info; @@ -1441,6 +1446,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (mProfileMaximumTimeOff != 0) { writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline); } + if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) { + writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_PACKAGE, mAlwaysOnVpnPackage); + } + if (mAlwaysOnVpnLockdown) { + writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown); + } } void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException { @@ -1686,6 +1697,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) { mProfileOffDeadline = Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) { + mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE); + } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) { + mAlwaysOnVpnLockdown = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); } else { Slog.w(LOG_TAG, "Unknown admin tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -1918,6 +1934,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { pw.println(mProfileMaximumTimeOff); pw.print("mProfileOffDeadline="); pw.println(mProfileOffDeadline); + pw.print("mAlwaysOnVpnPackage="); + pw.println(mAlwaysOnVpnPackage); + pw.print("mAlwaysOnVpnLockdown="); + pw.println(mAlwaysOnVpnLockdown); } } @@ -2290,6 +2310,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { context, requestCode, intent, flags, options, user); } + PendingIntent pendingIntentGetBroadcast( + Context context, int requestCode, Intent intent, int flags) { + return PendingIntent.getBroadcast(context, requestCode, intent, flags); + } + void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer, int userHandle) { mContext.getContentResolver().registerContentObserver(uri, notifyForDescendents, @@ -2748,11 +2773,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } if (!mInjector.systemPropertiesGet(PROPERTY_DEVICE_OWNER_PRESENT, "").isEmpty()) { - Slog.w(LOG_TAG, "Trying to set ro.device_owner, but it has already been set?"); + Slog.w(LOG_TAG, "Trying to set ro.organization_owned, but it has already been set?"); } else { final String value = Boolean.toString(hasDeviceOwner); mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, value); - Slog.i(LOG_TAG, "Set ro.device_owner property to " + value); + Slog.i(LOG_TAG, "Set ro.organization_owned property to " + value); } } @@ -6775,10 +6800,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * @throws UnsupportedOperationException if the package does not support being set as always-on. */ @Override - public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown, + public boolean setAlwaysOnVpnPackage(ComponentName who, String vpnPackage, boolean lockdown, List<String> lockdownWhitelist) throws SecurityException { - enforceProfileOrDeviceOwner(admin); + enforceProfileOrDeviceOwner(who); final int userId = mInjector.userHandleGetCallingUserId(); mInjector.binderWithCleanCallingIdentity(() -> { @@ -6804,12 +6829,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE) - .setAdmin(admin) + .setAdmin(who) .setStrings(vpnPackage) .setBoolean(lockdown) .setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0) .write(); }); + synchronized (getLockObject()) { + ActiveAdmin admin = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage) + || lockdown != admin.mAlwaysOnVpnLockdown) { + admin.mAlwaysOnVpnPackage = vpnPackage; + admin.mAlwaysOnVpnLockdown = lockdown; + saveSettingsLocked(userId); + } + } return true; } @@ -6823,6 +6858,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public String getAlwaysOnVpnPackageForUser(int userHandle) { + enforceSystemCaller("getAlwaysOnVpnPackageForUser"); + synchronized (getLockObject()) { + ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle); + return admin != null ? admin.mAlwaysOnVpnPackage : null; + } + } + + @Override public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException { enforceProfileOrDeviceOwner(admin); @@ -6832,6 +6876,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle) { + enforceSystemCaller("isAlwaysOnVpnLockdownEnabledForUser"); + synchronized (getLockObject()) { + ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle); + return admin != null ? admin.mAlwaysOnVpnLockdown : null; + } + } + + @Override public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin) throws SecurityException { enforceProfileOrDeviceOwner(admin); @@ -8981,6 +9034,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return null; } + /** + * Returns the ActiveAdmin associated wit the PO or DO on the given user. + * @param userHandle + * @return + */ + private @Nullable ActiveAdmin getDeviceOrProfileOwnerAdminLocked(int userHandle) { + ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle); + if (admin == null && getDeviceOwnerUserId() == userHandle) { + admin = getDeviceOwnerAdminLocked(); + } + return admin; + } + @GuardedBy("getLockObject()") ActiveAdmin getProfileOwnerOfOrganizationOwnedDeviceLocked(int userHandle) { return mInjector.binderWithCleanCallingIdentity(() -> { @@ -10040,35 +10106,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private boolean checkCallerIsCurrentUserOrProfile() { - final int callingUserId = UserHandle.getCallingUserId(); - final long token = mInjector.binderClearCallingIdentity(); - try { - UserInfo currentUser; - UserInfo callingUser = getUserInfo(callingUserId); - try { - currentUser = mInjector.getIActivityManager().getCurrentUser(); - } catch (RemoteException e) { - Slog.e(LOG_TAG, "Failed to talk to activity managed.", e); - return false; - } - - if (callingUser.isManagedProfile() && callingUser.profileGroupId != currentUser.id) { - Slog.e(LOG_TAG, "Cannot set permitted input methods for managed profile " - + "of a user that isn't the foreground user."); - return false; - } - if (!callingUser.isManagedProfile() && callingUserId != currentUser.id ) { - Slog.e(LOG_TAG, "Cannot set permitted input methods " - + "of a user that isn't the foreground user."); - return false; - } - } finally { - mInjector.binderRestoreCallingIdentity(token); - } - return true; - } - @Override public boolean setPermittedInputMethods(ComponentName who, List packageList) { if (!mHasFeature) { @@ -14517,12 +14554,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final int userHandle = mInjector.userHandleGetCallingUserId(); getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - DevicePolicyData policy = getUserData(userHandle); - if (policy.mPasswordTokenHandle != 0) { - return mInjector.binderWithCleanCallingIdentity( - () -> mLockPatternUtils.isEscrowTokenActive(policy.mPasswordTokenHandle, - userHandle)); - } + return isResetPasswordTokenActiveForUserLocked(userHandle); + } + } + + private boolean isResetPasswordTokenActiveForUserLocked(int userHandle) { + DevicePolicyData policy = getUserData(userHandle); + if (policy.mPasswordTokenHandle != 0) { + return mInjector.binderWithCleanCallingIdentity(() -> + mLockPatternUtils.isEscrowTokenActive(policy.mPasswordTokenHandle, userHandle)); } return false; } @@ -15670,8 +15710,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void updateProfileOffAlarm(long profileOffDeadline) { final AlarmManager am = mInjector.getAlarmManager(); - final PendingIntent pi = PendingIntent.getBroadcast(mContext, REQUEST_PROFILE_OFF_DEADLINE, - new Intent(ACTION_PROFILE_OFF_DEADLINE), + final PendingIntent pi = mInjector.pendingIntentGetBroadcast( + mContext, REQUEST_PROFILE_OFF_DEADLINE, new Intent(ACTION_PROFILE_OFF_DEADLINE), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); am.cancel(pi); if (profileOffDeadline != 0) { @@ -15806,4 +15846,34 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return admin.mProfileMaximumTimeOff; } } + + @Override + public boolean canProfileOwnerResetPasswordWhenLocked(int userId) { + enforceSystemCaller("call canProfileOwnerResetPasswordWhenLocked"); + synchronized (getLockObject()) { + final ActiveAdmin poAdmin = getProfileOwnerAdminLocked(userId); + if (poAdmin == null + || getEncryptionStatus() != ENCRYPTION_STATUS_ACTIVE_PER_USER + || !isResetPasswordTokenActiveForUserLocked(userId)) { + return false; + } + final ApplicationInfo poAppInfo; + try { + poAppInfo = mIPackageManager.getApplicationInfo( + poAdmin.info.getPackageName(), 0 /* flags */, userId); + } catch (RemoteException e) { + Slog.e(LOG_TAG, "Failed to query PO app info", e); + return false; + } + if (poAppInfo == null) { + Slog.wtf(LOG_TAG, "Cannot find AppInfo for profile owner"); + return false; + } + if (!poAppInfo.isEncryptionAware()) { + return false; + } + Slog.d(LOG_TAG, "PO should be able to reset password from direct boot"); + return true; + } + } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 569986c46186..b5d3d18b4350 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -44,7 +44,6 @@ import android.database.sqlite.SQLiteGlobal; import android.graphics.GraphicsStatsService; import android.hardware.display.DisplayManagerInternal; import android.net.ConnectivityModuleConnector; -import android.net.ITetheringConnector; import android.net.NetworkStackClient; import android.os.BaseBundle; import android.os.Binder; @@ -298,6 +297,9 @@ public final class SystemServer { "com.android.server.blob.BlobStoreManagerService"; private static final String APP_SEARCH_MANAGER_SERVICE_CLASS = "com.android.server.appsearch.AppSearchManagerService"; + + private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector"; + private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst"; private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file"; @@ -2331,7 +2333,7 @@ public final class SystemServer { try { // TODO: hide implementation details, b/146312721. ConnectivityModuleConnector.getInstance().startModuleService( - ITetheringConnector.class.getName(), + TETHERING_CONNECTOR_CLASS, PERMISSION_MAINLINE_NETWORK_STACK, service -> { ServiceManager.addService(Context.TETHERING_SERVICE, service, false /* allowIsolated */, diff --git a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java index 203e9804bfa3..7672cd0040ec 100644 --- a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java +++ b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java @@ -51,15 +51,18 @@ import java.util.concurrent.TimeoutException; abstract class AbstractProtoDiskReadWriter<T> { private static final String TAG = AbstractProtoDiskReadWriter.class.getSimpleName(); + + // Common disk write delay that will be appropriate for most scenarios. + private static final long DEFAULT_DISK_WRITE_DELAY = 2L * DateUtils.MINUTE_IN_MILLIS; private static final long SHUTDOWN_DISK_WRITE_TIMEOUT = 5L * DateUtils.SECOND_IN_MILLIS; private final File mRootDir; private final ScheduledExecutorService mScheduledExecutorService; - private final long mWriteDelayMs; @GuardedBy("this") private ScheduledFuture<?> mScheduledFuture; + // File name -> data class @GuardedBy("this") private Map<String, T> mScheduledFileDataMap = new ArrayMap<>(); @@ -75,15 +78,15 @@ abstract class AbstractProtoDiskReadWriter<T> { */ abstract ProtoStreamReader<T> protoStreamReader(); - AbstractProtoDiskReadWriter(@NonNull File rootDir, long writeDelayMs, + AbstractProtoDiskReadWriter(@NonNull File rootDir, @NonNull ScheduledExecutorService scheduledExecutorService) { mRootDir = rootDir; - mWriteDelayMs = writeDelayMs; mScheduledExecutorService = scheduledExecutorService; } @WorkerThread - void delete(@NonNull String fileName) { + synchronized void delete(@NonNull String fileName) { + mScheduledFileDataMap.remove(fileName); final File file = getFile(fileName); if (!file.exists()) { return; @@ -174,7 +177,7 @@ abstract class AbstractProtoDiskReadWriter<T> { } mScheduledFuture = mScheduledExecutorService.schedule(this::flushScheduledData, - mWriteDelayMs, TimeUnit.MILLISECONDS); + DEFAULT_DISK_WRITE_DELAY, TimeUnit.MILLISECONDS); } /** @@ -183,7 +186,13 @@ abstract class AbstractProtoDiskReadWriter<T> { */ @MainThread synchronized void saveImmediately(@NonNull String fileName, @NonNull T data) { - if (mScheduledExecutorService.isShutdown()) { + mScheduledFileDataMap.put(fileName, data); + triggerScheduledFlushEarly(); + } + + @MainThread + private synchronized void triggerScheduledFlushEarly() { + if (mScheduledFileDataMap.isEmpty() || mScheduledExecutorService.isShutdown()) { return; } // Cancel existing future. @@ -194,7 +203,6 @@ abstract class AbstractProtoDiskReadWriter<T> { mScheduledFuture.cancel(true); } - mScheduledFileDataMap.put(fileName, data); // Submit flush and blocks until it completes. Blocking will prevent the device from // shutting down before flushing completes. Future<?> future = mScheduledExecutorService.submit(this::flushScheduledData); @@ -212,9 +220,10 @@ abstract class AbstractProtoDiskReadWriter<T> { return; } for (String fileName : mScheduledFileDataMap.keySet()) { - T data = mScheduledFileDataMap.remove(fileName); + T data = mScheduledFileDataMap.get(fileName); writeTo(fileName, data); } + mScheduledFileDataMap.clear(); mScheduledFuture = null; } diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java index 3afb209ae5cd..62e9da83869c 100644 --- a/services/people/java/com/android/server/people/data/ConversationStore.java +++ b/services/people/java/com/android/server/people/data/ConversationStore.java @@ -23,7 +23,6 @@ import android.annotation.WorkerThread; import android.content.LocusId; import android.net.Uri; import android.text.TextUtils; -import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.Slog; import android.util.proto.ProtoInputStream; @@ -50,8 +49,6 @@ class ConversationStore { private static final String CONVERSATIONS_FILE_NAME = "conversations"; - private static final long DISK_WRITE_DELAY = 2L * DateUtils.MINUTE_IN_MILLIS; - // Shortcut ID -> Conversation Info @GuardedBy("this") private final Map<String, ConversationInfo> mConversationInfoMap = new ArrayMap<>(); @@ -92,7 +89,7 @@ class ConversationStore { */ @MainThread void loadConversationsFromDisk() { - mScheduledExecutorService.submit(() -> { + mScheduledExecutorService.execute(() -> { synchronized (this) { ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter = getConversationInfosProtoDiskReadWriter(); @@ -194,6 +191,15 @@ class ConversationStore { return getConversation(mNotifChannelIdToShortcutIdMap.get(notifChannelId)); } + synchronized void onDestroy() { + mConversationInfoMap.clear(); + mContactUriToShortcutIdMap.clear(); + mLocusIdToShortcutIdMap.clear(); + mNotifChannelIdToShortcutIdMap.clear(); + mPhoneNumberToShortcutIdMap.clear(); + mConversationInfosProtoDiskReadWriter.deleteConversationsFile(); + } + @MainThread private synchronized void updateConversationsInMemory( @NonNull ConversationInfo conversationInfo) { @@ -239,8 +245,7 @@ class ConversationStore { } if (mConversationInfosProtoDiskReadWriter == null) { mConversationInfosProtoDiskReadWriter = new ConversationInfosProtoDiskReadWriter( - mPackageDir, CONVERSATIONS_FILE_NAME, DISK_WRITE_DELAY, - mScheduledExecutorService); + mPackageDir, CONVERSATIONS_FILE_NAME, mScheduledExecutorService); } return mConversationInfosProtoDiskReadWriter; } @@ -264,16 +269,16 @@ class ConversationStore { return conversationInfo; } - /** Reads and writes {@link ConversationInfo} on disk. */ - static class ConversationInfosProtoDiskReadWriter extends + /** Reads and writes {@link ConversationInfo}s on disk. */ + private static class ConversationInfosProtoDiskReadWriter extends AbstractProtoDiskReadWriter<List<ConversationInfo>> { private final String mConversationInfoFileName; - ConversationInfosProtoDiskReadWriter(@NonNull File baseDir, + ConversationInfosProtoDiskReadWriter(@NonNull File rootDir, @NonNull String conversationInfoFileName, - long writeDelayMs, @NonNull ScheduledExecutorService scheduledExecutorService) { - super(baseDir, writeDelayMs, scheduledExecutorService); + @NonNull ScheduledExecutorService scheduledExecutorService) { + super(rootDir, scheduledExecutorService); mConversationInfoFileName = conversationInfoFileName; } @@ -328,5 +333,10 @@ class ConversationStore { void saveConversationsImmediately(@NonNull List<ConversationInfo> conversationInfos) { saveImmediately(mConversationInfoFileName, conversationInfos); } + + @WorkerThread + void deleteConversationsFile() { + delete(mConversationInfoFileName); + } } } diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java index 6b97c98b0029..7eb2176f2741 100644 --- a/services/people/java/com/android/server/people/data/DataManager.java +++ b/services/people/java/com/android/server/people/data/DataManager.java @@ -319,12 +319,11 @@ public class DataManager { } pruneUninstalledPackageData(userData); - long currentTimeMillis = System.currentTimeMillis(); userData.forAllPackages(packageData -> { if (signal.isCanceled()) { return; } - packageData.getEventStore().pruneOldEvents(currentTimeMillis); + packageData.getEventStore().pruneOldEvents(); if (!packageData.isDefaultDialer()) { packageData.getEventStore().deleteEventHistories(EventStore.CATEGORY_CALL); } diff --git a/services/people/java/com/android/server/people/data/Event.java b/services/people/java/com/android/server/people/data/Event.java index 81411c00db51..a929f6f68427 100644 --- a/services/people/java/com/android/server/people/data/Event.java +++ b/services/people/java/com/android/server/people/data/Event.java @@ -20,7 +20,13 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.text.format.DateFormat; import android.util.ArraySet; +import android.util.Slog; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; +import com.android.server.people.PeopleEventProto; + +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -29,6 +35,8 @@ import java.util.Set; /** An event representing the interaction with a specific conversation or app. */ public class Event { + private static final String TAG = Event.class.getSimpleName(); + public static final int TYPE_SHORTCUT_INVOCATION = 1; public static final int TYPE_NOTIFICATION_POSTED = 2; @@ -142,6 +150,36 @@ public class Event { return mDurationSeconds; } + /** Writes field members to {@link ProtoOutputStream}. */ + void writeToProto(@NonNull ProtoOutputStream protoOutputStream) { + protoOutputStream.write(PeopleEventProto.EVENT_TYPE, mType); + protoOutputStream.write(PeopleEventProto.TIME, mTimestamp); + protoOutputStream.write(PeopleEventProto.DURATION, mDurationSeconds); + } + + /** Reads from {@link ProtoInputStream} and constructs {@link Event}. */ + @NonNull + static Event readFromProto(@NonNull ProtoInputStream protoInputStream) throws IOException { + Event.Builder builder = new Event.Builder(); + while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (protoInputStream.getFieldNumber()) { + case (int) PeopleEventProto.EVENT_TYPE: + builder.setType(protoInputStream.readInt(PeopleEventProto.EVENT_TYPE)); + break; + case (int) PeopleEventProto.TIME: + builder.setTimestamp(protoInputStream.readLong(PeopleEventProto.TIME)); + break; + case (int) PeopleEventProto.DURATION: + builder.setDurationSeconds(protoInputStream.readInt(PeopleEventProto.DURATION)); + break; + default: + Slog.w(TAG, "Could not read undefined field: " + + protoInputStream.getFieldNumber()); + } + } + return builder.build(); + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -177,12 +215,14 @@ public class Event { /** Builder class for {@link Event} objects. */ static class Builder { - private final long mTimestamp; + private long mTimestamp; - private final int mType; + private int mType; private int mDurationSeconds; + private Builder() {} + Builder(long timestamp, @EventType int type) { mTimestamp = timestamp; mType = type; @@ -193,6 +233,16 @@ public class Event { return this; } + private Builder setTimestamp(long timestamp) { + mTimestamp = timestamp; + return this; + } + + private Builder setType(int type) { + mType = type; + return this; + } + Event build() { return new Event(this); } diff --git a/services/people/java/com/android/server/people/data/EventHistoryImpl.java b/services/people/java/com/android/server/people/data/EventHistoryImpl.java index 6bef1db5582e..85661c622fc2 100644 --- a/services/people/java/com/android/server/people/data/EventHistoryImpl.java +++ b/services/people/java/com/android/server/people/data/EventHistoryImpl.java @@ -16,42 +16,149 @@ package com.android.server.people.data; +import android.annotation.MainThread; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.WorkerThread; +import android.net.Uri; +import android.text.format.DateUtils; +import android.util.ArrayMap; +import android.util.Slog; import android.util.SparseArray; +import android.util.proto.ProtoInputStream; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.people.PeopleEventIndexesProto; +import com.android.server.people.PeopleEventsProto; +import com.android.server.people.TypedPeopleEventIndexProto; +import com.google.android.collect.Lists; + +import java.io.File; +import java.io.IOException; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; + class EventHistoryImpl implements EventHistory { + private static final long MAX_EVENTS_AGE = 4L * DateUtils.HOUR_IN_MILLIS; + private static final long PRUNE_OLD_EVENTS_DELAY = 15L * DateUtils.MINUTE_IN_MILLIS; + + private static final String EVENTS_DIR = "events"; + private static final String INDEXES_DIR = "indexes"; + private final Injector mInjector; + private final ScheduledExecutorService mScheduledExecutorService; + private final EventsProtoDiskReadWriter mEventsProtoDiskReadWriter; + private final EventIndexesProtoDiskReadWriter mEventIndexesProtoDiskReadWriter; // Event Type -> Event Index + @GuardedBy("this") private final SparseArray<EventIndex> mEventIndexArray = new SparseArray<>(); + @GuardedBy("this") private final EventList mRecentEvents = new EventList(); - EventHistoryImpl() { - mInjector = new Injector(); + private long mLastPruneTime; + + EventHistoryImpl(@NonNull File rootDir, + @NonNull ScheduledExecutorService scheduledExecutorService) { + this(new Injector(), rootDir, scheduledExecutorService); } @VisibleForTesting - EventHistoryImpl(Injector injector) { + EventHistoryImpl(@NonNull Injector injector, @NonNull File rootDir, + @NonNull ScheduledExecutorService scheduledExecutorService) { mInjector = injector; + mScheduledExecutorService = scheduledExecutorService; + mLastPruneTime = injector.currentTimeMillis(); + + File eventsDir = new File(rootDir, EVENTS_DIR); + mEventsProtoDiskReadWriter = new EventsProtoDiskReadWriter(eventsDir, + mScheduledExecutorService); + File indexesDir = new File(rootDir, INDEXES_DIR); + mEventIndexesProtoDiskReadWriter = new EventIndexesProtoDiskReadWriter(indexesDir, + scheduledExecutorService); + } + + @WorkerThread + @NonNull + static Map<String, EventHistoryImpl> eventHistoriesImplFromDisk(File categoryDir, + ScheduledExecutorService scheduledExecutorService) { + return eventHistoriesImplFromDisk(new Injector(), categoryDir, scheduledExecutorService); + } + + @VisibleForTesting + @NonNull + static Map<String, EventHistoryImpl> eventHistoriesImplFromDisk(Injector injector, + File categoryDir, ScheduledExecutorService scheduledExecutorService) { + Map<String, EventHistoryImpl> results = new ArrayMap<>(); + File[] keyDirs = categoryDir.listFiles(File::isDirectory); + if (keyDirs == null) { + return results; + } + for (File keyDir : keyDirs) { + File[] dirContents = keyDir.listFiles( + (dir, name) -> EVENTS_DIR.equals(name) || INDEXES_DIR.equals(name)); + if (dirContents != null && dirContents.length == 2) { + EventHistoryImpl eventHistory = new EventHistoryImpl(injector, keyDir, + scheduledExecutorService); + eventHistory.loadFromDisk(); + results.put(Uri.decode(keyDir.getName()), eventHistory); + } + } + return results; + } + + /** + * Loads recent events and indexes from disk to memory in a background thread. This should be + * called after the device powers on and the user has been unlocked. + */ + @VisibleForTesting + @MainThread + synchronized void loadFromDisk() { + mScheduledExecutorService.execute(() -> { + synchronized (this) { + EventList diskEvents = mEventsProtoDiskReadWriter.loadRecentEventsFromDisk(); + if (diskEvents != null) { + diskEvents.removeOldEvents(mInjector.currentTimeMillis() - MAX_EVENTS_AGE); + mRecentEvents.addAll(diskEvents.getAllEvents()); + } + + SparseArray<EventIndex> diskIndexes = + mEventIndexesProtoDiskReadWriter.loadIndexesFromDisk(); + if (diskIndexes != null) { + for (int i = 0; i < diskIndexes.size(); i++) { + mEventIndexArray.put(diskIndexes.keyAt(i), diskIndexes.valueAt(i)); + } + } + } + }); + } + + /** + * Flushes events and indexes immediately. This should be called when device is powering off. + */ + @MainThread + synchronized void saveToDisk() { + mEventsProtoDiskReadWriter.saveEventsImmediately(mRecentEvents); + mEventIndexesProtoDiskReadWriter.saveIndexesImmediately(mEventIndexArray); } @Override @NonNull - public EventIndex getEventIndex(@Event.EventType int eventType) { + public synchronized EventIndex getEventIndex(@Event.EventType int eventType) { EventIndex eventIndex = mEventIndexArray.get(eventType); return eventIndex != null ? new EventIndex(eventIndex) : mInjector.createEventIndex(); } @Override @NonNull - public EventIndex getEventIndex(Set<Integer> eventTypes) { + public synchronized EventIndex getEventIndex(Set<Integer> eventTypes) { EventIndex combined = mInjector.createEventIndex(); for (@Event.EventType int eventType : eventTypes) { EventIndex eventIndex = mEventIndexArray.get(eventType); @@ -64,29 +171,42 @@ class EventHistoryImpl implements EventHistory { @Override @NonNull - public List<Event> queryEvents(Set<Integer> eventTypes, long startTime, long endTime) { + public synchronized List<Event> queryEvents(Set<Integer> eventTypes, long startTime, + long endTime) { return mRecentEvents.queryEvents(eventTypes, startTime, endTime); } - void addEvent(Event event) { - EventIndex eventIndex = mEventIndexArray.get(event.getType()); - if (eventIndex == null) { - eventIndex = mInjector.createEventIndex(); - mEventIndexArray.put(event.getType(), eventIndex); - } - eventIndex.addEvent(event.getTimestamp()); - mRecentEvents.add(event); + synchronized void addEvent(Event event) { + pruneOldEvents(); + addEventInMemory(event); + mEventsProtoDiskReadWriter.scheduleEventsSave(mRecentEvents); + mEventIndexesProtoDiskReadWriter.scheduleIndexesSave(mEventIndexArray); } - void onDestroy() { + synchronized void onDestroy() { mEventIndexArray.clear(); mRecentEvents.clear(); - // TODO: STOPSHIP: Delete the data files. + mEventsProtoDiskReadWriter.deleteRecentEventsFile(); + mEventIndexesProtoDiskReadWriter.deleteIndexesFile(); } /** Deletes the events data that exceeds the retention period. */ - void pruneOldEvents(long currentTimeMillis) { - // TODO: STOPSHIP: Delete the old events data files. + synchronized void pruneOldEvents() { + long currentTime = mInjector.currentTimeMillis(); + if (currentTime - mLastPruneTime > PRUNE_OLD_EVENTS_DELAY) { + mRecentEvents.removeOldEvents(currentTime - MAX_EVENTS_AGE); + mLastPruneTime = currentTime; + } + } + + private synchronized void addEventInMemory(Event event) { + EventIndex eventIndex = mEventIndexArray.get(event.getType()); + if (eventIndex == null) { + eventIndex = mInjector.createEventIndex(); + mEventIndexArray.put(event.getType(), eventIndex); + } + eventIndex.addEvent(event.getTimestamp()); + mRecentEvents.add(event); } @VisibleForTesting @@ -95,5 +215,174 @@ class EventHistoryImpl implements EventHistory { EventIndex createEventIndex() { return new EventIndex(); } + + long currentTimeMillis() { + return System.currentTimeMillis(); + } + } + + /** Reads and writes {@link Event}s on disk. */ + private static class EventsProtoDiskReadWriter extends AbstractProtoDiskReadWriter<EventList> { + + private static final String TAG = EventsProtoDiskReadWriter.class.getSimpleName(); + + private static final String RECENT_FILE = "recent"; + + + EventsProtoDiskReadWriter(@NonNull File rootDir, + @NonNull ScheduledExecutorService scheduledExecutorService) { + super(rootDir, scheduledExecutorService); + rootDir.mkdirs(); + } + + @Override + ProtoStreamWriter<EventList> protoStreamWriter() { + return (protoOutputStream, data) -> { + for (Event event : data.getAllEvents()) { + long token = protoOutputStream.start(PeopleEventsProto.EVENTS); + event.writeToProto(protoOutputStream); + protoOutputStream.end(token); + } + }; + } + + @Override + ProtoStreamReader<EventList> protoStreamReader() { + return protoInputStream -> { + List<Event> results = Lists.newArrayList(); + try { + while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (protoInputStream.getFieldNumber() != (int) PeopleEventsProto.EVENTS) { + continue; + } + long token = protoInputStream.start(PeopleEventsProto.EVENTS); + Event event = Event.readFromProto(protoInputStream); + protoInputStream.end(token); + results.add(event); + } + } catch (IOException e) { + Slog.e(TAG, "Failed to read protobuf input stream.", e); + } + EventList eventList = new EventList(); + eventList.addAll(results); + return eventList; + }; + } + + @MainThread + void scheduleEventsSave(EventList recentEvents) { + scheduleSave(RECENT_FILE, recentEvents); + } + + @MainThread + void saveEventsImmediately(EventList recentEvents) { + saveImmediately(RECENT_FILE, recentEvents); + } + + /** + * Loads recent events from disk. This should be called when device is powered on. + */ + @WorkerThread + @Nullable + EventList loadRecentEventsFromDisk() { + return read(RECENT_FILE); + } + + @WorkerThread + void deleteRecentEventsFile() { + delete(RECENT_FILE); + } + } + + /** Reads and writes {@link EventIndex}s on disk. */ + private static class EventIndexesProtoDiskReadWriter extends + AbstractProtoDiskReadWriter<SparseArray<EventIndex>> { + + private static final String TAG = EventIndexesProtoDiskReadWriter.class.getSimpleName(); + + private static final String INDEXES_FILE = "index"; + + EventIndexesProtoDiskReadWriter(@NonNull File rootDir, + @NonNull ScheduledExecutorService scheduledExecutorService) { + super(rootDir, scheduledExecutorService); + rootDir.mkdirs(); + } + + @Override + ProtoStreamWriter<SparseArray<EventIndex>> protoStreamWriter() { + return (protoOutputStream, data) -> { + for (int i = 0; i < data.size(); i++) { + @Event.EventType int eventType = data.keyAt(i); + EventIndex index = data.valueAt(i); + long token = protoOutputStream.start(PeopleEventIndexesProto.TYPED_INDEXES); + protoOutputStream.write(TypedPeopleEventIndexProto.EVENT_TYPE, eventType); + long indexToken = protoOutputStream.start(TypedPeopleEventIndexProto.INDEX); + index.writeToProto(protoOutputStream); + protoOutputStream.end(indexToken); + protoOutputStream.end(token); + } + }; + } + + @Override + ProtoStreamReader<SparseArray<EventIndex>> protoStreamReader() { + return protoInputStream -> { + SparseArray<EventIndex> results = new SparseArray<>(); + try { + while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (protoInputStream.getFieldNumber() + != (int) PeopleEventIndexesProto.TYPED_INDEXES) { + continue; + } + long token = protoInputStream.start(PeopleEventIndexesProto.TYPED_INDEXES); + @Event.EventType int eventType = 0; + EventIndex index = EventIndex.EMPTY; + while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (protoInputStream.getFieldNumber()) { + case (int) TypedPeopleEventIndexProto.EVENT_TYPE: + eventType = protoInputStream.readInt( + TypedPeopleEventIndexProto.EVENT_TYPE); + break; + case (int) TypedPeopleEventIndexProto.INDEX: + long indexToken = protoInputStream.start( + TypedPeopleEventIndexProto.INDEX); + index = EventIndex.readFromProto(protoInputStream); + protoInputStream.end(indexToken); + break; + default: + Slog.w(TAG, "Could not read undefined field: " + + protoInputStream.getFieldNumber()); + } + } + results.append(eventType, index); + protoInputStream.end(token); + } + } catch (IOException e) { + Slog.e(TAG, "Failed to read protobuf input stream.", e); + } + return results; + }; + } + + @MainThread + void scheduleIndexesSave(SparseArray<EventIndex> indexes) { + scheduleSave(INDEXES_FILE, indexes); + } + + @MainThread + void saveIndexesImmediately(SparseArray<EventIndex> indexes) { + saveImmediately(INDEXES_FILE, indexes); + } + + @WorkerThread + @Nullable + SparseArray<EventIndex> loadIndexesFromDisk() { + return read(INDEXES_FILE); + } + + @WorkerThread + void deleteIndexesFile() { + delete(INDEXES_FILE); + } } } diff --git a/services/people/java/com/android/server/people/data/EventIndex.java b/services/people/java/com/android/server/people/data/EventIndex.java index b74a3fae98a5..47b620773180 100644 --- a/services/people/java/com/android/server/people/data/EventIndex.java +++ b/services/people/java/com/android/server/people/data/EventIndex.java @@ -21,9 +21,14 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.text.format.DateFormat; import android.util.Range; +import android.util.Slog; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.people.PeopleEventIndexProto; +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Instant; @@ -34,6 +39,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.TimeZone; import java.util.function.Function; @@ -60,8 +66,9 @@ import java.util.function.Function; * </pre> */ public class EventIndex { + private static final String TAG = EventIndex.class.getSimpleName(); - private static final int LONG_SIZE_BITS = 64; + private static final int RETENTION_DAYS = 63; private static final int TIME_SLOT_ONE_DAY = 0; @@ -118,22 +125,23 @@ public class EventIndex { private final Injector mInjector; EventIndex() { - mInjector = new Injector(); - mEventBitmaps = new long[]{0L, 0L, 0L, 0L}; - mLastUpdatedTime = mInjector.currentTimeMillis(); + this(new Injector()); } - EventIndex(EventIndex from) { - mInjector = new Injector(); - mEventBitmaps = Arrays.copyOf(from.mEventBitmaps, TIME_SLOT_TYPES_COUNT); - mLastUpdatedTime = from.mLastUpdatedTime; + EventIndex(@NonNull EventIndex from) { + this(from.mInjector, Arrays.copyOf(from.mEventBitmaps, TIME_SLOT_TYPES_COUNT), + from.mLastUpdatedTime); } @VisibleForTesting - EventIndex(Injector injector) { + EventIndex(@NonNull Injector injector) { + this(injector, new long[]{0L, 0L, 0L, 0L}, injector.currentTimeMillis()); + } + + private EventIndex(@NonNull Injector injector, long[] eventBitmaps, long lastUpdatedTime) { mInjector = injector; - mEventBitmaps = new long[]{0L, 0L, 0L, 0L}; - mLastUpdatedTime = mInjector.currentTimeMillis(); + mEventBitmaps = eventBitmaps; + mLastUpdatedTime = lastUpdatedTime; } /** @@ -202,7 +210,7 @@ public class EventIndex { updateEventBitmaps(currentTime); for (int slotType = 0; slotType < TIME_SLOT_TYPES_COUNT; slotType++) { int offset = diffTimeSlots(slotType, eventTime, currentTime); - if (offset < LONG_SIZE_BITS) { + if (offset < Long.SIZE) { mEventBitmaps[slotType] |= (1L << offset); } } @@ -232,19 +240,70 @@ public class EventIndex { return sb.toString(); } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof EventIndex)) { + return false; + } + EventIndex other = (EventIndex) obj; + return mLastUpdatedTime == other.mLastUpdatedTime + && Arrays.equals(mEventBitmaps, other.mEventBitmaps); + } + + @Override + public int hashCode() { + return Objects.hash(mLastUpdatedTime, mEventBitmaps); + } + + synchronized void writeToProto(@NonNull ProtoOutputStream protoOutputStream) { + for (long bitmap : mEventBitmaps) { + protoOutputStream.write(PeopleEventIndexProto.EVENT_BITMAPS, bitmap); + } + protoOutputStream.write(PeopleEventIndexProto.LAST_UPDATED_TIME, mLastUpdatedTime); + } + /** Shifts the event bitmaps to make them up-to-date. */ private void updateEventBitmaps(long currentTimeMillis) { for (int slotType = 0; slotType < TIME_SLOT_TYPES_COUNT; slotType++) { int offset = diffTimeSlots(slotType, mLastUpdatedTime, currentTimeMillis); - if (offset < LONG_SIZE_BITS) { + if (offset < Long.SIZE) { mEventBitmaps[slotType] <<= offset; } else { mEventBitmaps[slotType] = 0L; } } + + int bitsToClear = Long.SIZE - RETENTION_DAYS; + mEventBitmaps[TIME_SLOT_ONE_DAY] <<= bitsToClear; + mEventBitmaps[TIME_SLOT_ONE_DAY] >>>= bitsToClear; mLastUpdatedTime = currentTimeMillis; } + static EventIndex readFromProto(@NonNull ProtoInputStream protoInputStream) throws IOException { + int bitmapIndex = 0; + long[] eventBitmaps = new long[TIME_SLOT_TYPES_COUNT]; + long lastUpdated = 0L; + while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (protoInputStream.getFieldNumber()) { + case (int) PeopleEventIndexProto.EVENT_BITMAPS: + eventBitmaps[bitmapIndex++] = protoInputStream.readLong( + PeopleEventIndexProto.EVENT_BITMAPS); + break; + case (int) PeopleEventIndexProto.LAST_UPDATED_TIME: + lastUpdated = protoInputStream.readLong( + PeopleEventIndexProto.LAST_UPDATED_TIME); + break; + default: + Slog.e(TAG, "Could not read undefined field: " + + protoInputStream.getFieldNumber()); + } + } + return new EventIndex(new Injector(), eventBitmaps, lastUpdated); + } + private static LocalDateTime toLocalDateTime(long epochMilli) { return LocalDateTime.ofInstant( Instant.ofEpochMilli(epochMilli), TimeZone.getDefault().toZoneId()); diff --git a/services/people/java/com/android/server/people/data/EventList.java b/services/people/java/com/android/server/people/data/EventList.java index d770f912ea40..3788d6c92acf 100644 --- a/services/people/java/com/android/server/people/data/EventList.java +++ b/services/people/java/com/android/server/people/data/EventList.java @@ -18,6 +18,8 @@ package com.android.server.people.data; import android.annotation.NonNull; +import com.android.internal.util.CollectionUtils; + import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -41,6 +43,16 @@ class EventList { mEvents.add(index, event); } + + /** + * Call #add on each event to keep the order. + */ + void addAll(@NonNull List<Event> events) { + for (Event event : events) { + add(event); + } + } + /** * Returns a {@link List} of {@link Event}s whose timestamps are between the specified {@code * fromTimestamp}, inclusive, and {@code toTimestamp} exclusive, and match the specified event @@ -73,6 +85,44 @@ class EventList { mEvents.clear(); } + /** + * Returns a copy of events. + */ + @NonNull + List<Event> getAllEvents() { + return CollectionUtils.copyOf(mEvents); + } + + /** + * Remove events that are older than the specified cut off threshold timestamp. + */ + void removeOldEvents(long cutOffThreshold) { + + // Everything before the cut off is considered old, and should be removed. + int cutOffIndex = firstIndexOnOrAfter(cutOffThreshold); + if (cutOffIndex == 0) { + return; + } + + // Clear entire list if the cut off is greater than the last element. + int eventsSize = mEvents.size(); + if (cutOffIndex == eventsSize) { + mEvents.clear(); + return; + } + + // Reorder the list starting from the cut off index. + int i = 0; + for (; cutOffIndex < eventsSize; i++, cutOffIndex++) { + mEvents.set(i, mEvents.get(cutOffIndex)); + } + + // Clear the list after reordering. + if (eventsSize > i) { + mEvents.subList(i, eventsSize).clear(); + } + } + /** Returns the first index whose timestamp is greater or equal to the provided timestamp. */ private int firstIndexOnOrAfter(long timestamp) { int result = mEvents.size(); diff --git a/services/people/java/com/android/server/people/data/EventStore.java b/services/people/java/com/android/server/people/data/EventStore.java index c8d44ac07106..00d4241fc5f7 100644 --- a/services/people/java/com/android/server/people/data/EventStore.java +++ b/services/people/java/com/android/server/people/data/EventStore.java @@ -17,16 +17,22 @@ package com.android.server.people.data; import android.annotation.IntDef; +import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.Uri; import android.util.ArrayMap; +import com.android.internal.annotations.GuardedBy; + +import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; import java.util.function.Predicate; /** The store that stores and accesses the events data for a package. */ @@ -57,14 +63,58 @@ class EventStore { @Retention(RetentionPolicy.SOURCE) @interface EventCategory {} + @GuardedBy("this") private final List<Map<String, EventHistoryImpl>> mEventHistoryMaps = new ArrayList<>(); + private final List<File> mEventsCategoryDirs = new ArrayList<>(); + private final ScheduledExecutorService mScheduledExecutorService; - EventStore() { + EventStore(@NonNull File packageDir, + @NonNull ScheduledExecutorService scheduledExecutorService) { mEventHistoryMaps.add(CATEGORY_SHORTCUT_BASED, new ArrayMap<>()); mEventHistoryMaps.add(CATEGORY_LOCUS_ID_BASED, new ArrayMap<>()); mEventHistoryMaps.add(CATEGORY_CALL, new ArrayMap<>()); mEventHistoryMaps.add(CATEGORY_SMS, new ArrayMap<>()); mEventHistoryMaps.add(CATEGORY_CLASS_BASED, new ArrayMap<>()); + + File eventDir = new File(packageDir, "event"); + mEventsCategoryDirs.add(CATEGORY_SHORTCUT_BASED, new File(eventDir, "shortcut")); + mEventsCategoryDirs.add(CATEGORY_LOCUS_ID_BASED, new File(eventDir, "locus")); + mEventsCategoryDirs.add(CATEGORY_CALL, new File(eventDir, "call")); + mEventsCategoryDirs.add(CATEGORY_SMS, new File(eventDir, "sms")); + mEventsCategoryDirs.add(CATEGORY_CLASS_BASED, new File(eventDir, "class")); + + mScheduledExecutorService = scheduledExecutorService; + } + + /** + * Loads existing {@link EventHistoryImpl}s from disk. This should be called when device powers + * on and user is unlocked. + */ + @MainThread + void loadFromDisk() { + mScheduledExecutorService.execute(() -> { + synchronized (this) { + for (@EventCategory int category = 0; category < mEventsCategoryDirs.size(); + category++) { + File categoryDir = mEventsCategoryDirs.get(category); + Map<String, EventHistoryImpl> existingEventHistoriesImpl = + EventHistoryImpl.eventHistoriesImplFromDisk(categoryDir, + mScheduledExecutorService); + mEventHistoryMaps.get(category).putAll(existingEventHistoriesImpl); + } + } + }); + } + + /** + * Flushes all {@link EventHistoryImpl}s to disk. Should be called when device is shutting down. + */ + synchronized void saveToDisk() { + for (Map<String, EventHistoryImpl> map : mEventHistoryMaps) { + for (EventHistoryImpl eventHistory : map.values()) { + eventHistory.saveToDisk(); + } + } } /** @@ -74,7 +124,7 @@ class EventStore { * name. */ @Nullable - EventHistory getEventHistory(@EventCategory int category, String key) { + synchronized EventHistory getEventHistory(@EventCategory int category, String key) { return mEventHistoryMaps.get(category).get(key); } @@ -87,8 +137,11 @@ class EventStore { * name. */ @NonNull - EventHistoryImpl getOrCreateEventHistory(@EventCategory int category, String key) { - return mEventHistoryMaps.get(category).computeIfAbsent(key, k -> new EventHistoryImpl()); + synchronized EventHistoryImpl getOrCreateEventHistory(@EventCategory int category, String key) { + return mEventHistoryMaps.get(category).computeIfAbsent(key, + k -> new EventHistoryImpl( + new File(mEventsCategoryDirs.get(category), Uri.encode(key)), + mScheduledExecutorService)); } /** @@ -97,7 +150,7 @@ class EventStore { * @param key Category-specific key, it can be shortcut ID, locus ID, phone number, or class * name. */ - void deleteEventHistory(@EventCategory int category, String key) { + synchronized void deleteEventHistory(@EventCategory int category, String key) { EventHistoryImpl eventHistory = mEventHistoryMaps.get(category).remove(key); if (eventHistory != null) { eventHistory.onDestroy(); @@ -105,16 +158,18 @@ class EventStore { } /** Deletes all the events and index data for the specified category from disk. */ - void deleteEventHistories(@EventCategory int category) { + synchronized void deleteEventHistories(@EventCategory int category) { + for (EventHistoryImpl eventHistory : mEventHistoryMaps.get(category).values()) { + eventHistory.onDestroy(); + } mEventHistoryMaps.get(category).clear(); - // TODO: Implement this method to delete the data from disk. } /** Deletes the events data that exceeds the retention period. */ - void pruneOldEvents(long currentTimeMillis) { + synchronized void pruneOldEvents() { for (Map<String, EventHistoryImpl> map : mEventHistoryMaps) { for (EventHistoryImpl eventHistory : map.values()) { - eventHistory.pruneOldEvents(currentTimeMillis); + eventHistory.pruneOldEvents(); } } } @@ -125,7 +180,8 @@ class EventStore { * * @param keyChecker Check whether there exists a conversation contains this key. */ - void pruneOrphanEventHistories(@EventCategory int category, Predicate<String> keyChecker) { + synchronized void pruneOrphanEventHistories(@EventCategory int category, + Predicate<String> keyChecker) { Set<String> keys = mEventHistoryMaps.get(category).keySet(); List<String> keysToDelete = new ArrayList<>(); for (String key : keys) { @@ -141,4 +197,12 @@ class EventStore { } } } + + synchronized void onDestroy() { + for (Map<String, EventHistoryImpl> map : mEventHistoryMaps) { + for (EventHistoryImpl eventHistory : map.values()) { + eventHistory.onDestroy(); + } + } + } } diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java index c55f97205bc5..d47e2cc1ba90 100644 --- a/services/people/java/com/android/server/people/data/PackageData.java +++ b/services/people/java/com/android/server/people/data/PackageData.java @@ -27,8 +27,10 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.LocusId; import android.text.TextUtils; +import android.util.ArrayMap; import java.io.File; +import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; import java.util.function.Predicate; @@ -63,22 +65,50 @@ public class PackageData { mUserId = userId; mPackageDataDir = new File(perUserPeopleDataDir, mPackageName); + mPackageDataDir.mkdirs(); + mConversationStore = new ConversationStore(mPackageDataDir, scheduledExecutorService, helper); - mEventStore = new EventStore(); + mEventStore = new EventStore(mPackageDataDir, scheduledExecutorService); mIsDefaultDialerPredicate = isDefaultDialerPredicate; mIsDefaultSmsAppPredicate = isDefaultSmsAppPredicate; } - /** Called when user is unlocked. */ - void loadFromDisk() { - mPackageDataDir.mkdirs(); + /** + * Returns a map of package directory names as keys and their associated {@link PackageData}. + * This should be called when device is powered on and unlocked. + */ + @NonNull + static Map<String, PackageData> packagesDataFromDisk(@UserIdInt int userId, + @NonNull Predicate<String> isDefaultDialerPredicate, + @NonNull Predicate<String> isDefaultSmsAppPredicate, + @NonNull ScheduledExecutorService scheduledExecutorService, + @NonNull File perUserPeopleDataDir, + @NonNull ContactsQueryHelper helper) { + Map<String, PackageData> results = new ArrayMap<>(); + File[] packageDirs = perUserPeopleDataDir.listFiles(File::isDirectory); + if (packageDirs == null) { + return results; + } + for (File packageDir : packageDirs) { + PackageData packageData = new PackageData(packageDir.getName(), userId, + isDefaultDialerPredicate, isDefaultSmsAppPredicate, scheduledExecutorService, + perUserPeopleDataDir, helper); + packageData.loadFromDisk(); + results.put(packageDir.getName(), packageData); + } + return results; + } + + private void loadFromDisk() { mConversationStore.loadConversationsFromDisk(); + mEventStore.loadFromDisk(); } /** Called when device is shutting down. */ void saveToDisk() { mConversationStore.saveConversationsToDisk(); + mEventStore.saveToDisk(); } @NonNull @@ -222,6 +252,7 @@ public class PackageData { } void onDestroy() { - // TODO: STOPSHIP: Implements this method for the case of package being uninstalled. + mEventStore.onDestroy(); + mConversationStore.onDestroy(); } } diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java index 7ca4b6c76a36..d3cecceed884 100644 --- a/services/people/java/com/android/server/people/data/UserData.java +++ b/services/people/java/com/android/server/people/data/UserData.java @@ -73,9 +73,8 @@ class UserData { // Ensures per user root directory for people data is present, and attempt to load // data from disk. mPerUserPeopleDataDir.mkdirs(); - for (PackageData packageData : mPackageDataMap.values()) { - packageData.loadFromDisk(); - } + mPackageDataMap.putAll(PackageData.packagesDataFromDisk(mUserId, this::isDefaultDialer, + this::isDefaultSmsApp, mScheduledExecutorService, mPerUserPeopleDataDir, mHelper)); } void setUserStopped() { diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java index 6190802d033d..fa0febd7f20f 100644 --- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java @@ -46,8 +46,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; @@ -58,6 +56,9 @@ import androidx.test.core.app.ApplicationProvider; import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.util.FunctionalUtils.ThrowingSupplier; import com.android.server.LocalServices; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.testing.shadows.ShadowApplicationPackageManager; import com.android.server.testing.shadows.ShadowUserManager; import com.android.server.wm.ActivityTaskManagerInternal; @@ -135,7 +136,8 @@ public class CrossProfileAppsServiceImplRoboTest { eq(userId))) .thenReturn(packageInfo); when(mPackageManagerInternal.getPackage(uid)) - .thenReturn(PackageImpl.forParsing(CROSS_PROFILE_APP_PACKAGE_NAME)); + .thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME) + .hideAsParsed()).hideAsFinal()); } private PackageInfo buildTestPackageInfo() { @@ -497,7 +499,9 @@ public class CrossProfileAppsServiceImplRoboTest { private void declareCrossProfileAttributeOnCrossProfileApp(boolean value) { mockCrossProfileAndroidPackage( - PackageImpl.forParsing(CROSS_PROFILE_APP_PACKAGE_NAME).setCrossProfile(value)); + ((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME) + .setCrossProfile(value) + .hideAsParsed()).hideAsFinal()); } private class TestInjector implements CrossProfileAppsServiceImpl.Injector { diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java index 2d5fa237f6b7..959dc0525e8f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -50,7 +50,6 @@ import android.app.AppOpsManager.PackageOps; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManagerInternal; -import android.content.pm.parsing.AndroidPackage; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -63,6 +62,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.server.LocalServices; +import com.android.server.pm.parsing.pkg.AndroidPackage; import org.junit.After; import org.junit.Before; diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java index 3778e17f4320..e5450a9ca5f2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java @@ -149,7 +149,7 @@ public class BlobStoreManagerServiceTest { final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobId2, blobFile2, false); mUserBlobs.put(blobHandle2, blobMetadata2); - mService.addKnownIdsForTest(sessionId1, sessionId2, sessionId3, sessionId4, + mService.addActiveIdsForTest(sessionId1, sessionId2, sessionId3, sessionId4, blobId1, blobId2); // Invoke test method @@ -180,8 +180,10 @@ public class BlobStoreManagerServiceTest { assertThat(mUserBlobs.get(blobHandle1)).isNotNull(); assertThat(mUserBlobs.get(blobHandle2)).isNull(); - assertThat(mService.getKnownIdsForTest()).containsExactly( + assertThat(mService.getActiveIdsForTest()).containsExactly( sessionId2, sessionId3, blobId1); + assertThat(mService.getKnownIdsForTest()).containsExactly( + sessionId1, sessionId2, sessionId3, sessionId4, blobId1, blobId2); } @Test @@ -198,12 +200,12 @@ public class BlobStoreManagerServiceTest { doReturn(String.valueOf(testId3)).when(file3).getName(); doReturn(new File[] {file1, file2, file3}).when(mBlobsDir).listFiles(); - mService.addKnownIdsForTest(testId1, testId3); + mService.addActiveIdsForTest(testId1, testId3); // Invoke test method mService.handleIdleMaintenanceLocked(); - // Verify unknown blobs are delete + // Verify unknown blobs are deleted verify(file1, never()).delete(); verify(file2).delete(); verify(file3, never()).delete(); @@ -242,7 +244,7 @@ public class BlobStoreManagerServiceTest { sessionId3, sessionFile3, blobHandle3); mUserSessions.append(sessionId3, session3); - mService.addKnownIdsForTest(sessionId1, sessionId2, sessionId3); + mService.addActiveIdsForTest(sessionId1, sessionId2, sessionId3); // Invoke test method mService.handleIdleMaintenanceLocked(); @@ -255,7 +257,9 @@ public class BlobStoreManagerServiceTest { assertThat(mUserSessions.size()).isEqualTo(1); assertThat(mUserSessions.get(sessionId2)).isNotNull(); - assertThat(mService.getKnownIdsForTest()).containsExactly(sessionId2); + assertThat(mService.getActiveIdsForTest()).containsExactly(sessionId2); + assertThat(mService.getKnownIdsForTest()).containsExactly( + sessionId1, sessionId2, sessionId3); } @Test @@ -282,7 +286,7 @@ public class BlobStoreManagerServiceTest { final BlobMetadata blobMetadata3 = createBlobMetadataMock(blobId3, blobFile3, false); mUserBlobs.put(blobHandle3, blobMetadata3); - mService.addKnownIdsForTest(blobId1, blobId2, blobId3); + mService.addActiveIdsForTest(blobId1, blobId2, blobId3); // Invoke test method mService.handleIdleMaintenanceLocked(); @@ -295,7 +299,8 @@ public class BlobStoreManagerServiceTest { assertThat(mUserBlobs.size()).isEqualTo(1); assertThat(mUserBlobs.get(blobHandle2)).isNotNull(); - assertThat(mService.getKnownIdsForTest()).containsExactly(blobId2); + assertThat(mService.getActiveIdsForTest()).containsExactly(blobId2); + assertThat(mService.getKnownIdsForTest()).containsExactly(blobId1, blobId2, blobId3); } private BlobStoreSession createBlobStoreSessionMock(String ownerPackageName, int ownerUid, diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java index d7a3cfd8aeca..1bf9c2a0822e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java @@ -73,7 +73,9 @@ public class JobStatusTest { private static final double DELTA = 0.00001; private static final String TEST_PACKAGE = "job.test.package"; private static final ComponentName TEST_JOB_COMPONENT = new ComponentName(TEST_PACKAGE, "test"); - private static final Uri TEST_MEDIA_URI = Uri.parse("content://media/path/to/media"); + + private static final Uri IMAGES_MEDIA_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + private static final Uri VIDEO_MEDIA_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; @Mock private JobSchedulerInternal mJobSchedulerInternal; @@ -127,7 +129,7 @@ public class JobStatusTest { @Test public void testMediaBackupExemption_lateConstraint() { final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) - .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) + .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .setOverrideDeadline(12) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); @@ -138,7 +140,7 @@ public class JobStatusTest { @Test public void testMediaBackupExemption_noConnectivityConstraint() { final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) - .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) + .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); assertEffectiveBucketForMediaExemption(createJobStatus(triggerContentJob), false); @@ -156,7 +158,7 @@ public class JobStatusTest { @Test public void testMediaBackupExemption_wrongSourcePackage() { final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) - .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) + .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn("not.test.package"); @@ -164,11 +166,12 @@ public class JobStatusTest { } @Test - public void testMediaBackupExemption_nonMediaUri() { - final Uri nonMediaUri = Uri.parse("content://not-media/any/path"); + public void testMediaBackupExemption_nonEligibleUri() { + final Uri nonEligibleUri = MediaStore.AUTHORITY_URI.buildUpon() + .appendPath("any_path").build(); final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) - .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) - .addTriggerContentUri(new JobInfo.TriggerContentUri(nonMediaUri, 0)) + .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) + .addTriggerContentUri(new JobInfo.TriggerContentUri(nonEligibleUri, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); @@ -177,12 +180,25 @@ public class JobStatusTest { @Test public void testMediaBackupExemptionGranted() { - final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) - .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) + when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); + final JobInfo imageUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) + .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); - when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); - assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), true); + assertEffectiveBucketForMediaExemption(createJobStatus(imageUriJob), true); + + final JobInfo videoUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) + .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0)) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .build(); + assertEffectiveBucketForMediaExemption(createJobStatus(videoUriJob), true); + + final JobInfo bothUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) + .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) + .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0)) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .build(); + assertEffectiveBucketForMediaExemption(createJobStatus(bothUriJob), true); } @Test diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index bf2b9bec33c9..d148c21b7d6e 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -93,6 +93,7 @@ android_test { }, data: [":JobTestApp"], + resource_zips: [":FrameworksServicesTests_apks_as_resources"], } java_library { @@ -115,3 +116,28 @@ filegroup { "src/com/android/server/pm/SuspendPackagesTest.java", ], } + +// Rules to copy all the test apks to the intermediate raw resource directory +java_genrule { + name: "FrameworksServicesTests_apks_as_resources", + srcs: [ + ":FrameworksCoreTests_install_complete_package_info", + ":FrameworksServicesTests_install_intent_filters", + ":FrameworksServicesTests_install_split_base", + ":FrameworksServicesTests_install_split_feature_a", + ":FrameworksServicesTests_install_uses_sdk_0", + ":FrameworksServicesTests_install_uses_sdk_q0", + ":FrameworksServicesTests_install_uses_sdk_r", + ":FrameworksServicesTests_install_uses_sdk_r0", + ":FrameworksServicesTests_install_uses_sdk_r5", + ], + out: ["FrameworkServicesTests_apks_as_resources.res.zip"], + tools: ["soong_zip"], + + cmd: "mkdir -p $(genDir)/res/raw && " + + "for i in $(in); do " + + " x=$${i##*FrameworksCoreTests_}; cp $$i $(genDir)/res/raw/$${x%.apk};" + + " x=$${i##*FrameworksServicesTests_}; cp $$i $(genDir)/res/raw/$${x%.apk};" + + "done && " + + "$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res", +} diff --git a/services/tests/servicestests/apks/Android.bp b/services/tests/servicestests/apks/Android.bp new file mode 100644 index 000000000000..3e11604005a0 --- /dev/null +++ b/services/tests/servicestests/apks/Android.bp @@ -0,0 +1,7 @@ +java_defaults { + name: "FrameworksServicesTests_apks_defaults", + sdk_version: "current", + + // Every package should have a native library + jni_libs: ["libframeworks_coretests_jni"], +} diff --git a/services/tests/servicestests/apks/install-split-base/Android.bp b/services/tests/servicestests/apks/install-split-base/Android.bp new file mode 100644 index 000000000000..1b62aa2a8e96 --- /dev/null +++ b/services/tests/servicestests/apks/install-split-base/Android.bp @@ -0,0 +1,6 @@ +android_test_helper_app { + name: "FrameworksServicesTests_install_split_base", + defaults: ["FrameworksServicesTests_apks_defaults"], + + srcs: ["**/*.java"], +} diff --git a/core/tests/coretests/apks/install-split-base/AndroidManifest.xml b/services/tests/servicestests/apks/install-split-base/AndroidManifest.xml index c2bfeddf32e3..2979395a8141 100644 --- a/core/tests/coretests/apks/install-split-base/AndroidManifest.xml +++ b/services/tests/servicestests/apks/install-split-base/AndroidManifest.xml @@ -15,7 +15,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_split" + package="com.android.frameworks.servicestests.install_split" android:isolatedSplits="true"> <application android:label="ClassloaderSplitApp"> diff --git a/core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java b/services/tests/servicestests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java index cb5760ceef8e..cb5760ceef8e 100644 --- a/core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java +++ b/services/tests/servicestests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java diff --git a/core/tests/coretests/apks/install-split-feature-a/Android.bp b/services/tests/servicestests/apks/install-split-feature-a/Android.bp index 9ec9893cc408..45d891720166 100644 --- a/core/tests/coretests/apks/install-split-feature-a/Android.bp +++ b/services/tests/servicestests/apks/install-split-feature-a/Android.bp @@ -1,6 +1,6 @@ android_test_helper_app { - name: "FrameworksCoreTests_install_split_feature_a", - defaults: ["FrameworksCoreTests_apks_defaults"], + name: "FrameworksServicesTests_install_split_feature_a", + defaults: ["FrameworksServicesTests_apks_defaults"], srcs: ["**/*.java"], diff --git a/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml b/services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml index 3221c75ebe0c..a3dd55f712a2 100644 --- a/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml +++ b/services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml @@ -15,7 +15,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_split" + package="com.android.frameworks.servicestests.install_split" featureSplit="feature_a"> <application> diff --git a/core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java b/services/tests/servicestests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java index 0af5f893164c..0af5f893164c 100644 --- a/core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java +++ b/services/tests/servicestests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java diff --git a/services/tests/servicestests/apks/install_intent_filters/Android.bp b/services/tests/servicestests/apks/install_intent_filters/Android.bp new file mode 100644 index 000000000000..59c8524e01c2 --- /dev/null +++ b/services/tests/servicestests/apks/install_intent_filters/Android.bp @@ -0,0 +1,7 @@ +android_test_helper_app { + name: "FrameworksServicesTests_install_intent_filters", + defaults: ["FrameworksServicesTests_apks_defaults"], + + srcs: ["**/*.java"], +} + diff --git a/core/tests/coretests/apks/install_intent_filters/AndroidManifest.xml b/services/tests/servicestests/apks/install_intent_filters/AndroidManifest.xml index d7ee76eb381d..fc7134d24dda 100644 --- a/core/tests/coretests/apks/install_intent_filters/AndroidManifest.xml +++ b/services/tests/servicestests/apks/install_intent_filters/AndroidManifest.xml @@ -16,7 +16,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_intent_filters"> + package="com.android.frameworks.servicestests.install_intent_filters"> <!-- This manifest declares an activity for testing intent filters. @@ -24,7 +24,7 @@ --> <uses-feature - android:name="com.android.frameworks.coretests.nonexistent" /> + android:name="com.android.frameworks.servicestests.nonexistent" /> <uses-configuration android:reqFiveWayNav="false" /> @@ -41,7 +41,7 @@ <application android:hasCode="true"> <activity - android:name="com.android.frameworks.coretests.TestActivity"> + android:name="com.android.frameworks.servicestests.TestActivity"> <intent-filter> <action android:name="action1"/> <data android:mimeGroup="mime_group_1"/> diff --git a/core/tests/coretests/apks/install_intent_filters/src/com/android/frameworks/coretests/TestActivity.java b/services/tests/servicestests/apks/install_intent_filters/src/com/android/frameworks/servicestests/TestActivity.java index 08a19aacc21e..08a19aacc21e 100644 --- a/core/tests/coretests/apks/install_intent_filters/src/com/android/frameworks/coretests/TestActivity.java +++ b/services/tests/servicestests/apks/install_intent_filters/src/com/android/frameworks/servicestests/TestActivity.java diff --git a/services/tests/servicestests/apks/install_uses_sdk/Android.bp b/services/tests/servicestests/apks/install_uses_sdk/Android.bp new file mode 100644 index 000000000000..c24aa2bd8bba --- /dev/null +++ b/services/tests/servicestests/apks/install_uses_sdk/Android.bp @@ -0,0 +1,39 @@ +android_test_helper_app { + name: "FrameworksServicesTests_install_uses_sdk_r0", + defaults: ["FrameworksServicesTests_apks_defaults"], + manifest: "AndroidManifest-r0.xml", + + srcs: ["**/*.java"], +} + +android_test_helper_app { + name: "FrameworksServicesTests_install_uses_sdk_r5", + defaults: ["FrameworksServicesTests_apks_defaults"], + manifest: "AndroidManifest-r5.xml", + + srcs: ["**/*.java"], +} + +android_test_helper_app { + name: "FrameworksServicesTests_install_uses_sdk_q0", + defaults: ["FrameworksServicesTests_apks_defaults"], + manifest: "AndroidManifest-q0.xml", + + srcs: ["**/*.java"], +} + +android_test_helper_app { + name: "FrameworksServicesTests_install_uses_sdk_r", + defaults: ["FrameworksServicesTests_apks_defaults"], + manifest: "AndroidManifest-r.xml", + + srcs: ["**/*.java"], +} + +android_test_helper_app { + name: "FrameworksServicesTests_install_uses_sdk_0", + defaults: ["FrameworksServicesTests_apks_defaults"], + manifest: "AndroidManifest-0.xml", + + srcs: ["**/*.java"], +} diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml index 634228b1ace3..215384b2831c 100644 --- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-0.xml +++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml @@ -14,7 +14,7 @@ limitations under the License. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_uses_sdk"> + package="com.android.frameworks.servicestests.install_uses_sdk"> <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29"> <!-- This is invalid, because there is no sdk version specified --> diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-q0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0.xml index 8994966832aa..c0e58674a226 100644 --- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-q0.xml +++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0.xml @@ -14,7 +14,7 @@ limitations under the License. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_uses_sdk"> + package="com.android.frameworks.servicestests.install_uses_sdk"> <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29"> <!-- This fails because 29 doesn't have an extension sdk --> diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml index 0d0d8b9e9029..5d22577d118a 100644 --- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r.xml +++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml @@ -14,7 +14,7 @@ limitations under the License. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_uses_sdk"> + package="com.android.frameworks.servicestests.install_uses_sdk"> <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29"> <!-- This is invalid, because there is no minimum extension version specified --> diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml index a987afa2438e..c1244f246355 100644 --- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r0.xml +++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml @@ -14,7 +14,7 @@ limitations under the License. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_uses_sdk"> + package="com.android.frameworks.servicestests.install_uses_sdk"> <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29"> <extension-sdk android:sdkVersion="10000" android:minExtensionVersion="0" /> diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r5.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml index 9860096386bc..3410938b3c2d 100644 --- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r5.xml +++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml @@ -14,7 +14,7 @@ limitations under the License. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_uses_sdk"> + package="com.android.frameworks.servicestests.install_uses_sdk"> <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29"> <!-- This will fail to install, because minExtensionVersion is not met --> diff --git a/core/tests/coretests/apks/install_uses_sdk/res/values/strings.xml b/services/tests/servicestests/apks/install_uses_sdk/res/values/strings.xml index 3b8b3b1af9b5..3b8b3b1af9b5 100644 --- a/core/tests/coretests/apks/install_uses_sdk/res/values/strings.xml +++ b/services/tests/servicestests/apks/install_uses_sdk/res/values/strings.xml diff --git a/core/tests/coretests/res/raw/com_android_tzdata.apex b/services/tests/servicestests/res/raw/com_android_tzdata.apex Binary files differindex ca89bf66c8ff..ca89bf66c8ff 100644 --- a/core/tests/coretests/res/raw/com_android_tzdata.apex +++ b/services/tests/servicestests/res/raw/com_android_tzdata.apex diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index 9574a086c74b..40b0e7114cc9 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -31,8 +31,11 @@ import android.content.pm.PackageManager; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.annotations.Presubmit; import android.provider.Settings; +import androidx.test.filters.SmallTest; + import com.android.frameworks.servicestests.R; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -43,7 +46,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -// TODO (b/143516163): Fix old test cases and put into presubmit. +// TODO (b/149818286): Fix old test cases and put the whole test into presubmit. public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { private static final String USER_TYPE_EMPTY = ""; @@ -343,6 +346,8 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { assertTrue(alreadySet.contains(UserManager.DISALLOW_BLUETOOTH_SHARING)); } + @Presubmit + @SmallTest public void testCompMigrationUnAffiliated_skipped() throws Exception { prepareAdmin1AsDo(); prepareAdminAnotherPackageAsPo(COPE_PROFILE_USER_ID); @@ -354,6 +359,8 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { assertTrue(dpms.mOwners.hasDeviceOwner()); } + @Presubmit + @SmallTest public void testCompMigrationAffiliated() throws Exception { prepareAdmin1AsDo(); prepareAdmin1AsPo(COPE_PROFILE_USER_ID); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index 3a8258be5f01..853151f8a0de 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -369,6 +369,12 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override + PendingIntent pendingIntentGetBroadcast(Context context, int requestCode, + Intent intent, int flags) { + return null; + } + + @Override void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer, int userHandle) { mContentObservers.put(new Pair<Uri, Integer>(uri, userHandle), observer); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 6a83082c736c..dbf2f14146fb 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -26,6 +26,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM; import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; import static android.app.admin.DevicePolicyManager.WIPE_EUICC; import static android.app.admin.PasswordMetrics.computeForPassword; +import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; @@ -6048,6 +6049,86 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertTrue(dpm.isCommonCriteriaModeEnabled(admin1)); } + public void testCanProfileOwnerResetPasswordWhenLocked_nonDirectBootAwarePo() + throws Exception { + setDeviceEncryptionPerUser(); + setupProfileOwner(); + setupPasswordResetToken(); + + mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; + assertFalse("po is not direct boot aware", + dpm.canProfileOwnerResetPasswordWhenLocked(DpmMockContext.CALLER_USER_HANDLE)); + } + + public void testCanProfileOwnerResetPasswordWhenLocked_noActiveToken() throws Exception { + setDeviceEncryptionPerUser(); + setupProfileOwner(); + makeAdmin1DirectBootAware(); + + mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; + assertFalse("po doesn't have an active password reset token", + dpm.canProfileOwnerResetPasswordWhenLocked(DpmMockContext.CALLER_USER_HANDLE)); + } + + public void testCanProfileOwnerResetPasswordWhenLocked_nonFbeDevice() throws Exception { + setupProfileOwner(); + makeAdmin1DirectBootAware(); + setupPasswordResetToken(); + + mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; + assertFalse("device is not FBE", + dpm.canProfileOwnerResetPasswordWhenLocked(DpmMockContext.CALLER_USER_HANDLE)); + } + + public void testCanProfileOwnerResetPasswordWhenLocked() throws Exception { + setDeviceEncryptionPerUser(); + setupProfileOwner(); + makeAdmin1DirectBootAware(); + setupPasswordResetToken(); + + mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; + assertTrue("direct boot aware po with active password reset token", + dpm.canProfileOwnerResetPasswordWhenLocked(DpmMockContext.CALLER_USER_HANDLE)); + } + + private void setupPasswordResetToken() { + final byte[] token = new byte[32]; + final long handle = 123456; + + when(getServices().lockPatternUtils + .addEscrowToken(eq(token), eq(DpmMockContext.CALLER_USER_HANDLE), + nullable(EscrowTokenStateChangeCallback.class))) + .thenReturn(handle); + + dpm.setResetPasswordToken(admin1, token); + + when(getServices().lockPatternUtils + .isEscrowTokenActive(eq(handle), eq(DpmMockContext.CALLER_USER_HANDLE))) + .thenReturn(true); + + assertTrue("failed to activate token", dpm.isResetPasswordTokenActive(admin1)); + } + + private void makeAdmin1DirectBootAware() + throws PackageManager.NameNotFoundException, android.os.RemoteException { + Mockito.reset(getServices().ipackageManager); + + final ApplicationInfo ai = DpmTestUtils.cloneParcelable( + mRealTestContext.getPackageManager().getApplicationInfo( + admin1.getPackageName(), + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS)); + ai.privateFlags = PRIVATE_FLAG_DIRECT_BOOT_AWARE; + + doReturn(ai).when(getServices().ipackageManager).getApplicationInfo( + eq(admin1.getPackageName()), + anyInt(), + eq(DpmMockContext.CALLER_USER_HANDLE)); + } + + private void setDeviceEncryptionPerUser() { + when(getServices().storageManager.isFileBasedEncryptionEnabled()).thenReturn(true); + } + private void setCrossProfileAppsList(String... packages) { when(mContext.getResources() .getStringArray(eq(R.array.cross_profile_apps))) diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java index 3dc26afdb9af..ab21ab05ab5f 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java @@ -73,7 +73,7 @@ public class RuleBinaryParserTest { private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS); private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS); private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS); - private static final int INVALID_KEY_VALUE = 6; + private static final int INVALID_KEY_VALUE = 8; private static final String INVALID_KEY = getBits(INVALID_KEY_VALUE, KEY_BITS); private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS); diff --git a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java index 19cbb0e6e9b5..a99c982753c5 100644 --- a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java @@ -38,6 +38,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.location.GnssAntennaInfo; +import android.location.GnssAntennaInfo.SphericalCorrections; import android.location.GnssClock; import android.location.GnssMeasurementCorrections; import android.location.GnssMeasurementsEvent; @@ -245,8 +246,8 @@ public class GnssManagerServiceTest { private static List<GnssAntennaInfo> createDummyGnssAntennaInfos() { double carrierFrequencyMHz = 13758.0; - GnssAntennaInfo.PhaseCenterOffsetCoordinates phaseCenterOffsetCoordinates = new - GnssAntennaInfo.PhaseCenterOffsetCoordinates( + GnssAntennaInfo.PhaseCenterOffset phaseCenterOffset = new + GnssAntennaInfo.PhaseCenterOffset( 4.3d, 1.4d, 2.10d, @@ -256,22 +257,26 @@ public class GnssManagerServiceTest { double[][] phaseCenterVariationCorrectionsMillimeters = new double[10][10]; double[][] phaseCenterVariationCorrectionsUncertaintyMillimeters = new double[10][10]; - GnssAntennaInfo.PhaseCenterVariationCorrections + SphericalCorrections phaseCenterVariationCorrections = - new GnssAntennaInfo.PhaseCenterVariationCorrections( + new SphericalCorrections( phaseCenterVariationCorrectionsMillimeters, phaseCenterVariationCorrectionsUncertaintyMillimeters); double[][] signalGainCorrectionsDbi = new double[10][10]; double[][] signalGainCorrectionsUncertaintyDbi = new double[10][10]; - GnssAntennaInfo.SignalGainCorrections signalGainCorrections = new - GnssAntennaInfo.SignalGainCorrections( + SphericalCorrections signalGainCorrections = new + SphericalCorrections( signalGainCorrectionsDbi, signalGainCorrectionsUncertaintyDbi); List<GnssAntennaInfo> gnssAntennaInfos = new ArrayList(); - gnssAntennaInfos.add(new GnssAntennaInfo(carrierFrequencyMHz, phaseCenterOffsetCoordinates, - phaseCenterVariationCorrections, signalGainCorrections)); + gnssAntennaInfos.add(new GnssAntennaInfo.Builder() + .setCarrierFrequencyMHz(carrierFrequencyMHz) + .setPhaseCenterOffset(phaseCenterOffset) + .setPhaseCenterVariationCorrections(phaseCenterVariationCorrections) + .setSignalGainCorrections(signalGainCorrections) + .build()); return gnssAntennaInfos; } @@ -388,14 +393,6 @@ public class GnssManagerServiceTest { } @Test - public void getGnssCapabilitiesWithoutPermissionsTest() { - disableLocationPermissions(); - - assertThrows(SecurityException.class, - () -> mGnssManagerService.getGnssCapabilities("com.android.server")); - } - - @Test public void getGnssCapabilitiesWithPermissionsTest() { final long mGnssCapabilities = 23132L; when(mMockGnssCapabilitiesProvider.getGnssCapabilities()).thenReturn(mGnssCapabilities); diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt index ef1294819f34..063cd5dacc93 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt +++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt @@ -16,8 +16,8 @@ package com.android.server.om -import android.content.pm.parsing.AndroidPackage import android.net.Uri +import com.android.server.pm.parsing.pkg.AndroidPackage import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -196,11 +196,13 @@ class OverlayReferenceMapperTests { whenever(packageName) { "$TARGET_PACKAGE_NAME$increment" } whenever(overlayables) { mapOf("overlayableName$increment" to ACTOR_NAME) } whenever(toString()) { "Package{$packageName}" } + whenever(isOverlay) { false } } private fun mockOverlay(increment: Int = 0) = mockThrowOnUnmocked<AndroidPackage> { whenever(packageName) { "$OVERLAY_PACKAGE_NAME$increment" } whenever(overlayables) { emptyMap<String, String>() } whenever(toString()) { "Package{$packageName}" } + whenever(isOverlay) { true } } } diff --git a/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java b/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java index b614a4f91d28..443718d94be6 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java @@ -21,11 +21,16 @@ import static com.android.server.people.data.TestUtils.timestamp; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.content.Context; + +import androidx.test.InstrumentationRegistry; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.io.File; import java.util.List; @RunWith(JUnit4.class) @@ -60,11 +65,16 @@ public final class AggregateEventHistoryImplTest { EventHistoryImpl.Injector injector = new EventHistoryImplInjector(); - mEventHistory1 = new EventHistoryImpl(injector); + Context ctx = InstrumentationRegistry.getContext(); + File testDir = new File(ctx.getCacheDir(), "testdir"); + MockScheduledExecutorService mockScheduledExecutorService = + new MockScheduledExecutorService(); + + mEventHistory1 = new EventHistoryImpl(injector, testDir, mockScheduledExecutorService); mEventHistory1.addEvent(E1); mEventHistory1.addEvent(E2); - mEventHistory2 = new EventHistoryImpl(injector); + mEventHistory2 = new EventHistoryImpl(injector, testDir, mockScheduledExecutorService); mEventHistory2.addEvent(E3); mEventHistory2.addEvent(E4); } diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java index 5e104a5210d7..f73a4b5776b6 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java @@ -56,7 +56,6 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; -import android.content.pm.parsing.AndroidPackage; import android.database.ContentObserver; import android.net.Uri; import android.os.CancellationSignal; @@ -73,6 +72,7 @@ import android.util.Range; import com.android.internal.app.ChooserActivity; import com.android.internal.content.PackageMonitor; import com.android.server.LocalServices; +import com.android.server.pm.parsing.pkg.AndroidPackage; import org.junit.After; import org.junit.Before; diff --git a/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java b/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java index 43e1001f2aee..825ca1065e73 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java @@ -21,18 +21,27 @@ import static com.android.server.people.data.TestUtils.timestamp; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.content.Context; +import android.os.FileUtils; +import android.text.format.DateUtils; + +import androidx.test.InstrumentationRegistry; + +import com.google.android.collect.Lists; import com.google.android.collect.Sets; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.io.File; import java.util.List; +import java.util.Map; @RunWith(JUnit4.class) public final class EventHistoryImplTest { - private static final long CURRENT_TIMESTAMP = timestamp("01-30 18:50"); private static final Event E1 = new Event(timestamp("01-06 05:26"), @@ -41,26 +50,48 @@ public final class EventHistoryImplTest { Event.TYPE_NOTIFICATION_OPENED); private static final Event E3 = new Event(timestamp("01-30 03:06"), Event.TYPE_SHARE_IMAGE); - private static final Event E4 = new Event(timestamp("01-30 18:14"), + private static final Event E4 = new Event(timestamp("01-30 16:14"), + Event.TYPE_SMS_INCOMING); + private static final Event E5 = new Event(timestamp("01-30 18:30"), Event.TYPE_SMS_INCOMING); + private static final EventIndex.Injector EVENT_INDEX_INJECTOR = new EventIndex.Injector() { + @Override + long currentTimeMillis() { + return CURRENT_TIMESTAMP; + } + }; + private static final EventHistoryImpl.Injector EVENT_HISTORY_INJECTOR = + new EventHistoryImpl.Injector() { + @Override + EventIndex createEventIndex() { + return new EventIndex(EVENT_INDEX_INJECTOR); + } + + @Override + long currentTimeMillis() { + return CURRENT_TIMESTAMP; + } + }; + private EventHistoryImpl mEventHistory; + private File mCacheDir; + private File mFile; + private MockScheduledExecutorService mMockScheduledExecutorService; @Before public void setUp() { - EventIndex.Injector eventIndexInjector = new EventIndex.Injector() { - @Override - long currentTimeMillis() { - return CURRENT_TIMESTAMP; - } - }; - EventHistoryImpl.Injector eventHistoryInjector = new EventHistoryImpl.Injector() { - @Override - EventIndex createEventIndex() { - return new EventIndex(eventIndexInjector); - } - }; - mEventHistory = new EventHistoryImpl(eventHistoryInjector); + Context ctx = InstrumentationRegistry.getContext(); + mCacheDir = ctx.getCacheDir(); + mFile = new File(mCacheDir, "testdir"); + mMockScheduledExecutorService = new MockScheduledExecutorService(); + mEventHistory = new EventHistoryImpl(EVENT_HISTORY_INJECTOR, mFile, + mMockScheduledExecutorService); + } + + @After + public void tearDown() { + FileUtils.deleteContentsAndDir(mFile); } @Test @@ -115,4 +146,105 @@ public final class EventHistoryImplTest { Sets.newArraySet(Event.TYPE_SHARE_IMAGE), 0L, Long.MAX_VALUE); assertEquals(1, events.size()); } + + @Test + public void testPersistenceAndRestoration() { + mEventHistory.addEvent(E1); + mEventHistory.addEvent(E2); + mEventHistory.addEvent(E3); + mEventHistory.addEvent(E4); + mEventHistory.addEvent(E5); + + // futures of events and event index flush. + long futuresExecuted = mMockScheduledExecutorService.fastForwardTime( + 3L * DateUtils.MINUTE_IN_MILLIS); + assertEquals(2, futuresExecuted); + + EventIndex indexBeforePowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES); + + resetAndLoadEventHistory(); + + List<Event> events = mEventHistory.queryEvents(Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE); + assertEquals(2, events.size()); + assertTrue(events.containsAll(Lists.newArrayList(E4, E5))); + + EventIndex indexAfterPowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES); + assertEquals(indexBeforePowerOff, indexAfterPowerOff); + } + + @Test + public void testMimicDevicePowerOff() { + mEventHistory.addEvent(E1); + mEventHistory.addEvent(E2); + mEventHistory.addEvent(E3); + mEventHistory.addEvent(E4); + mEventHistory.addEvent(E5); + mEventHistory.saveToDisk(); + + EventIndex indexBeforePowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES); + + // Ensure that futures were cancelled and the immediate flush occurred. + assertEquals(0, mMockScheduledExecutorService.getFutures().size()); + + // Expect to see 2 executes from #saveToDisk, one for events and another for index. + assertEquals(2, mMockScheduledExecutorService.getExecutes().size()); + + resetAndLoadEventHistory(); + + List<Event> events = mEventHistory.queryEvents(Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE); + assertEquals(2, events.size()); + assertTrue(events.containsAll(Lists.newArrayList(E4, E5))); + + EventIndex indexAfterPowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES); + assertEquals(indexBeforePowerOff, indexAfterPowerOff); + } + + @Test + public void testOnDestroy() { + mEventHistory.addEvent(E1); + mEventHistory.addEvent(E2); + mEventHistory.addEvent(E3); + mEventHistory.addEvent(E4); + mEventHistory.addEvent(E5); + mEventHistory.saveToDisk(); + + mEventHistory.onDestroy(); + + List<Event> events = mEventHistory.queryEvents(Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE); + assertTrue(events.isEmpty()); + + EventIndex index = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES); + assertTrue(index.isEmpty()); + } + + @Test + public void testEventHistoriesImplFromDisk() { + mEventHistory.addEvent(E1); + mEventHistory.addEvent(E2); + mEventHistory.addEvent(E3); + mEventHistory.addEvent(E4); + mEventHistory.addEvent(E5); + mEventHistory.saveToDisk(); + + EventIndex indexBefore = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES); + + Map<String, EventHistoryImpl> map = EventHistoryImpl.eventHistoriesImplFromDisk( + EVENT_HISTORY_INJECTOR, mCacheDir, mMockScheduledExecutorService); + assertEquals(1, map.size()); + assertTrue(map.containsKey("testdir")); + + List<Event> events = map.get("testdir").queryEvents(Event.ALL_EVENT_TYPES, 0L, + Long.MAX_VALUE); + assertEquals(2, events.size()); + assertTrue(events.containsAll(Lists.newArrayList(E4, E5))); + + EventIndex indexAfter = map.get("testdir").getEventIndex(Event.ALL_EVENT_TYPES); + assertEquals(indexBefore, indexAfter); + } + + private void resetAndLoadEventHistory() { + mEventHistory = new EventHistoryImpl(EVENT_HISTORY_INJECTOR, mFile, + mMockScheduledExecutorService); + mEventHistory.loadFromDisk(); + } } diff --git a/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java b/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java index 8b8ba1247a4b..aecbc8d031e1 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java +++ b/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java @@ -54,8 +54,8 @@ class MockScheduledExecutorService implements ScheduledExecutorService { long totalExecuted = 0; for (MockScheduledFuture<?> future : futuresCopy) { if (future.getDelay() < mTimeElapsedMillis) { - future.getCommand().run(); - mExecutes.add(future.getCommand()); + future.getRunnable().run(); + mExecutes.add(future.getRunnable()); totalExecuted += 1; } else { mFutures.add(future); @@ -96,7 +96,8 @@ class MockScheduledExecutorService implements ScheduledExecutorService { @Override public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { - throw new UnsupportedOperationException(); + Preconditions.checkState(unit == TimeUnit.MILLISECONDS); + return new MockScheduledFuture<>(command, period, unit); } @Override @@ -132,7 +133,13 @@ class MockScheduledExecutorService implements ScheduledExecutorService { @Override public <T> Future<T> submit(Callable<T> task) { - throw new UnsupportedOperationException(); + MockScheduledFuture<T> future = new MockScheduledFuture<>(task, 0, TimeUnit.MILLISECONDS); + try { + future.getCallable().call(); + } catch (Exception e) { + e.printStackTrace(); + } + return future; } @Override @@ -141,11 +148,11 @@ class MockScheduledExecutorService implements ScheduledExecutorService { } @Override - public Future<?> submit(Runnable command) { - mExecutes.add(command); - MockScheduledFuture<?> future = new MockScheduledFuture<>(command, 0, + public Future<?> submit(Runnable runnable) { + mExecutes.add(runnable); + MockScheduledFuture<?> future = new MockScheduledFuture<>(runnable, 0, TimeUnit.MILLISECONDS); - future.getCommand().run(); + future.getRunnable().run(); return future; } @@ -181,12 +188,22 @@ class MockScheduledExecutorService implements ScheduledExecutorService { class MockScheduledFuture<V> implements ScheduledFuture<V> { - private final Runnable mCommand; + private final Runnable mRunnable; + private final Callable<V> mCallable; private final long mDelay; private boolean mCancelled = false; - MockScheduledFuture(Runnable command, long delay, TimeUnit timeUnit) { - mCommand = command; + MockScheduledFuture(Runnable runnable, long delay, TimeUnit timeUnit) { + this(runnable, null, delay); + } + + MockScheduledFuture(Callable<V> callable, long delay, TimeUnit timeUnit) { + this(null, callable, delay); + } + + private MockScheduledFuture(Runnable runnable, Callable<V> callable, long delay) { + mCallable = callable; + mRunnable = runnable; mDelay = delay; } @@ -194,8 +211,12 @@ class MockScheduledExecutorService implements ScheduledExecutorService { return mDelay; } - public Runnable getCommand() { - return mCommand; + public Runnable getRunnable() { + return mRunnable; + } + + public Callable<V> getCallable() { + return mCallable; } @Override diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java index d444466cdef5..418067fd14f8 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java @@ -16,6 +16,8 @@ package com.android.server.people.data; +import static com.android.server.people.data.TestUtils.timestamp; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -62,7 +64,8 @@ public final class UsageStatsQueryHelperTest { private static final LocusId LOCUS_ID_1 = new LocusId("locus_1"); private static final LocusId LOCUS_ID_2 = new LocusId("locus_2"); - @Mock private UsageStatsManagerInternal mUsageStatsManagerInternal; + @Mock + private UsageStatsManagerInternal mUsageStatsManagerInternal; private TestPackageData mPackageData; private UsageStatsQueryHelper mHelper; @@ -233,7 +236,7 @@ public final class UsageStatsQueryHelperTest { private static class TestPackageData extends PackageData { private final TestConversationStore mConversationStore; - private final TestEventStore mEventStore = new TestEventStore(); + private final TestEventStore mEventStore; TestPackageData(@NonNull String packageName, @UserIdInt int userId, @NonNull Predicate<String> isDefaultDialerPredicate, @@ -244,6 +247,7 @@ public final class UsageStatsQueryHelperTest { scheduledExecutorService, rootDir, helper); mConversationStore = new TestConversationStore(rootDir, scheduledExecutorService, helper); + mEventStore = new TestEventStore(rootDir, scheduledExecutorService); } @Override @@ -261,8 +265,31 @@ public final class UsageStatsQueryHelperTest { private static class TestEventStore extends EventStore { - private final EventHistoryImpl mShortcutEventHistory = new TestEventHistoryImpl(); - private final EventHistoryImpl mLocusEventHistory = new TestEventHistoryImpl(); + private static final long CURRENT_TIMESTAMP = timestamp("01-30 18:50"); + private static final EventIndex.Injector EVENT_INDEX_INJECTOR = new EventIndex.Injector() { + @Override + long currentTimeMillis() { + return CURRENT_TIMESTAMP; + } + }; + private static final EventHistoryImpl.Injector EVENT_HISTORY_INJECTOR = + new EventHistoryImpl.Injector() { + @Override + EventIndex createEventIndex() { + return new EventIndex(EVENT_INDEX_INJECTOR); + } + }; + + private final EventHistoryImpl mShortcutEventHistory; + private final EventHistoryImpl mLocusEventHistory; + + TestEventStore(File rootDir, ScheduledExecutorService scheduledExecutorService) { + super(rootDir, scheduledExecutorService); + mShortcutEventHistory = new TestEventHistoryImpl(EVENT_HISTORY_INJECTOR, rootDir, + scheduledExecutorService); + mLocusEventHistory = new TestEventHistoryImpl(EVENT_HISTORY_INJECTOR, rootDir, + scheduledExecutorService); + } @Override @NonNull @@ -280,6 +307,11 @@ public final class UsageStatsQueryHelperTest { private final List<Event> mEvents = new ArrayList<>(); + TestEventHistoryImpl(Injector injector, File rootDir, + ScheduledExecutorService scheduledExecutorService) { + super(injector, rootDir, scheduledExecutorService); + } + @Override @NonNull public List<Event> queryEvents(Set<Integer> eventTypes, long startTime, long endTime) { diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index 9670658d4e45..5d5c71471aec 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -29,12 +29,10 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageParser; import android.content.pm.Signature; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; -import android.content.pm.parsing.PackageImpl; import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedProvider; import android.os.Build; import android.os.Process; import android.platform.test.annotations.Presubmit; @@ -44,6 +42,9 @@ import android.util.ArraySet; import androidx.annotation.NonNull; import com.android.server.om.OverlayReferenceMapper; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; import org.junit.Before; import org.junit.Test; @@ -74,7 +75,7 @@ public class AppsFilterTest { private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>(); private static ParsingPackage pkg(String packageName) { - return PackageImpl.forParsing(packageName) + return PackageImpl.forTesting(packageName) .setTargetSdkVersion(Build.VERSION_CODES.R); } @@ -113,7 +114,7 @@ public class AppsFilterTest { ParsedActivity activity = new ParsedActivity(); activity.setPackageName(packageName); for (IntentFilter filter : filters) { - final ParsedActivityIntentInfo info = new ParsedActivityIntentInfo(packageName, null); + final ParsedIntentInfo info = new ParsedIntentInfo(); if (filter.countActions() > 0) { filter.actionsIterator().forEachRemaining(info::addAction); } @@ -127,7 +128,7 @@ public class AppsFilterTest { filter.schemesIterator().forEachRemaining(info::addDataScheme); } activity.addIntent(info); - activity.exported = true; + activity.setExported(true); } return pkg(packageName) @@ -135,7 +136,7 @@ public class AppsFilterTest { } private static ParsingPackage pkgWithProvider(String packageName, String authority) { - ComponentParseUtils.ParsedProvider provider = new ComponentParseUtils.ParsedProvider(); + ParsedProvider provider = new ParsedProvider(); provider.setPackageName(packageName); provider.setExported(true); provider.setAuthority(authority); @@ -437,7 +438,7 @@ public class AppsFilterTest { ParsingPackage target = pkg("com.some.package.target") .addOverlayable("overlayableName", actorName); ParsingPackage overlay = pkg("com.some.package.overlay") - .setIsOverlay(true) + .setOverlay(true) .setOverlayTarget(target.getPackageName()) .setOverlayTargetName("overlayableName"); ParsingPackage actor = pkg("com.some.package.actor"); @@ -499,7 +500,7 @@ public class AppsFilterTest { ParsingPackage target = pkg("com.some.package.target") .addOverlayable("overlayableName", actorName); ParsingPackage overlay = pkg("com.some.package.overlay") - .setIsOverlay(true) + .setOverlay(true) .setOverlayTarget(target.getPackageName()) .setOverlayTargetName("overlayableName"); ParsingPackage actorOne = pkg("com.some.package.actor.one"); @@ -618,7 +619,7 @@ public class AppsFilterTest { private PackageSetting simulateAddPackage(AppsFilter filter, ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) { - AndroidPackage newPkg = newPkgBuilder.hideAsParsed().hideAsFinal(); + AndroidPackage newPkg = ((ParsedPackage) newPkgBuilder.hideAsParsed()).hideAsFinal(); final PackageSettingBuilder settingBuilder = new PackageSettingBuilder() .setPackage(newPkg) diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index df2b3efeb94c..6c769485f6ad 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -562,6 +562,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) { return true; } + + @Override + boolean injectHasInteractAcrossUsersFullPermission(int callingPid, int callingUid) { + return false; + } } protected class LauncherAppsTestable extends LauncherApps { diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index 56ac7c55443e..d2ec50001789 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import android.annotation.NonNull; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; @@ -31,32 +32,34 @@ import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; -import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils; -import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; -import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; -import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; -import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; -import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; -import android.content.pm.parsing.ComponentParseUtils.ParsedService; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.PackageInfoUtils; -import android.content.pm.parsing.ParsedPackage; import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.component.ParsedActivity; +import android.content.pm.parsing.component.ParsedComponent; +import android.content.pm.parsing.component.ParsedInstrumentation; +import android.content.pm.parsing.component.ParsedIntentInfo; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.content.pm.parsing.component.ParsedProvider; +import android.content.pm.parsing.component.ParsedService; import android.os.Bundle; import android.os.Parcel; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; +import android.util.DisplayMetrics; +import androidx.annotation.Nullable; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.ArrayUtils; +import com.android.server.pm.parsing.PackageCacher; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; import org.junit.Before; import org.junit.Rule; @@ -70,12 +73,12 @@ import java.lang.reflect.Array; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +@Presubmit @RunWith(AndroidJUnit4.class) @MediumTest public class PackageParserTest { @@ -96,13 +99,13 @@ public class PackageParserTest { @Test public void testParse_noCache() throws Exception { - PackageParser pp = new CachePackageNameParser(); - ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, + CachePackageNameParser pp = new CachePackageNameParser(null, false, null, null, null); + ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); assertNotNull(pkg); pp.setCacheDir(mTmpDir); - pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, + pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); assertNotNull(pkg); @@ -113,39 +116,37 @@ public class PackageParserTest { @Test public void testParse_withCache() throws Exception { - PackageParser pp = new CachePackageNameParser(); + CachePackageNameParser pp = new CachePackageNameParser(null, false, null, null, null); pp.setCacheDir(mTmpDir); // The first parse will write this package to the cache. - pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); + pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); // Now attempt to parse the package again, should return the // cached result. - ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, + ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); assertEquals("cache_android", pkg.getPackageName()); // Try again, with useCaches == false, shouldn't return the parsed // result. - pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); + pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); assertEquals("android", pkg.getPackageName()); // We haven't set a cache directory here : the parse should still succeed, // just not using the cached results. - pp = new CachePackageNameParser(); - pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); + pp = new CachePackageNameParser(null, false, null, null, null); + pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); assertEquals("android", pkg.getPackageName()); - pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); + pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); assertEquals("android", pkg.getPackageName()); } @Test public void test_serializePackage() throws Exception { - PackageParser pp = new PackageParser(); - pp.setCacheDir(mTmpDir); - - ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, + PackageParser2 pp = new PackageParser2(null, false, null, mTmpDir, null); + ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); Parcel p = Parcel.obtain(); @@ -161,7 +162,7 @@ public class PackageParserTest { @SmallTest @Presubmit public void test_roundTripKnownFields() throws Exception { - ParsingPackage pkg = PackageImpl.forParsing("foo"); + ParsingPackage pkg = PackageImpl.forTesting("foo"); setKnownFields(pkg); Parcel p = Parcel.obtain(); @@ -174,7 +175,7 @@ public class PackageParserTest { @Test public void test_stringInterning() throws Exception { - ParsingPackage pkg = PackageImpl.forParsing("foo"); + ParsingPackage pkg = PackageImpl.forTesting("foo"); setKnownFields(pkg); Parcel p = Parcel.obtain(); @@ -212,19 +213,44 @@ public class PackageParserTest { * A trivial subclass of package parser that only caches the package name, and throws away * all other information. */ - public static class CachePackageNameParser extends PackageParser { - @Override - public byte[] toCacheEntry(ParsedPackage pkg) { - return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8); + public static class CachePackageNameParser extends PackageParser2 { + + CachePackageNameParser(String[] separateProcesses, boolean onlyCoreApps, + DisplayMetrics displayMetrics, @Nullable File cacheDir, + PackageParser2.Callback callback) { + super(separateProcesses, onlyCoreApps, displayMetrics, cacheDir, callback); + if (cacheDir != null) { + setCacheDir(cacheDir); + } } - @Override - public ParsedPackage fromCacheEntry(byte[] cacheEntry) { - return PackageImpl.forParsing(new String(cacheEntry, StandardCharsets.UTF_8)) - .hideAsParsed(); + void setCacheDir(@NonNull File cacheDir) { + this.mCacher = new PackageCacher(cacheDir) { + @Override + public byte[] toCacheEntry(ParsedPackage pkg) { + return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8); + } + + @Override + public ParsedPackage fromCacheEntry(byte[] cacheEntry) { + return ((ParsedPackage) PackageImpl.forTesting( + new String(cacheEntry, StandardCharsets.UTF_8)) + .hideAsParsed()); + } + }; } } + private static PackageSetting mockPkgSetting(AndroidPackage pkg) { + return new PackageSetting(pkg.getPackageName(), pkg.getRealPackage(), + new File(pkg.getCodePath()), new File(pkg.getCodePath()), null, + pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(), + null, pkg.getVersionCode(), + PackageInfoUtils.appInfoFlags(pkg, null), + PackageInfoUtils.appInfoPrivateFlags(pkg, null), + pkg.getSharedUserLabel(), null, null, null); + } + // NOTE: The equality assertions below are based on code autogenerated by IntelliJ. public static void assertPackagesEqual(AndroidPackage a, AndroidPackage b) { @@ -232,7 +258,6 @@ public class PackageParserTest { assertEquals(a.isBaseHardwareAccelerated(), b.isBaseHardwareAccelerated()); assertEquals(a.getVersionCode(), b.getVersionCode()); assertEquals(a.getSharedUserLabel(), b.getSharedUserLabel()); - assertEquals(a.getPreferredOrder(), b.getPreferredOrder()); assertEquals(a.getInstallLocation(), b.getInstallLocation()); assertEquals(a.isCoreApp(), b.isCoreApp()); assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers()); @@ -249,9 +274,9 @@ public class PackageParserTest { assertArrayEquals(a.getSplitFlags(), b.getSplitFlags()); PackageInfo aInfo = PackageInfoUtils.generate(a, new int[]{}, 0, 0, 0, - Collections.emptySet(), new PackageUserState(), 0); + Collections.emptySet(), new PackageUserState(), 0, mockPkgSetting(a)); PackageInfo bInfo = PackageInfoUtils.generate(b, new int[]{}, 0, 0, 0, - Collections.emptySet(), new PackageUserState(), 0); + Collections.emptySet(), new PackageUserState(), 0, mockPkgSetting(b)); assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); assertEquals(ArrayUtils.size(a.getPermissions()), ArrayUtils.size(b.getPermissions())); @@ -298,15 +323,13 @@ public class PackageParserTest { assertEquals(a.getLibraryNames(), b.getLibraryNames()); assertEquals(a.getUsesLibraries(), b.getUsesLibraries()); assertEquals(a.getUsesOptionalLibraries(), b.getUsesOptionalLibraries()); - assertArrayEquals(a.getUsesLibraryFiles(), b.getUsesLibraryFiles()); assertEquals(a.getOriginalPackages(), b.getOriginalPackages()); assertEquals(a.getRealPackage(), b.getRealPackage()); assertEquals(a.getAdoptPermissions(), b.getAdoptPermissions()); - assertBundleApproximateEquals(a.getAppMetaData(), b.getAppMetaData()); + assertBundleApproximateEquals(a.getMetaData(), b.getMetaData()); assertEquals(a.getVersionName(), b.getVersionName()); assertEquals(a.getSharedUserId(), b.getSharedUserId()); assertArrayEquals(a.getSigningDetails().signatures, b.getSigningDetails().signatures); - assertArrayEquals(a.getLastPackageUsageTimeInMills(), b.getLastPackageUsageTimeInMills()); assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType()); assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType()); assertEquals(a.getOverlayTarget(), b.getOverlayTarget()); @@ -317,7 +340,6 @@ public class PackageParserTest { assertEquals(a.getSigningDetails().publicKeys, b.getSigningDetails().publicKeys); assertEquals(a.getUpgradeKeySets(), b.getUpgradeKeySets()); assertEquals(a.getKeySetMapping(), b.getKeySetMapping()); - assertEquals(a.getCpuAbiOverride(), b.getCpuAbiOverride()); assertArrayEquals(a.getRestrictUpdateHash(), b.getRestrictUpdateHash()); } @@ -333,44 +355,42 @@ public class PackageParserTest { assertEquals(a.toString(), b.toString()); } - private static void assertComponentsEqual(ParsedComponent<?> a, - ParsedComponent<?> b) { - assertEquals(a.className, b.className); + private static void assertComponentsEqual(ParsedComponent a, ParsedComponent b) { + assertEquals(a.getName(), b.getName()); assertBundleApproximateEquals(a.getMetaData(), b.getMetaData()); assertEquals(a.getComponentName(), b.getComponentName()); - if (a.intents != null && b.intents != null) { - assertEquals(a.intents.size(), b.intents.size()); - } else if (a.intents == null || b.intents == null) { + if (a.getIntents() != null && b.getIntents() != null) { + assertEquals(a.getIntents().size(), b.getIntents().size()); + } else if (a.getIntents() == null || b.getIntents() == null) { return; } - for (int i = 0; i < a.intents.size(); ++i) { - ParsedIntentInfo aIntent = a.intents.get(i); - ParsedIntentInfo bIntent = b.intents.get(i); + for (int i = 0; i < a.getIntents().size(); ++i) { + ParsedIntentInfo aIntent = a.getIntents().get(i); + ParsedIntentInfo bIntent = b.getIntents().get(i); - assertEquals(aIntent.hasDefault, bIntent.hasDefault); - assertEquals(aIntent.labelRes, bIntent.labelRes); - assertEquals(aIntent.nonLocalizedLabel, bIntent.nonLocalizedLabel); - assertEquals(aIntent.icon, bIntent.icon); + assertEquals(aIntent.isHasDefault(), bIntent.isHasDefault()); + assertEquals(aIntent.getLabelRes(), bIntent.getLabelRes()); + assertEquals(aIntent.getNonLocalizedLabel(), bIntent.getNonLocalizedLabel()); + assertEquals(aIntent.getIcon(), bIntent.getIcon()); } } - private static void assertPermissionsEqual(ParsedPermission a, - ParsedPermission b) { + private static void assertPermissionsEqual(ParsedPermission a, ParsedPermission b) { assertComponentsEqual(a, b); - assertEquals(a.tree, b.tree); + assertEquals(a.isTree(), b.isTree()); // Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform // a full structural equality here because the code that serializes them isn't parser // specific and is tested elsewhere. assertEquals(a.getProtection(), b.getProtection()); assertEquals(a.getGroup(), b.getGroup()); - assertEquals(a.flags, b.flags); + assertEquals(a.getFlags(), b.getFlags()); - if (a.parsedPermissionGroup != null && b.parsedPermissionGroup != null) { - assertPermissionGroupsEqual(a.parsedPermissionGroup, b.parsedPermissionGroup); - } else if (a.parsedPermissionGroup != null || b.parsedPermissionGroup != null) { + if (a.getParsedPermissionGroup() != null && b.getParsedPermissionGroup() != null) { + assertPermissionGroupsEqual(a.getParsedPermissionGroup(), b.getParsedPermissionGroup()); + } else if (a.getParsedPermissionGroup() != null || b.getParsedPermissionGroup() != null) { throw new AssertionError(); } } @@ -382,6 +402,8 @@ public class PackageParserTest { // Sanity check for InstrumentationInfo. assertEquals(a.getTargetPackage(), b.getTargetPackage()); assertEquals(a.getTargetProcesses(), b.getTargetProcesses()); + assertEquals(a.isHandleProfiling(), b.isHandleProfiling()); + assertEquals(a.isFunctionalTest(), b.isFunctionalTest()); } private static void assertServicesEqual( @@ -393,10 +415,10 @@ public class PackageParserTest { assertComponentsEqual(a, b); // Sanity check for ServiceInfo. - ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0, new PackageUserState(), - 0); - ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0, new PackageUserState(), - 0); + ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0, + new PackageUserState(), 0, mockPkgSetting(aPkg)); + ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0, + new PackageUserState(), 0, mockPkgSetting(bPkg)); assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); assertEquals(a.getName(), b.getName()); } @@ -411,9 +433,9 @@ public class PackageParserTest { // Sanity check for ProviderInfo ProviderInfo aInfo = PackageInfoUtils.generateProviderInfo(aPkg, a, 0, - new PackageUserState(), 0); + new PackageUserState(), 0, mockPkgSetting(aPkg)); ProviderInfo bInfo = PackageInfoUtils.generateProviderInfo(bPkg, b, 0, - new PackageUserState(), 0); + new PackageUserState(), 0, mockPkgSetting(bPkg)); assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); assertEquals(a.getName(), b.getName()); } @@ -428,9 +450,9 @@ public class PackageParserTest { // Sanity check for ActivityInfo. ActivityInfo aInfo = PackageInfoUtils.generateActivityInfo(aPkg, a, 0, - new PackageUserState(), 0); + new PackageUserState(), 0, mockPkgSetting(aPkg)); ActivityInfo bInfo = PackageInfoUtils.generateActivityInfo(bPkg, b, 0, - new PackageUserState(), 0); + new PackageUserState(), 0, mockPkgSetting(bPkg)); assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); assertEquals(a.getName(), b.getName()); } @@ -441,7 +463,7 @@ public class PackageParserTest { // Sanity check for PermissionGroupInfo. assertEquals(a.getName(), b.getName()); - assertEquals(a.descriptionRes, b.descriptionRes); + assertEquals(a.getDescriptionRes(), b.getDescriptionRes()); } private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) { @@ -494,12 +516,11 @@ public class PackageParserTest { bundle.putString("key", "value"); ParsedPermission permission = new ParsedPermission(); - permission.parsedPermissionGroup = new ParsedPermissionGroup(); + permission.setParsedPermissionGroup(new ParsedPermissionGroup()); - pkg.setBaseRevisionCode(100) + ((ParsedPackage) pkg.setBaseRevisionCode(100) .setBaseHardwareAccelerated(true) .setSharedUserLabel(100) - .setPreferredOrder(100) .setInstallLocation(100) .setRequiredForAllUsers(true) .asSplit( @@ -510,7 +531,6 @@ public class PackageParserTest { ) .setUse32BitAbi(true) .setVolumeUuid("foo3") - .setCodePath("foo4") .addPermission(permission) .addPermissionGroup(new ParsedPermissionGroup()) .addActivity(new ParsedActivity()) @@ -532,7 +552,7 @@ public class PackageParserTest { .addOriginalPackage("foo14") .setRealPackage("foo15") .addAdoptPermission("foo16") - .setAppMetaData(bundle) + .setMetaData(bundle) .setVersionName("foo17") .setSharedUserId("foo18") .setSigningDetails( @@ -547,8 +567,7 @@ public class PackageParserTest { .setOverlayTarget("foo21") .setOverlayPriority(100) .setUpgradeKeySets(new ArraySet<>()) - .addPreferredActivityFilter( - new ComponentParseUtils.ParsedActivityIntentInfo("foo", "className")) + .addPreferredActivityFilter("className", new ParsedIntentInfo()) .addConfigPreference(new ConfigurationInfo()) .addReqFeature(new FeatureInfo()) .addFeatureGroup(new FeatureGroupInfo()) @@ -559,19 +578,14 @@ public class PackageParserTest { .setOverlayTargetName("foo26") .setVisibleToInstantApps(true) .setSplitHasCode(0, true) - .hideAsParsed() + .hideAsParsed()) .setBaseCodePath("foo5") + .setCodePath("foo4") .setVersionCode(100) - .setCpuAbiOverride("foo22") .setRestrictUpdateHash(new byte[16]) .setVersionCodeMajor(100) .setCoreApp(true) - .hideAsFinal() - .mutate() - .setUsesLibraryInfos(Arrays.asList( - new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null) - )) - .setUsesLibraryFiles(new String[]{"foo13"}); + .hideAsFinal(); } private static void assertAllFieldsExist(ParsedPackage pkg) throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java index 841cea2703ec..d12ea89469b7 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java @@ -18,10 +18,11 @@ package com.android.server.pm; import android.content.pm.PackageParser; import android.content.pm.PackageUserState; -import android.content.pm.parsing.AndroidPackage; import android.util.ArraySet; import android.util.SparseArray; +import com.android.server.pm.parsing.pkg.AndroidPackage; + import java.io.File; import java.util.Map; diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java index da5986f71f11..9d3ac1720930 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java @@ -17,11 +17,14 @@ package com.android.server.pm; import android.content.pm.PackageParser; -import android.content.pm.parsing.ParsedPackage; +import android.platform.test.annotations.Presubmit; import android.util.Log; import androidx.test.runner.AndroidJUnit4; +import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.parsing.pkg.ParsedPackage; + import junit.framework.Assert; import org.junit.Before; @@ -36,6 +39,7 @@ import java.util.concurrent.ExecutorService; /** * Tests for {@link ParallelPackageParser} */ +@Presubmit @RunWith(AndroidJUnit4.class) public class ParallelPackageParserTest { private static final String TAG = ParallelPackageParserTest.class.getSimpleName(); @@ -44,7 +48,7 @@ public class ParallelPackageParserTest { @Before public void setUp() { - mParser = new TestParallelPackageParser(new PackageParser(), + mParser = new TestParallelPackageParser(new PackageParser2(null, false, null, null, null), ParallelPackageParser.makeExecutorService()); } @@ -72,7 +76,7 @@ public class ParallelPackageParserTest { private class TestParallelPackageParser extends ParallelPackageParser { - TestParallelPackageParser(PackageParser packageParser, ExecutorService executorService) { + TestParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) { super(packageParser, executorService); } diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java index 30108c67d920..efc1c057d8f4 100644 --- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java @@ -22,12 +22,13 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; import android.os.Build; import android.platform.test.annotations.Presubmit; import com.android.server.compat.PlatformCompat; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; import org.junit.Test; import org.junit.runner.RunWith; @@ -79,9 +80,9 @@ public class SELinuxMMACTest { } private AndroidPackage makePackage(int targetSdkVersion) { - return PackageImpl.forParsing(PACKAGE_NAME) + return ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(targetSdkVersion) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java index 11f154be688b..12fb400cbdb7 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java @@ -16,10 +16,13 @@ package com.android.server.pm; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ParsedPackage; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.UserHandle; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.ParsedPackage; + class ScanRequestBuilder { private final ParsedPackage mPkg; private AndroidPackage mOldPkg; @@ -32,6 +35,8 @@ class ScanRequestBuilder { private int mScanFlags; private UserHandle mUser; private boolean mIsPlatformPackage; + @Nullable + private String mCpuAbiOverride; ScanRequestBuilder(ParsedPackage pkg) { this.mPkg = pkg; @@ -97,10 +102,16 @@ class ScanRequestBuilder { return this; } + @NonNull + public ScanRequestBuilder setCpuAbiOverride(@Nullable String cpuAbiOverride) { + this.mCpuAbiOverride = cpuAbiOverride; + return this; + } + PackageManagerService.ScanRequest build() { return new PackageManagerService.ScanRequest( mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting, mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage, - mUser); + mUser, mCpuAbiOverride); } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java index 583cf5827367..09f946d4b107 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java @@ -42,9 +42,6 @@ import android.Manifest; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.SharedLibraryInfo; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.PackageInfoUtils; -import android.content.pm.parsing.ParsedPackage; import android.content.pm.parsing.ParsingPackage; import android.content.res.TypedArray; import android.os.Environment; @@ -54,6 +51,10 @@ import android.platform.test.annotations.Presubmit; import android.util.Pair; import com.android.server.compat.PlatformCompat; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; @@ -101,18 +102,18 @@ public class ScanTests { @Before public void setupDefaultAbiBehavior() throws Exception { when(mMockPackageAbiHelper.derivePackageAbi( - any(ParsedPackage.class), nullable(String.class), anyBoolean())) + any(AndroidPackage.class), anyBoolean(), nullable(String.class), anyBoolean())) .thenReturn(new Pair<>( new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"), new PackageAbiHelper.NativeLibraryPaths( "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2"))); when(mMockPackageAbiHelper.getNativeLibraryPaths( - any(ParsedPackage.class), any(File.class))) + any(AndroidPackage.class), any(PackageSetting.class), any(File.class))) .thenReturn(new PackageAbiHelper.NativeLibraryPaths( "getRootDir", true, "getNativeDir", "getNativeDir2" )); when(mMockPackageAbiHelper.getBundledAppAbis( - any(ParsedPackage.class))) + any(AndroidPackage.class))) .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary")); } @@ -223,10 +224,10 @@ public class ScanTests { @Test public void installStaticSharedLibrary() throws Exception { - final ParsedPackage pkg = createBasicPackage("static.lib.pkg") + final ParsedPackage pkg = ((ParsedPackage) createBasicPackage("static.lib.pkg") .setStaticSharedLibName("static.lib") .setStaticSharedLibVersion(123L) - .hideAsParsed() + .hideAsParsed()) .setPackageName("static.lib.pkg.123") .setVersionCodeMajor(1) .setVersionCode(234) @@ -255,10 +256,11 @@ public class ScanTests { @Test public void installDynamicLibraries() throws Exception { - final ParsedPackage pkg = createBasicPackage("dynamic.lib.pkg") + final ParsedPackage pkg = ((ParsedPackage) createBasicPackage( + "dynamic.lib.pkg") .addLibraryName("liba") .addLibraryName("libb") - .hideAsParsed() + .hideAsParsed()) .setVersionCodeMajor(1) .setVersionCode(234) .setBaseCodePath("/some/path.apk") @@ -304,9 +306,9 @@ public class ScanTests { .setVolumeUuid("someUuid") .build(); - final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) - .hideAsParsed() - .setApplicationVolumeUuid(UUID_TWO.toString()); + final ParsedPackage basicPackage = ((ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME) + .setVolumeUuid(UUID_TWO.toString()) + .hideAsParsed()); final PackageManagerService.ScanResult scanResult = executeScan( @@ -321,9 +323,8 @@ public class ScanTests { createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build(); final ParsedPackage basicPackage = - createBasicPackage(DUMMY_PACKAGE_NAME) - .hideAsParsed() - .setCpuAbiOverride("testOverride"); + ((ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME) + .hideAsParsed()); final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder( @@ -341,7 +342,7 @@ public class ScanTests { createBasicPackageSettingBuilder("original.package").build(); final ParsedPackage basicPackage = - createBasicPackage(DUMMY_PACKAGE_NAME) + (ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME) .hideAsParsed(); @@ -411,8 +412,9 @@ public class ScanTests { final PackageManagerService.ScanResult scanResult = executeScan(scanRequest); - assertThat(scanResult.request.parsedPackage.getFlags(), - hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)); + int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage, + scanResult.pkgSetting); + assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)); } @Test @@ -426,14 +428,15 @@ public class ScanTests { true /*isUnderFactoryTest*/, System.currentTimeMillis()); - assertThat(scanResult.request.parsedPackage.getFlags(), - hasFlag(ApplicationInfo.FLAG_FACTORY_TEST)); + int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage, + scanResult.request.pkgSetting); + assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_FACTORY_TEST)); } @Test public void scanSystemApp_isOrphanedTrue() throws Exception { - final ParsedPackage pkg = createBasicPackage(DUMMY_PACKAGE_NAME) - .hideAsParsed() + final ParsedPackage pkg = ((ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME) + .hideAsParsed()) .setSystem(true); final PackageManagerService.ScanRequest scanRequest = @@ -474,10 +477,6 @@ public class ScanTests { System.currentTimeMillis()); } - private static String createResourcePath(String packageName) { - return "/data/app/" + packageName + "-randompath/base.apk"; - } - private static String createCodePath(String packageName) { return "/data/app/" + packageName + "-randompath"; } @@ -486,11 +485,11 @@ public class ScanTests { return new PackageSettingBuilder() .setName(packageName) .setCodePath(createCodePath(packageName)) - .setResourcePath(createResourcePath(packageName)); + .setResourcePath(createCodePath(packageName)); } private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) { - return new ScanRequestBuilder(pkg.hideAsParsed()) + return new ScanRequestBuilder((ParsedPackage) pkg.hideAsParsed()) .setUser(UserHandle.of(0)); } @@ -501,16 +500,15 @@ public class ScanTests { private static ParsingPackage createBasicPackage(String packageName) { // TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps - return new PackageImpl(packageName, null, mock(TypedArray.class), false) - .setCodePath("/data/tmp/randompath") - .setApplicationInfoCodePath(createCodePath(packageName)) - .setApplicationInfoResourcePath(createResourcePath(packageName)) - .setApplicationVolumeUuid(UUID_ONE.toString()) - .setBaseCodePath("/data/tmp/randompath/base.apk") + return (ParsingPackage) ((ParsedPackage) new PackageImpl(packageName, + "/data/tmp/randompath/base.apk", createCodePath(packageName), + mock(TypedArray.class), false) + .setVolumeUuid(UUID_ONE.toString()) .addUsesStaticLibrary("some.static.library") .addUsesStaticLibraryVersion(234L) .addUsesStaticLibrary("some.other.static.library") .addUsesStaticLibraryVersion(456L) + .hideAsParsed()) .setNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib") .setVersionCodeMajor(1) .setVersionCode(2345); @@ -524,7 +522,7 @@ public class ScanTests { assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting); final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo( - pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0); + pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting); assertBasicApplicationInfo(scanResult, applicationInfo); } @@ -537,7 +535,7 @@ public class ScanTests { assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L})); assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage)); assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName)))); - assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName)))); + assertThat(pkgSetting.resourcePath, is(new File(createCodePath(packageName)))); assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345))); } @@ -559,7 +557,7 @@ public class ScanTests { private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) { PackageSetting pkgSetting = scanResult.pkgSetting; final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo( - pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0); + pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting); assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary")); assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary")); @@ -573,7 +571,7 @@ public class ScanTests { private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) { PackageSetting pkgSetting = scanResult.pkgSetting; final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo( - pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0); + pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting); assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir")); assertThat(pkgSetting.legacyNativeLibraryPathString, is("getRootDir")); assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true)); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 2936bdd8501b..56460fb6f0a0 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -379,6 +379,113 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); } + public void testPushDynamicShortcut() { + + setCaller(CALLING_PACKAGE_1, USER_0); + + final ShortcutInfo s1 = makeShortcut("s1"); + final ShortcutInfo s2 = makeShortcut("s2"); + final ShortcutInfo s3 = makeShortcut("s3"); + final ShortcutInfo s4 = makeShortcut("s4"); + + final ShortcutInfo s10 = makeShortcut("s10"); + final ShortcutInfo s11 = makeShortcut("s11"); + final ShortcutInfo s12 = makeShortcut("s12"); + final ShortcutInfo s13 = makeShortcut("s13"); + final ShortcutInfo s14 = makeShortcut("s14"); + + // Test push as first shortcut + mManager.pushDynamicShortcut(s1); + assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1"); + assertEquals(0, getCallerShortcut("s1").getRank()); + + // Test push when other shortcuts exist + assertTrue(mManager.setDynamicShortcuts(list(s1, s2))); + assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1", "s2"); + mManager.pushDynamicShortcut(s3); + assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), + "s1", "s2", "s3"); + assertEquals(0, getCallerShortcut("s3").getRank()); + assertEquals(1, getCallerShortcut("s1").getRank()); + assertEquals(2, getCallerShortcut("s2").getRank()); + + mInjectedCurrentTimeMillis += INTERVAL; // reset + + // Push with set rank + s4.setRank(2); + mManager.pushDynamicShortcut(s4); + assertEquals(2, getCallerShortcut("s4").getRank()); + assertEquals(3, getCallerShortcut("s2").getRank()); + + // Push existing shortcut with set rank + final ShortcutInfo s4_2 = makeShortcut("s4"); + s4_2.setRank(4); + mManager.pushDynamicShortcut(s4_2); + assertEquals(2, getCallerShortcut("s2").getRank()); + assertEquals(3, getCallerShortcut("s4").getRank()); + + mInjectedCurrentTimeMillis += INTERVAL; // reset + + // Test push as last + assertTrue(mManager.addDynamicShortcuts(makeShortcuts("s5", "s6", "s7", "s8", "s9"))); + mManager.pushDynamicShortcut(s10); + assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), + "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10"); + assertEquals(0, getCallerShortcut("s10").getRank()); + assertEquals(1, getCallerShortcut("s5").getRank()); + assertEquals(6, getCallerShortcut("s3").getRank()); + assertEquals(7, getCallerShortcut("s1").getRank()); + assertEquals(8, getCallerShortcut("s2").getRank()); + assertEquals(9, getCallerShortcut("s4").getRank()); + + // Push when max has already reached + mManager.pushDynamicShortcut(s11); + assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), + "s1", "s2", "s3", "s5", "s6", "s7", "s8", "s9", "s10", "s11"); + assertEquals(0, getCallerShortcut("s11").getRank()); + assertEquals(1, getCallerShortcut("s10").getRank()); + assertEquals(9, getCallerShortcut("s2").getRank()); + + mInjectedCurrentTimeMillis += INTERVAL; // reset + + // Push with different activity + s12.setActivity(makeComponent(ShortcutActivity2.class)); + mManager.pushDynamicShortcut(s12); + assertEquals(makeComponent(ShortcutActivity2.class), + getCallerShortcut("s12").getActivity()); + assertEquals(0, getCallerShortcut("s12").getRank()); + + // Push to update shortcut with different activity + final ShortcutInfo s1_2 = makeShortcut("s1"); + s1_2.setActivity(makeComponent(ShortcutActivity2.class)); + s1_2.setRank(1); + mManager.pushDynamicShortcut(s1_2); + assertEquals(0, getCallerShortcut("s12").getRank()); + assertEquals(1, getCallerShortcut("s1").getRank()); + assertEquals(0, getCallerShortcut("s11").getRank()); + assertEquals(1, getCallerShortcut("s10").getRank()); + assertEquals(7, getCallerShortcut("s3").getRank()); + assertEquals(8, getCallerShortcut("s2").getRank()); + + mInjectedCurrentTimeMillis += INTERVAL; // reset + + // Test push when dropped shortcut is cached + s13.setLongLived(); + s13.setRank(100); + mManager.pushDynamicShortcut(s13); + assertEquals(9, getCallerShortcut("s13").getRank()); + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s13"), HANDLE_USER_0); + }); + + mManager.pushDynamicShortcut(s14); + assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), + "s1", "s2", "s3", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s14"); + // Verify s13 stayed as cached + assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), + "s13"); + } + public void testUnlimitedCalls() { setCaller(CALLING_PACKAGE_1, USER_0); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java index 3db832b24236..ce210990ac28 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java @@ -39,8 +39,6 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; import android.os.Looper; import android.os.SystemProperties; import android.os.UserManager; @@ -56,6 +54,9 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.LocalServices; import com.android.server.SystemConfig; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; import org.junit.After; import org.junit.Before; @@ -252,14 +253,14 @@ public class UserSystemPackageInstallerTest { final Set<String> userWhitelist = new ArraySet<>(); userWhitelist.add(packageName1); - final AndroidPackage pkg1 = PackageImpl.forParsing(packageName1) - .hideAsParsed().hideAsFinal(); - final AndroidPackage pkg2 = PackageImpl.forParsing(packageName2) - .hideAsParsed().hideAsFinal(); - final AndroidPackage pkg3 = PackageImpl.forParsing(packageName3) - .hideAsParsed().hideAsFinal(); - final AndroidPackage pkg4 = PackageImpl.forParsing(packageName4) - .hideAsParsed().hideAsFinal(); + final AndroidPackage pkg1 = ((ParsedPackage) PackageImpl.forTesting(packageName1) + .hideAsParsed()).hideAsFinal(); + final AndroidPackage pkg2 = ((ParsedPackage) PackageImpl.forTesting(packageName2) + .hideAsParsed()).hideAsFinal(); + final AndroidPackage pkg3 = ((ParsedPackage) PackageImpl.forTesting(packageName3) + .hideAsParsed()).hideAsFinal(); + final AndroidPackage pkg4 = ((ParsedPackage) PackageImpl.forTesting(packageName4) + .hideAsParsed()).hideAsFinal(); // No implicit whitelist, so only install pkg1. boolean implicit = false; diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java index f5e5e2a13bcf..d69e1b8786b4 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -532,6 +532,61 @@ public class DexManagerTests { assertHasDclInfo(mBarUser0, mBarUser0, secondaries); } + @Test + public void testPrimaryAndSecondaryDexLoad() { + // Foo loads both primary and secondary dexes + List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); + List<String> fooDexes = new ArrayList<>(mFooUser0.getBaseAndSplitDexPaths()); + int primaryCount = fooDexes.size(); + fooDexes.addAll(fooSecondaries); + + notifyDexLoad(mFooUser0, fooDexes, mUser0); + + PackageUseInfo pui = getPackageUseInfo(mFooUser0); + assertIsUsedByOtherApps(mFooUser0, pui, false); + assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); + + // Below we want to verify that the secondary dex files within fooDexes have been correctly + // reported and their class loader contexts were correctly recorded. + // + // In order to achieve this we first use DexoptUtils.processContextForDexLoad to compute the + // class loader contexts for all the dex files. + String[] allClassLoaderContexts = DexoptUtils.processContextForDexLoad( + Arrays.asList(mFooUser0.mClassLoader), + Arrays.asList(String.join(File.pathSeparator, fooDexes))); + // Next we filter out the class loader contexts corresponding to non-secondary dex files. + String[] secondaryClassLoaderContexts = Arrays.copyOfRange(allClassLoaderContexts, + primaryCount, allClassLoaderContexts.length); + assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0, + secondaryClassLoaderContexts); + + assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries); + } + + @Test + public void testNotifySecondary_withSharedLibrary() { + // Foo loads its own secondary files. + List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); + + String contextSuffix = "{PCL[/system/framework/org.apache.http.legacy.jar]}"; + String[] expectedContexts = DexoptUtils.processContextForDexLoad( + Arrays.asList(mFooUser0.mClassLoader), + Arrays.asList(String.join(File.pathSeparator, fooSecondaries))); + for (int i = 0; i < expectedContexts.length; i++) { + expectedContexts[i] += contextSuffix; + } + + notifyDexLoad(mFooUser0, fooSecondaries, expectedContexts, mUser0); + + PackageUseInfo pui = getPackageUseInfo(mFooUser0); + assertIsUsedByOtherApps(mFooUser0, pui, false); + assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); + assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0, + expectedContexts); + + assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries); + } + private void assertSecondaryUse(TestData testData, PackageUseInfo pui, List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId, String[] expectedContexts) { @@ -572,17 +627,43 @@ public class DexManagerTests { // By default, assume a single class loader in the chain. // This makes writing tests much easier. List<String> classLoaders = Arrays.asList(testData.mClassLoader); - List<String> classPaths = (dexPaths == null) - ? Arrays.asList((String) null) - : Arrays.asList(String.join(File.pathSeparator, dexPaths)); + List<String> classPaths = dexPaths != null + ? Arrays.<String>asList(String.join(File.pathSeparator, dexPaths)) : null; notifyDexLoad(testData, classLoaders, classPaths, loaderUserId); } private void notifyDexLoad(TestData testData, List<String> classLoaders, List<String> classPaths, int loaderUserId) { + String[] classLoaderContexts = computeClassLoaderContexts(classLoaders, classPaths); // We call the internal function so any exceptions thrown cause test failures. - mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, classLoaders, - classPaths, testData.mLoaderIsa, loaderUserId); + List<String> dexPaths = classPaths != null + ? Arrays.asList(classPaths.get(0).split(File.pathSeparator)) : Arrays.asList(); + notifyDexLoad(testData, dexPaths, classLoaderContexts, loaderUserId); + } + + private void notifyDexLoad(TestData testData, List<String> dexPaths, + String[] classLoaderContexts, int loaderUserId) { + assertTrue(dexPaths.size() == classLoaderContexts.length); + HashMap<String, String> dexPathMapping = new HashMap<>(dexPaths.size()); + for (int i = 0; i < dexPaths.size(); i++) { + dexPathMapping.put(dexPaths.get(i), classLoaderContexts != null + ? classLoaderContexts[i] : PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT); + } + mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, dexPathMapping, + testData.mLoaderIsa, loaderUserId); + } + + private String[] computeClassLoaderContexts(List<String> classLoaders, + List<String> classPaths) { + if (classPaths == null) { + return new String[0]; + } + String[] results = DexoptUtils.processContextForDexLoad(classLoaders, classPaths); + if (results == null) { + results = new String[classPaths.get(0).split(File.pathSeparator).length]; + Arrays.fill(results, PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT); + } + return results; } private PackageUseInfo getPackageUseInfo(TestData testData) { diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java index 1e0bfb08693f..f87f68d4942f 100644 --- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java @@ -1,5 +1,5 @@ -/** - * Copyright (C) 2018 The Android Open Source Project +/* + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.content.pm.dex; +package com.android.server.pm.dex; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -27,14 +27,17 @@ import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.parsing.ParsedPackage; +import android.content.pm.dex.DexMetadataHelper; import android.os.FileUtils; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.frameworks.coretests.R; +import com.android.frameworks.servicestests.R; +import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.parsing.pkg.ParsedPackage; import org.junit.Assert; import org.junit.Before; @@ -90,13 +93,17 @@ public class DexMetadataHelperTest { return outFile; } + private PackageParser2 makeParser() { + return new PackageParser2(null, false, null, null, null); + } + @Test public void testParsePackageWithDmFileValid() throws IOException, PackageParserException { copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); createDexMetadataFile("install_split_base.apk"); - ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false); + ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false); - Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); + Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg); assertEquals(1, packageDexMetadata.size()); String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath()); assertNotNull(baseDexMetadata); @@ -110,9 +117,9 @@ public class DexMetadataHelperTest { copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); createDexMetadataFile("install_split_base.apk"); createDexMetadataFile("install_split_feature_a.apk"); - ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false); + ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false); - Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); + Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg); assertEquals(2, packageDexMetadata.size()); String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath()); assertNotNull(baseDexMetadata); @@ -129,9 +136,9 @@ public class DexMetadataHelperTest { copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); createDexMetadataFile("install_split_feature_a.apk"); - ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false); + ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false); - Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); + Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg); assertEquals(1, packageDexMetadata.size()); String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]); @@ -145,9 +152,8 @@ public class DexMetadataHelperTest { File invalidDmFile = new File(mTmpDir, "install_split_base.dm"); Files.createFile(invalidDmFile.toPath()); try { - ParsedPackage pkg = new PackageParser() - .parseParsedPackage(mTmpDir, 0 /* flags */, false); - DexMetadataHelper.validatePackageDexMetadata(pkg); + ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false); + AndroidPackageUtils.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA); } @@ -163,9 +169,8 @@ public class DexMetadataHelperTest { Files.createFile(invalidDmFile.toPath()); try { - ParsedPackage pkg = new PackageParser() - .parseParsedPackage(mTmpDir, 0 /* flags */, false); - DexMetadataHelper.validatePackageDexMetadata(pkg); + ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false); + AndroidPackageUtils.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA); } diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java index 66a4946ecc20..3846be09a6c1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java @@ -23,15 +23,16 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.content.pm.SharedLibraryInfo; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.ParsedPackage; import android.content.pm.parsing.ParsingPackage; import android.util.SparseArray; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + import dalvik.system.DelegateLastClassLoader; import dalvik.system.DexClassLoader; import dalvik.system.PathClassLoader; @@ -61,7 +62,8 @@ public class DexoptUtilsTest { private TestData createMockApplicationInfo(String baseClassLoader, boolean addSplits, boolean addSplitDependencies, boolean isolatedSplitLoading) { String codeDir = "/data/app/mock.android.com"; - ParsingPackage parsingPackage = PackageImpl.forParsing("mock.android.com") + ParsingPackage parsingPackage = PackageImpl.forTesting("mock.android.com", + codeDir + "/base.dex") .setClassLoaderName(baseClassLoader); parsingPackage.setIsolatedSplitLoading(isolatedSplitLoading); @@ -122,8 +124,7 @@ public class DexoptUtilsTest { .setSplitClassLoaderName(7, null); } - ParsedPackage parsedPackage = parsingPackage.hideAsParsed() - .setBaseCodePath(codeDir + "/base.dex"); + ParsedPackage parsedPackage = (ParsedPackage) parsingPackage.hideAsParsed(); TestData data = new TestData(); data.pkg = parsedPackage.hideAsFinal(); diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt index 27d02e194540..0a32e4a53284 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt @@ -20,9 +20,10 @@ import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.content.pm.PackageParser -import android.content.pm.parsing.AndroidPackage +import android.platform.test.annotations.Presubmit import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo +import com.android.server.pm.parsing.pkg.AndroidPackage import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage import org.junit.Test @@ -36,6 +37,7 @@ import org.junit.runners.Parameterized * This test has to be updated manually whenever the info generation behavior changes, since * there's no single place where flag -> field is defined besides this test. */ +@Presubmit @RunWith(Parameterized::class) class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() { diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt index 925af7fba82a..191c038c3052 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt @@ -17,6 +17,7 @@ package com.android.server.pm.parsing import android.content.pm.PackageManager +import android.platform.test.annotations.Presubmit import com.google.common.truth.Truth.assertWithMessage import org.junit.Test @@ -24,6 +25,7 @@ import org.junit.Test * Collects APKs from the device and verifies that the new parsing behavior outputs * the same exposed Info object as the old parsing logic. */ +@Presubmit class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() { @Test diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt index afd6e1851cde..ca6b296f155c 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt @@ -27,26 +27,27 @@ import android.content.pm.PackageParser import android.content.pm.PackageUserState import android.content.pm.PermissionInfo import android.content.pm.ProviderInfo -import android.content.pm.parsing.AndroidPackage -import android.content.pm.parsing.PackageImpl -import android.content.pm.parsing.PackageInfoUtils import android.os.Debug import android.os.Environment import android.util.SparseArray import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.om.mockThrowOnUnmocked +import com.android.server.om.whenever import com.android.server.pm.PackageManagerService +import com.android.server.pm.PackageSetting +import com.android.server.pm.parsing.pkg.AndroidPackage +import com.android.server.pm.pkg.PackageStateUnserialized import org.junit.BeforeClass import org.mockito.Mockito +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.mock import java.io.File open class AndroidPackageParsingTestBase { companion object { - /** - * By default, don't parse all APKs on device, only the framework one. - * Toggle this manually if working on package parsing. - */ + // TODO(chiuwinson): Enable in separate change to fail all presubmit builds and fix errors private const val VERIFY_ALL_APKS = false /** For auditing memory usage differences */ @@ -59,6 +60,11 @@ open class AndroidPackageParsingTestBase { setCallback { true } } + protected val packageParser2 = PackageParser2(null, false, context.resources.displayMetrics, + null, object : PackageParser2.Callback() { + override fun hasFeature(feature: String?) = true + }) + /** * It would be difficult to mock all possibilities, so just use the APKs on device. * Unfortunately, this means the device must be bootable to verify potentially @@ -80,9 +86,9 @@ open class AndroidPackageParsingTestBase { .toList() } - private val dummyState = Mockito.mock(PackageUserState::class.java).apply { + private val dummyUserState = mock(PackageUserState::class.java).apply { installed = true - Mockito.`when`(isAvailable(Mockito.anyInt())).thenReturn(true) + Mockito.`when`(isAvailable(anyInt())).thenReturn(true) } lateinit var oldPackages: List<PackageParser.Package> @@ -98,7 +104,7 @@ open class AndroidPackageParsingTestBase { } this.newPackages = apks.map { - packageParser.parseParsedPackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false) + packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false) } if (DUMP_HPROF_TO_EXTERNAL) { @@ -111,19 +117,27 @@ open class AndroidPackageParsingTestBase { } fun oldAppInfo(pkg: PackageParser.Package, flags: Int = 0): ApplicationInfo? { - return PackageParser.generateApplicationInfo(pkg, flags, dummyState, 0) + return PackageParser.generateApplicationInfo(pkg, flags, dummyUserState, 0) } fun newAppInfo(pkg: AndroidPackage, flags: Int = 0): ApplicationInfo? { - return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyState, 0) + return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyUserState, 0, + mockPkgSetting(pkg)) } fun oldPackageInfo(pkg: PackageParser.Package, flags: Int = 0): PackageInfo? { - return PackageParser.generatePackageInfo(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState) + return PackageParser.generatePackageInfo(pkg, intArrayOf(), flags, 5, 6, emptySet(), + dummyUserState) } fun newPackageInfo(pkg: AndroidPackage, flags: Int = 0): PackageInfo? { - return PackageInfoUtils.generate(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState, 0) + return PackageInfoUtils.generate(pkg, intArrayOf(), flags, 5, 6, emptySet(), + dummyUserState, 0, mockPkgSetting(pkg)) + } + + private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> { + this.pkg = aPkg + whenever(pkgState) { PackageStateUnserialized() } } } diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java index 46e992ee9362..66cd46699334 100644 --- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.content.pm; +package com.android.server.pm.parsing; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -24,21 +24,26 @@ import static org.junit.Assert.fail; import android.apex.ApexInfo; import android.content.Context; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; -import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; -import android.content.pm.parsing.ParsedPackage; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PermissionInfo; +import android.content.pm.parsing.component.ParsedComponent; +import android.content.pm.parsing.component.ParsedPermission; import android.os.Build; import android.os.Bundle; import android.os.FileUtils; -import android.util.Log; +import android.platform.test.annotations.Presubmit; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.frameworks.coretests.R; +import com.android.frameworks.servicestests.R; import com.android.internal.util.ArrayUtils; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.ParsedPackage; import org.junit.Test; import org.junit.runner.RunWith; @@ -47,9 +52,19 @@ import java.io.File; import java.io.InputStream; import java.util.function.Function; +/** + * {@link ParsedPackage} was moved to the server, so this test moved along with it. + * + * This should be eventually refactored to a comprehensive parsing test, combined with its + * server variant in the parent package. + * + * TODO(b/135203078): Remove this test and replicate the cases in the actual com.android.server + * variant. + */ +@Presubmit @SmallTest @RunWith(AndroidJUnit4.class) -public class PackageParserTest { +public class PackageParserLegacyCoreTest { private static final String RELEASED = null; private static final String OLDER_PRE_RELEASE = "A"; private static final String PRE_RELEASE = "B"; @@ -87,6 +102,10 @@ public class PackageParserTest { } } + private PackageParser2 makeParser() { + return new PackageParser2(null, false, null, null, null); + } + @Test public void testComputeMinSdkVersion_preReleasePlatform() { // Do allow older release minSdkVersion on pre-release platform. @@ -339,7 +358,7 @@ public class PackageParserTest { try { outFile = copyRawResourceToFile(apkFileName, apkResourceId); return converter.apply( - new PackageParser().parseParsedPackage(outFile, 0 /* flags */, false)); + makeParser().parsePackage(outFile, 0 /* flags */, false)); } finally { if (outFile != null) { outFile.delete(); @@ -350,9 +369,9 @@ public class PackageParserTest { /** * Asserts basic properties about a component. */ - private void assertComponent(String className, int numIntents, ParsedComponent<?> component) { - assertEquals(className, component.className); - assertEquals(numIntents, component.intents.size()); + private void assertComponent(String className, int numIntents, ParsedComponent component) { + assertEquals(className, component.getName()); + assertEquals(numIntents, component.getIntents().size()); } /** @@ -406,7 +425,7 @@ public class PackageParserTest { @Test public void testPackageWithComponents_cached() throws Exception { checkPackageWithComponents(p -> - PackageParser.fromCacheEntryStatic(PackageParser.toCacheEntryStatic(p))); + PackageCacher.fromCacheEntryStatic(PackageCacher.toCacheEntryStatic(p))); } private void checkPackageWithComponents( @@ -426,7 +445,7 @@ public class PackageParserTest { assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p); - assertMetadata(p.getAppMetaData(), + assertMetadata(p.getMetaData(), "key1", "value1", "key2", "this_is_app"); assertMetadata(p.getActivities().get(0).getMetaData(), @@ -448,7 +467,7 @@ public class PackageParserTest { // Hidden "app details" activity is added to every package. boolean foundAppDetailsActivity = false; for (int i = 0; i < ArrayUtils.size(p.getActivities()); i++) { - if (p.getActivities().get(i).className.equals( + if (p.getActivities().get(i).getClassName().equals( PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) { foundAppDetailsActivity = true; p.getActivities().remove(i); @@ -466,7 +485,7 @@ public class PackageParserTest { @Test public void testPackageWithIntentFilters_cached() throws Exception { checkPackageWithIntentFilters(p -> - PackageParser.fromCacheEntryStatic(PackageParser.toCacheEntryStatic(p))); + PackageCacher.fromCacheEntryStatic(PackageCacher.toCacheEntryStatic(p))); } private void checkPackageWithIntentFilters( @@ -474,20 +493,19 @@ public class PackageParserTest { ParsedPackage p = parsePackage( "install_intent_filters.apk", R.raw.install_intent_filters, converter); - String packageName = "com.android.frameworks.coretests.install_intent_filters"; + String packageName = "com.android.frameworks.servicestests.install_intent_filters"; assertEquals(packageName, p.getPackageName()); findAndRemoveAppDetailsActivity(p); - Log.e("ParserTest", "" + p.getActivities()); assertEquals("Expected exactly one activity", 1, p.getActivities().size()); assertEquals("Expected exactly one intent filter", - 1, p.getActivities().get(0).intents.size()); + 1, p.getActivities().get(0).getIntents().size()); assertEquals("Expected exactly one mime group in intent filter", - 1, p.getActivities().get(0).intents.get(0).countMimeGroups()); + 1, p.getActivities().get(0).getIntents().get(0).countMimeGroups()); assertTrue("Did not find expected mime group 'mime_group_1'", - p.getActivities().get(0).intents.get(0).hasMimeGroup("mime_group_1")); + p.getActivities().get(0).getIntents().get(0).hasMimeGroup("mime_group_1")); } @Test diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java index 21479c096752..6b600421666e 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,25 +14,28 @@ * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.ParsedPackage; import android.os.Build; +import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** - * Test for {@link AndroidHidlUpdater} + * Test for {@link com.android.server.pm.parsing.library.AndroidHidlUpdater} */ +@Presubmit @SmallTest @RunWith(JUnit4.class) public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { @@ -41,13 +44,13 @@ public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { @Test public void targeted_at_P() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // no change, not system @@ -56,17 +59,17 @@ public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { @Test public void targeted_at_P_system() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) - .hideAsParsed() + .hideAsParsed()) .setSystem(true); // Should add both HIDL libraries - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) .addUsesLibrary(ANDROID_HIDL_MANAGER) .addUsesLibrary(ANDROID_HIDL_BASE) - .hideAsParsed() + .hideAsParsed()) .setSystem(true) .hideAsFinal(); @@ -75,15 +78,15 @@ public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { @Test public void targeted_at_P_not_empty_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // no change, not system @@ -92,20 +95,20 @@ public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { @Test public void targeted_at_P_not_empty_usesLibraries_system() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed() + .hideAsParsed()) .setSystem(true); // The hidl jars should be added at the start of the list because it // is not on the bootclasspath and the package targets pre-P. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) .addUsesLibrary(ANDROID_HIDL_MANAGER) .addUsesLibrary(ANDROID_HIDL_BASE) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed() + .hideAsParsed()) .setSystem(true) .hideAsFinal(); @@ -114,15 +117,15 @@ public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { @Test public void targeted_at_P_in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) .addUsesLibrary(ANDROID_HIDL_MANAGER) .addUsesLibrary(ANDROID_HIDL_BASE) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // Libraries are removed because they are not available for non-system apps @@ -131,18 +134,18 @@ public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { @Test public void targeted_at_P_in_usesLibraries_system() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) .addUsesLibrary(ANDROID_HIDL_MANAGER) .addUsesLibrary(ANDROID_HIDL_BASE) - .hideAsParsed() + .hideAsParsed()) .setSystem(true); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.P) .addUsesLibrary(ANDROID_HIDL_MANAGER) .addUsesLibrary(ANDROID_HIDL_BASE) - .hideAsParsed() + .hideAsParsed()) .setSystem(true) .hideAsFinal(); @@ -153,15 +156,15 @@ public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { @Test public void in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ANDROID_HIDL_BASE) - .hideAsParsed(); + .hideAsParsed()); // Dependency is removed, it is not available. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // Libraries are removed because they are not available for apps targeting Q+ @@ -170,15 +173,15 @@ public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { @Test public void in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesOptionalLibrary(ANDROID_HIDL_BASE) - .hideAsParsed(); + .hideAsParsed()); // Dependency is removed, it is not available. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // Libraries are removed because they are not available for apps targeting Q+ diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java index 65ae219058f4..f536052a319d 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,42 +14,44 @@ * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; -import android.content.pm.OptionalClassRunner; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.ParsedPackage; import android.os.Build; +import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + import org.junit.Test; import org.junit.runner.RunWith; /** * Test for {@link AndroidTestBaseUpdater} */ +@Presubmit @SmallTest @RunWith(OptionalClassRunner.class) -@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.AndroidTestBaseUpdater") +@OptionalClassRunner.OptionalClass("com.android.server.pm.parsing.library.AndroidTestBaseUpdater") public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest { private static final String OTHER_LIBRARY = "other.library"; @Test public void targeted_at_Q() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) - .hideAsParsed(); + .hideAsParsed()); // Should add org.apache.http.legacy. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) .addUsesLibrary(ANDROID_TEST_BASE) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -57,18 +59,18 @@ public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest @Test public void targeted_at_Q_not_empty_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed(); + .hideAsParsed()); // The org.apache.http.legacy jar should be added at the start of the list because it // is not on the bootclasspath and the package targets pre-Q. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) .addUsesLibrary(ANDROID_TEST_BASE) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -76,15 +78,15 @@ public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest @Test public void targeted_at_Q_in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) .addUsesLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) .addUsesLibrary(ANDROID_TEST_BASE) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change is required because although org.apache.http.legacy has been removed from @@ -94,15 +96,15 @@ public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest @Test public void targeted_at_Q_in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) .addUsesOptionalLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) .addUsesOptionalLibrary(ANDROID_TEST_BASE) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change is required because although org.apache.http.legacy has been removed from @@ -112,15 +114,15 @@ public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest @Test public void in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ANDROID_TEST_BASE) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change is required because the package explicitly requests org.apache.http.legacy @@ -130,15 +132,15 @@ public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest @Test public void in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesOptionalLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesOptionalLibrary(ANDROID_TEST_BASE) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change is required because the package explicitly requests org.apache.http.legacy diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java index 38755b9aa965..77197e3c6bcb 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java @@ -14,19 +14,21 @@ * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.ParsedPackage; -import android.content.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater; import android.os.Build; +import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.server.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -34,22 +36,23 @@ import org.junit.runners.JUnit4; /** * Test for {@link AndroidTestRunnerSplitUpdater} */ +@Presubmit @SmallTest @RunWith(JUnit4.class) public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest { @Test public void android_test_runner_in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesOptionalLibrary(ANDROID_TEST_RUNNER) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesOptionalLibrary(ANDROID_TEST_MOCK) .addUsesOptionalLibrary(ANDROID_TEST_RUNNER) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -57,17 +60,17 @@ public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdat @Test public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ANDROID_TEST_RUNNER) .addUsesOptionalLibrary(ANDROID_TEST_MOCK) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ANDROID_TEST_RUNNER) .addUsesOptionalLibrary(ANDROID_TEST_MOCK) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); diff --git a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OptionalClassRunner.java index 05db8ee29844..0ebfe1a0eecb 100644 --- a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OptionalClassRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.content.pm; +package com.android.server.pm.parsing.library; import org.junit.Assume; import org.junit.runner.Description; diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java index 4c7899b47164..95b8d3f9eb4e 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java @@ -14,42 +14,44 @@ * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.OptionalClassRunner; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.ParsedPackage; import android.os.Build; +import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + import org.junit.Test; import org.junit.runner.RunWith; /** - * Test for {@link OrgApacheHttpLegacyUpdater} + * Test for {@link com.android.server.pm.parsing.library.OrgApacheHttpLegacyUpdater} */ +@Presubmit @SmallTest @RunWith(OptionalClassRunner.class) -@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater") +@OptionalClassRunner.OptionalClass("com.android.server.pm.parsing.library.OrgApacheHttpLegacyUpdater") public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest { private static final String OTHER_LIBRARY = "other.library"; @Test public void targeted_at_O() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed(); + .hideAsParsed()); // Should add org.apache.http.legacy. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -57,18 +59,18 @@ public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterT @Test public void targeted_at_O_not_empty_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed(); + .hideAsParsed()); // The org.apache.http.legacy jar should be added at the start of the list because it // is not on the bootclasspath and the package targets pre-P. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -76,15 +78,15 @@ public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterT @Test public void targeted_at_O_in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change is required because although org.apache.http.legacy has been removed from @@ -94,15 +96,15 @@ public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterT @Test public void targeted_at_O_in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change is required because although org.apache.http.legacy has been removed from @@ -112,15 +114,15 @@ public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterT @Test public void in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change is required because the package explicitly requests org.apache.http.legacy @@ -130,15 +132,15 @@ public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterT @Test public void in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change is required because the package explicitly requests org.apache.http.legacy diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java index 00d468de4ee4..ca3886092cf1 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java @@ -14,40 +14,43 @@ * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; -import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.ParsedPackage; import android.content.pm.parsing.ParsingPackage; -import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; import android.os.Build; +import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +@Presubmit @SmallTest @RunWith(JUnit4.class) public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdaterTest { @Test public void null_usesLibraries_and_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -74,12 +77,12 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate */ @Test public void targeted_at_O() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed(); + .hideAsParsed()); - ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME) + ParsingPackage after = PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .setTargetSdkVersion(Build.VERSION_CODES.O); @@ -88,7 +91,7 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate } after.addUsesLibrary(ORG_APACHE_HTTP_LEGACY); - checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal()); + checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal()); } /** @@ -105,16 +108,16 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate + ANDROID_TEST_BASE + " is on the bootclasspath", PackageBackwardCompatibility.bootClassPathContainsATB()); - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); // android.test.base should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -129,12 +132,12 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate */ @Test public void android_test_runner_in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ANDROID_TEST_RUNNER) - .hideAsParsed(); + .hideAsParsed()); - ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME) + ParsingPackage after = PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT); if (!PackageBackwardCompatibility.bootClassPathContainsATB()) { after.addUsesLibrary(ANDROID_TEST_BASE); @@ -142,7 +145,7 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate after.addUsesLibrary(ANDROID_TEST_MOCK); after.addUsesLibrary(ANDROID_TEST_RUNNER); - checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal()); + checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal()); } private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java index e7a80e1a7618..a71572fa2b54 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; import static org.junit.Assert.assertEquals; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ParsedPackage; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.ParsedPackage; import java.util.function.Supplier; @@ -32,7 +32,7 @@ abstract class PackageSharedLibraryUpdaterTest { static void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after, Supplier<PackageSharedLibraryUpdater> updaterSupplier) { - updaterSupplier.get().updatePackage(before); + updaterSupplier.get().updatePackage(before, false); check(before.hideAsFinal(), after); } diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java index fd3ba2bd0c68..1122490d6b1a 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java @@ -14,18 +14,20 @@ * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.ParsedPackage; -import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; import android.os.Build; +import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -33,6 +35,7 @@ import org.junit.runners.JUnit4; /** * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary} */ +@Presubmit @SmallTest @RunWith(JUnit4.class) public class RemoveUnnecessaryAndroidTestBaseLibraryTest @@ -42,13 +45,13 @@ public class RemoveUnnecessaryAndroidTestBaseLibraryTest @Test public void targeted_at_O() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change required. @@ -57,15 +60,15 @@ public class RemoveUnnecessaryAndroidTestBaseLibraryTest @Test public void targeted_at_O_not_empty_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change required. @@ -74,16 +77,16 @@ public class RemoveUnnecessaryAndroidTestBaseLibraryTest @Test public void targeted_at_O_in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); // android.test.base should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -91,16 +94,16 @@ public class RemoveUnnecessaryAndroidTestBaseLibraryTest @Test public void targeted_at_O_in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesOptionalLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); // android.test.base should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -108,14 +111,14 @@ public class RemoveUnnecessaryAndroidTestBaseLibraryTest @Test public void in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .addUsesLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); // android.test.base should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) - .hideAsParsed() + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -123,16 +126,16 @@ public class RemoveUnnecessaryAndroidTestBaseLibraryTest @Test public void in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesOptionalLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); // android.test.base should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -140,17 +143,17 @@ public class RemoveUnnecessaryAndroidTestBaseLibraryTest @Test public void in_bothLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ANDROID_TEST_BASE) .addUsesOptionalLibrary(ANDROID_TEST_BASE) - .hideAsParsed(); + .hideAsParsed()); // android.test.base should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java index d3494d93ae52..3cc84753b810 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java @@ -14,18 +14,20 @@ * limitations under the License. */ -package android.content.pm.parsing.library; +package com.android.server.pm.parsing.library; -import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.ParsedPackage; -import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary; import android.os.Build; +import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -33,6 +35,7 @@ import org.junit.runners.JUnit4; /** * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary} */ +@Presubmit @SmallTest @RunWith(JUnit4.class) public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest @@ -42,13 +45,13 @@ public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest @Test public void targeted_at_O() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change required. @@ -57,15 +60,15 @@ public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest @Test public void targeted_at_O_not_empty_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed(); + .hideAsParsed()); - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(OTHER_LIBRARY) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); // No change required. @@ -74,16 +77,16 @@ public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest @Test public void targeted_at_O_in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed(); + .hideAsParsed()); // org.apache.http.legacy should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -91,16 +94,16 @@ public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest @Test public void targeted_at_O_in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed(); + .hideAsParsed()); // org.apache.http.legacy should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.O) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -108,15 +111,16 @@ public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest @Test public void in_usesLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed(); + .hideAsParsed()); // org.apache.http.legacy should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) - .hideAsParsed() + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -124,15 +128,16 @@ public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest @Test public void in_usesOptionalLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed(); + .hideAsParsed()); // org.apache.http.legacy should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) - .hideAsParsed() + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); @@ -140,17 +145,17 @@ public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest @Test public void in_bothLibraries() { - ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) - .hideAsParsed(); + .hideAsParsed()); // org.apache.http.legacy should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) - .hideAsParsed() + .hideAsParsed()) .hideAsFinal(); checkBackwardsCompatibility(before, after); diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 9e577636c1b3..0fdffd554b36 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -66,6 +66,7 @@ import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; import android.view.Display; @@ -83,6 +84,7 @@ import org.junit.runner.RunWith; import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -101,6 +103,8 @@ public class AppStandbyControllerTests { private static final int UID_EXEMPTED_1 = 10001; private static final int USER_ID = 0; private static final int USER_ID2 = 10; + private static final UserHandle USER_HANDLE_USER2 = new UserHandle(USER_ID2); + private static final int USER_ID3 = 11; private static final String PACKAGE_UNKNOWN = "com.example.unknown"; @@ -150,6 +154,8 @@ public class AppStandbyControllerTests { boolean mDisplayOn; DisplayManager.DisplayListener mDisplayListener; String mBoundWidgetPackage = PACKAGE_EXEMPTED_1; + int[] mRunningUsers = new int[] {USER_ID}; + List<UserHandle> mCrossProfileTargets = Collections.emptyList(); MyInjector(Context context, Looper looper) { super(context, looper); @@ -212,7 +218,7 @@ public class AppStandbyControllerTests { @Override int[] getRunningUserIds() { - return new int[] {USER_ID}; + return mRunningUsers; } @Override @@ -248,6 +254,11 @@ public class AppStandbyControllerTests { return false; } + @Override + public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) { + return mCrossProfileTargets; + } + // Internal methods void setDisplayOn(boolean on) { @@ -379,10 +390,15 @@ public class AppStandbyControllerTests { } private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) { + assertTimeout(controller, elapsedTime, bucket, USER_ID); + } + + private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket, + int userId) { mInjector.mElapsedRealtime = elapsedTime; - controller.checkIdleStates(USER_ID); + controller.checkIdleStates(userId); assertEquals(bucket, - controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, + controller.getAppStandbyBucket(PACKAGE_1, userId, mInjector.mElapsedRealtime, false)); } @@ -397,7 +413,11 @@ public class AppStandbyControllerTests { } private int getStandbyBucket(AppStandbyController controller, String packageName) { - return controller.getAppStandbyBucket(packageName, USER_ID, mInjector.mElapsedRealtime, + return getStandbyBucket(USER_ID, controller, packageName); + } + + private int getStandbyBucket(int userId, AppStandbyController controller, String packageName) { + return controller.getAppStandbyBucket(packageName, userId, mInjector.mElapsedRealtime, true); } @@ -1012,6 +1032,29 @@ public class AppStandbyControllerTests { assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID); } + @Test + public void testUserInteraction_CrossProfile() throws Exception { + mInjector.mRunningUsers = new int[] {USER_ID, USER_ID2, USER_ID3}; + mInjector.mCrossProfileTargets = Arrays.asList(USER_HANDLE_USER2); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); + assertEquals("Cross profile connected package bucket should be elevated on usage", + STANDBY_BUCKET_ACTIVE, getStandbyBucket(USER_ID2, mController, PACKAGE_1)); + assertEquals("Not Cross profile connected package bucket should not be elevated on usage", + STANDBY_BUCKET_NEVER, getStandbyBucket(USER_ID3, mController, PACKAGE_1)); + + assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE, USER_ID); + assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE, USER_ID2); + + assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET, USER_ID); + assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET, USER_ID2); + + mInjector.mCrossProfileTargets = Collections.emptyList(); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); + assertEquals("No longer cross profile connected package bucket should not be " + + "elevated on usage", + STANDBY_BUCKET_WORKING_SET, getStandbyBucket(USER_ID2, mController, PACKAGE_1)); + } + private String getAdminAppsStr(int userId) { return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId)); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index bc2766c8f92f..cee486fbb4e3 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -16,6 +16,19 @@ package com.android.server.notification; +import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_EVENTS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM; +import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY; +import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS; +import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; @@ -219,7 +232,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void testZenOff_NoMuteApplied() { mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_OFF; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | - Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); + PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); doNothing().when(mZenModeHelperSpy).applyRestrictions(eq(false), anyBoolean(), anyInt()); @@ -230,10 +243,73 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + public void testZenOn_NotificationApplied() { + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + // The most permissive policy + mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | + PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES + | PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS + | PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REMINDERS + | PRIORITY_CATEGORY_REPEAT_CALLERS | PRIORITY_CATEGORY_SYSTEM, PRIORITY_SENDERS_ANY, + PRIORITY_SENDERS_ANY, 0, CONVERSATION_SENDERS_ANYONE); + mZenModeHelperSpy.applyRestrictions(); + + doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyBoolean(), anyInt()); + verify(mZenModeHelperSpy).applyRestrictions(true, true, + AudioAttributes.USAGE_NOTIFICATION); + verify(mZenModeHelperSpy).applyRestrictions(true, true, + AudioAttributes.USAGE_NOTIFICATION_EVENT); + verify(mZenModeHelperSpy).applyRestrictions(true, true, + AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED); + verify(mZenModeHelperSpy).applyRestrictions(true, true, + AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT); + } + + @Test + public void testZenOn_StarredCallers_CallTypesBlocked() { + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + // The most permissive policy + mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | + PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES + | PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS + | PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REMINDERS + | PRIORITY_CATEGORY_SYSTEM, + PRIORITY_SENDERS_STARRED, + PRIORITY_SENDERS_ANY, 0, CONVERSATION_SENDERS_ANYONE); + mZenModeHelperSpy.applyRestrictions(); + + doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyBoolean(), anyInt()); + verify(mZenModeHelperSpy).applyRestrictions(true, true, + AudioAttributes.USAGE_NOTIFICATION_RINGTONE); + verify(mZenModeHelperSpy).applyRestrictions(true, true, + AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST); + } + + @Test + public void testZenOn_AllCallers_CallTypesAllowed() { + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + // The most permissive policy + mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | + PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES + | PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS + | PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REMINDERS + | PRIORITY_CATEGORY_REPEAT_CALLERS | PRIORITY_CATEGORY_SYSTEM, + PRIORITY_SENDERS_ANY, + PRIORITY_SENDERS_ANY, 0, CONVERSATION_SENDERS_ANYONE); + mZenModeHelperSpy.applyRestrictions(); + + doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyBoolean(), anyInt()); + verify(mZenModeHelperSpy).applyRestrictions(true, false, + AudioAttributes.USAGE_NOTIFICATION_RINGTONE); + verify(mZenModeHelperSpy).applyRestrictions(true, false, + AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST); + } + + @Test public void testZenOn_AllowAlarmsMedia_NoAlarmMediaMuteApplied() { mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | - Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); + PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, @@ -261,7 +337,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void testTotalSilence() { mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | - Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); + PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); // Total silence will silence alarms, media and system noises (but not vibrations) diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index ba577454f9d5..2b0ad890aae1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -605,6 +605,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; + mWindow.mAttrs.setFitInsetsTypes(0 /* types */); addWindow(mWindow); mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); @@ -625,6 +626,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; + mWindow.mAttrs.setFitInsetsTypes(0 /* types */); mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER; addWindow(mWindow); diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java index 18b640ff6bf5..c3d3d83f02fa 100644 --- a/services/usage/java/com/android/server/usage/StorageStatsService.java +++ b/services/usage/java/com/android/server/usage/StorageStatsService.java @@ -86,6 +86,7 @@ import java.util.function.Consumer; public class StorageStatsService extends IStorageStatsManager.Stub { private static final String TAG = "StorageStatsService"; + private static final String PROP_STORAGE_CRATES = "fw.storage_crates"; private static final String PROP_DISABLE_QUOTA = "fw.disable_quota"; private static final String PROP_VERIFY_STORAGE = "fw.verify_storage"; @@ -595,6 +596,13 @@ public class StorageStatsService extends IStorageStatsManager.Stub { Uri.parse("content://com.android.externalstorage.documents/"), null, false); } + private static void checkCratesEnable() { + final boolean enable = SystemProperties.getBoolean(PROP_STORAGE_CRATES, false); + if (!enable) { + throw new IllegalStateException("Storage Crate feature is disabled."); + } + } + /** * To enforce the calling or self to have the {@link android.Manifest.permission#MANAGE_CRATES} * permission. @@ -650,6 +658,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { @Override public ParceledListSlice<CrateInfo> queryCratesForPackage(String volumeUuid, @NonNull String packageName, @UserIdInt int userId, @NonNull String callingPackage) { + checkCratesEnable(); if (userId != UserHandle.getCallingUserId()) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS, TAG); @@ -677,6 +686,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { @Override public ParceledListSlice<CrateInfo> queryCratesForUid(String volumeUuid, int uid, @NonNull String callingPackage) { + checkCratesEnable(); final int userId = UserHandle.getUserId(uid); if (userId != UserHandle.getCallingUserId()) { mContext.enforceCallingOrSelfPermission( @@ -718,6 +728,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { @Override public ParceledListSlice<CrateInfo> queryCratesForUser(String volumeUuid, int userId, @NonNull String callingPackage) { + checkCratesEnable(); if (userId != UserHandle.getCallingUserId()) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS, TAG); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index df5b311bbab1..0d1b3523bf9b 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -86,6 +86,7 @@ import android.util.SparseIntArray; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; @@ -104,6 +105,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.StandardCopyOption; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; @@ -1121,7 +1123,7 @@ public class UsageStatsService extends SystemService implements boolean checkin = false; boolean compact = false; - String pkg = null; + final ArrayList<String> pkgs = new ArrayList<>(); if (args != null) { for (int i = 0; i < args.length; i++) { @@ -1214,8 +1216,7 @@ public class UsageStatsService extends SystemService implements return; } else if (arg != null && !arg.startsWith("-")) { // Anything else that doesn't start with '-' is a pkg to filter - pkg = arg; - break; + pkgs.add(arg); } } } @@ -1230,15 +1231,15 @@ public class UsageStatsService extends SystemService implements if (checkin) { mUserState.valueAt(i).checkin(idpw); } else { - mUserState.valueAt(i).dump(idpw, pkg, compact); + mUserState.valueAt(i).dump(idpw, pkgs, compact); idpw.println(); } } - mAppStandby.dumpUser(idpw, userId, pkg); + mAppStandby.dumpUser(idpw, userId, pkgs); idpw.decreaseIndent(); } - if (pkg == null) { + if (CollectionUtils.isEmpty(pkgs)) { pw.println(); mAppStandby.dumpState(args, pw); } diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index db26d88dbfbb..b7779fd40990 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -48,6 +48,7 @@ import android.util.Slog; import android.util.SparseIntArray; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.usage.UsageStatsDatabase.StatCombiner; @@ -753,18 +754,21 @@ class UserUsageStatsService { }); } - void dump(IndentingPrintWriter pw, String pkg) { - dump(pw, pkg, false); + void dump(IndentingPrintWriter pw, List<String> pkgs) { + dump(pw, pkgs, false); } - void dump(IndentingPrintWriter pw, String pkg, boolean compact) { - printLast24HrEvents(pw, !compact, pkg); + + void dump(IndentingPrintWriter pw, List<String> pkgs, boolean compact) { + printLast24HrEvents(pw, !compact, pkgs); for (int interval = 0; interval < mCurrentStats.length; interval++) { pw.print("In-memory "); pw.print(intervalToString(interval)); pw.println(" stats"); - printIntervalStats(pw, mCurrentStats[interval], !compact, true, pkg); + printIntervalStats(pw, mCurrentStats[interval], !compact, true, pkgs); + } + if (CollectionUtils.isEmpty(pkgs)) { + mDatabase.dump(pw, compact); } - mDatabase.dump(pw, compact); } void dumpDatabaseInfo(IndentingPrintWriter ipw) { @@ -894,7 +898,8 @@ class UserUsageStatsService { pw.println(); } - void printLast24HrEvents(IndentingPrintWriter pw, boolean prettyDates, final String pkg) { + void printLast24HrEvents(IndentingPrintWriter pw, boolean prettyDates, + final List<String> pkgs) { final long endTime = System.currentTimeMillis(); UnixCalendar yesterday = new UnixCalendar(endTime); yesterday.addDays(-1); @@ -914,7 +919,7 @@ class UserUsageStatsService { } Event event = stats.events.get(i); - if (pkg != null && !pkg.equals(event.mPackage)) { + if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(event.mPackage)) { continue; } accumulatedResult.add(event); @@ -958,7 +963,7 @@ class UserUsageStatsService { } void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats, - boolean prettyDates, boolean skipEvents, String pkg) { + boolean prettyDates, boolean skipEvents, List<String> pkgs) { if (prettyDates) { pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext, stats.beginTime, stats.endTime, sDateFormatFlags) + "\""); @@ -974,7 +979,7 @@ class UserUsageStatsService { final int pkgCount = pkgStats.size(); for (int i = 0; i < pkgCount; i++) { final UsageStats usageStats = pkgStats.valueAt(i); - if (pkg != null && !pkg.equals(usageStats.mPackageName)) { + if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(usageStats.mPackageName)) { continue; } pw.printPair("package", usageStats.mPackageName); @@ -998,7 +1003,7 @@ class UserUsageStatsService { pw.println("ChooserCounts"); pw.increaseIndent(); for (UsageStats usageStats : pkgStats.values()) { - if (pkg != null && !pkg.equals(usageStats.mPackageName)) { + if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(usageStats.mPackageName)) { continue; } pw.printPair("package", usageStats.mPackageName); @@ -1023,7 +1028,7 @@ class UserUsageStatsService { } pw.decreaseIndent(); - if (pkg == null) { + if (CollectionUtils.isEmpty(pkgs)) { pw.println("configurations"); pw.increaseIndent(); final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations; @@ -1060,7 +1065,7 @@ class UserUsageStatsService { final int eventCount = events != null ? events.size() : 0; for (int i = 0; i < eventCount; i++) { final Event event = events.get(i); - if (pkg != null && !pkg.equals(event.mPackage)) { + if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(event.mPackage)) { continue; } printEvent(pw, event, prettyDates); diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 6407ec76958e..84f411f33157 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -41,6 +41,7 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Resources; import android.debug.AdbManagerInternal; +import android.debug.AdbTransportType; import android.debug.IAdbTransport; import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.UsbAccessory; @@ -775,8 +776,10 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser } @Override - public void onAdbEnabled(boolean enabled) { - mHandler.sendMessage(MSG_ENABLE_ADB, enabled); + public void onAdbEnabled(boolean enabled, byte transportType) { + if (transportType == AdbTransportType.USB) { + mHandler.sendMessage(MSG_ENABLE_ADB, enabled); + } } } @@ -1170,7 +1173,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser } protected boolean isAdbEnabled() { - return LocalServices.getService(AdbManagerInternal.class).isAdbEnabled(); + return LocalServices.getService(AdbManagerInternal.class) + .isAdbEnabled(AdbTransportType.USB); } protected void updateAdbNotification(boolean force) { diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 52213d8c4fae..c5fcf67c9be9 100644..100755 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -465,8 +465,27 @@ public final class Call { * @hide */ public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000; + + /** + * When set for a call, indicates that this {@code Call} can be transferred to another + * number. + * Call supports the blind and assured call transfer feature. + * + * @hide + */ + public static final int CAPABILITY_TRANSFER = 0x04000000; + + /** + * When set for a call, indicates that this {@code Call} can be transferred to another + * ongoing call. + * Call supports the consultative call transfer feature. + * + * @hide + */ + public static final int CAPABILITY_TRANSFER_CONSULTATIVE = 0x08000000; + //****************************************************************************************** - // Next CAPABILITY value: 0x04000000 + // Next CAPABILITY value: 0x10000000 //****************************************************************************************** /** @@ -699,6 +718,12 @@ public final class Call { if (can(capabilities, CAPABILITY_ADD_PARTICIPANT)) { builder.append(" CAPABILITY_ADD_PARTICIPANT"); } + if (can(capabilities, CAPABILITY_TRANSFER)) { + builder.append(" CAPABILITY_TRANSFER"); + } + if (can(capabilities, CAPABILITY_TRANSFER_CONSULTATIVE)) { + builder.append(" CAPABILITY_TRANSFER_CONSULTATIVE"); + } builder.append("]"); return builder.toString(); } @@ -1564,6 +1589,30 @@ public final class Call { } /** + * Instructs this {@code Call} to be transferred to another number. + * + * @param targetNumber The address to which the call will be transferred. + * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer, + * if {@code false}, it will initiate BLIND transfer. + * + * @hide + */ + public void transfer(@NonNull Uri targetNumber, boolean isConfirmationRequired) { + mInCallAdapter.transferCall(mTelecomCallId, targetNumber, isConfirmationRequired); + } + + /** + * Instructs this {@code Call} to be transferred to another ongoing call. + * This will initiate CONSULTATIVE transfer. + * @param toCall The other ongoing {@code Call} to which this call will be transferred. + * + * @hide + */ + public void transfer(@NonNull android.telecom.Call toCall) { + mInCallAdapter.transferCall(mTelecomCallId, toCall.mTelecomCallId); + } + + /** * Instructs this {@code Call} to disconnect. */ public void disconnect() { diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 3b0ba2548660..4604cd2e2e75 100644..100755 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -387,8 +387,25 @@ public abstract class Connection extends Conferenceable { * @hide */ public static final int CAPABILITY_ADD_PARTICIPANT = 0x04000000; + + /** + * Indicates that this {@code Connection} can be transferred to another + * number. + * Connection supports the blind and assured call transfer feature. + * @hide + */ + public static final int CAPABILITY_TRANSFER = 0x08000000; + + /** + * Indicates that this {@code Connection} can be transferred to another + * ongoing {@code Connection}. + * Connection supports the consultative call transfer feature. + * @hide + */ + public static final int CAPABILITY_TRANSFER_CONSULTATIVE = 0x10000000; + //********************************************************************************************** - // Next CAPABILITY value: 0x08000000 + // Next CAPABILITY value: 0x20000000 //********************************************************************************************** /** @@ -967,6 +984,13 @@ public abstract class Connection extends Conferenceable { if ((capabilities & CAPABILITY_ADD_PARTICIPANT) == CAPABILITY_ADD_PARTICIPANT) { builder.append(isLong ? " CAPABILITY_ADD_PARTICIPANT" : " add_participant"); } + if ((capabilities & CAPABILITY_TRANSFER) == CAPABILITY_TRANSFER) { + builder.append(isLong ? " CAPABILITY_TRANSFER" : " sup_trans"); + } + if ((capabilities & CAPABILITY_TRANSFER_CONSULTATIVE) + == CAPABILITY_TRANSFER_CONSULTATIVE) { + builder.append(isLong ? " CAPABILITY_TRANSFER_CONSULTATIVE" : " sup_cTrans"); + } builder.append("]"); return builder.toString(); } @@ -3092,6 +3116,26 @@ public abstract class Connection extends Conferenceable { public void onReject(String replyMessage) {} /** + * Notifies this Connection, a request to transfer to a target number. + * @param number the number to transfer this {@link Connection} to. + * @param isConfirmationRequired when {@code true}, the {@link ConnectionService} + * should wait until the transfer has successfully completed before disconnecting + * the current {@link Connection}. + * When {@code false}, the {@link ConnectionService} should signal the network to + * perform the transfer, but should immediately disconnect the call regardless of + * the outcome of the transfer. + * @hide + */ + public void onTransfer(@NonNull Uri number, boolean isConfirmationRequired) {} + + /** + * Notifies this Connection, a request to transfer to another Connection. + * @param otherConnection the {@link Connection} to transfer this call to. + * @hide + */ + public void onTransfer(@NonNull Connection otherConnection) {} + + /** * Notifies this Connection of a request to silence the ringer. * <p> * The ringer may be silenced by any of the following methods: @@ -3532,7 +3576,7 @@ public abstract class Connection extends Conferenceable { * ATIS-1000082. * @return the verification status. */ - public @VerificationStatus int getCallerNumberVerificationStatus() { + public final @VerificationStatus int getCallerNumberVerificationStatus() { return mCallerNumberVerificationStatus; } @@ -3544,7 +3588,7 @@ public abstract class Connection extends Conferenceable { * by * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}. */ - public void setCallerNumberVerificationStatus( + public final void setCallerNumberVerificationStatus( @VerificationStatus int callerNumberVerificationStatus) { mCallerNumberVerificationStatus = callerNumberVerificationStatus; } diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 2aea723cf418..0dca006f37c0 100644..100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -128,6 +128,8 @@ public abstract class ConnectionService extends Service { private static final String SESSION_ANSWER = "CS.an"; private static final String SESSION_ANSWER_VIDEO = "CS.anV"; private static final String SESSION_DEFLECT = "CS.def"; + private static final String SESSION_TRANSFER = "CS.trans"; + private static final String SESSION_CONSULTATIVE_TRANSFER = "CS.cTrans"; private static final String SESSION_REJECT = "CS.r"; private static final String SESSION_REJECT_MESSAGE = "CS.rWM"; private static final String SESSION_SILENCE = "CS.s"; @@ -196,6 +198,8 @@ public abstract class ConnectionService extends Service { private static final int MSG_CREATE_CONFERENCE_FAILED = 37; private static final int MSG_REJECT_WITH_REASON = 38; private static final int MSG_ADD_PARTICIPANT = 39; + private static final int MSG_EXPLICIT_CALL_TRANSFER = 40; + private static final int MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE = 41; private static Connection sNullConnection; @@ -481,6 +485,38 @@ public abstract class ConnectionService extends Service { } @Override + public void transfer(@NonNull String callId, @NonNull Uri number, + boolean isConfirmationRequired, Session.Info sessionInfo) { + Log.startSession(sessionInfo, SESSION_TRANSFER); + try { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = callId; + args.arg2 = number; + args.argi1 = isConfirmationRequired ? 1 : 0; + args.arg3 = Log.createSubsession(); + mHandler.obtainMessage(MSG_EXPLICIT_CALL_TRANSFER, args).sendToTarget(); + } finally { + Log.endSession(); + } + } + + @Override + public void consultativeTransfer(@NonNull String callId, @NonNull String otherCallId, + Session.Info sessionInfo) { + Log.startSession(sessionInfo, SESSION_CONSULTATIVE_TRANSFER); + try { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = callId; + args.arg2 = otherCallId; + args.arg3 = Log.createSubsession(); + mHandler.obtainMessage( + MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE, args).sendToTarget(); + } finally { + Log.endSession(); + } + } + + @Override public void silence(String callId, Session.Info sessionInfo) { Log.startSession(sessionInfo, SESSION_SILENCE); try { @@ -1108,6 +1144,30 @@ public abstract class ConnectionService extends Service { } break; } + case MSG_EXPLICIT_CALL_TRANSFER: { + SomeArgs args = (SomeArgs) msg.obj; + Log.continueSession((Session) args.arg3, SESSION_HANDLER + SESSION_TRANSFER); + try { + final boolean isConfirmationRequired = args.argi1 == 1; + transfer((String) args.arg1, (Uri) args.arg2, isConfirmationRequired); + } finally { + args.recycle(); + Log.endSession(); + } + break; + } + case MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE: { + SomeArgs args = (SomeArgs) msg.obj; + Log.continueSession( + (Session) args.arg3, SESSION_HANDLER + SESSION_CONSULTATIVE_TRANSFER); + try { + consultativeTransfer((String) args.arg1, (String) args.arg2); + } finally { + args.recycle(); + Log.endSession(); + } + break; + } case MSG_DISCONNECT: { SomeArgs args = (SomeArgs) msg.obj; Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_DISCONNECT); @@ -2042,6 +2102,18 @@ public abstract class ConnectionService extends Service { findConnectionForAction(callId, "reject").onReject(rejectReason); } + private void transfer(String callId, Uri number, boolean isConfirmationRequired) { + Log.d(this, "transfer %s", callId); + findConnectionForAction(callId, "transfer").onTransfer(number, isConfirmationRequired); + } + + private void consultativeTransfer(String callId, String otherCallId) { + Log.d(this, "consultativeTransfer %s", callId); + Connection connection1 = findConnectionForAction(callId, "consultativeTransfer"); + Connection connection2 = findConnectionForAction(otherCallId, " consultativeTransfer"); + connection1.onTransfer(connection2); + } + private void silence(String callId) { Log.d(this, "silence %s", callId); findConnectionForAction(callId, "silence").onSilence(); diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java index 9d29174059ad..dd6c15311651 100644..100755 --- a/telecomm/java/android/telecom/InCallAdapter.java +++ b/telecomm/java/android/telecom/InCallAdapter.java @@ -16,6 +16,7 @@ package android.telecom; +import android.annotation.NonNull; import android.bluetooth.BluetoothDevice; import android.net.Uri; import android.os.Bundle; @@ -102,6 +103,35 @@ public final class InCallAdapter { } /** + * Instructs Telecom to transfer the specified call. + * + * @param callId The identifier of the call to transfer. + * @param targetNumber The address to transfer to. + * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer, + * if {@code false}, it will initiate BLIND transfer. + */ + public void transferCall(@NonNull String callId, @NonNull Uri targetNumber, + boolean isConfirmationRequired) { + try { + mAdapter.transferCall(callId, targetNumber, isConfirmationRequired); + } catch (RemoteException e) { + } + } + + /** + * Instructs Telecom to transfer the specified call to another ongoing call. + * + * @param callId The identifier of the call to transfer. + * @param otherCallId The identifier of the other call to which this will be transferred. + */ + public void transferCall(@NonNull String callId, @NonNull String otherCallId) { + try { + mAdapter.consultativeTransfer(callId, otherCallId); + } catch (RemoteException e) { + } + } + + /** * Instructs Telecom to disconnect the specified call. * * @param callId The identifier of the call to disconnect. diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl index a397d77db2f6..fb5417994b57 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl @@ -81,6 +81,11 @@ oneway interface IConnectionService { void rejectWithMessage(String callId, String message, in Session.Info sessionInfo); + void transfer(String callId, in Uri number, boolean isConfirmationRequired, + in Session.Info sessionInfo); + + void consultativeTransfer(String callId, String otherCallId, in Session.Info sessionInfo); + void disconnect(String callId, in Session.Info sessionInfo); void silence(String callId, in Session.Info sessionInfo); diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl index 9beff22ce52e..edf1cf4cdb18 100644..100755 --- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl @@ -36,6 +36,10 @@ oneway interface IInCallAdapter { void rejectCallWithReason(String callId, int rejectReason); + void transferCall(String callId, in Uri targetNumber, boolean isConfirmationRequired); + + void consultativeTransfer(String callId, String otherCallId); + void disconnectCall(String callId); void holdCall(String callId); diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index a27c4802c306..9ae86c8c586b 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -432,7 +432,7 @@ public class Annotation { DataFailCause.LIMITED_TO_IPV6, DataFailCause.VSNCP_TIMEOUT, DataFailCause.VSNCP_GEN_ERROR, - DataFailCause.VSNCP_APN_UNATHORIZED, + DataFailCause.VSNCP_APN_UNAUTHORIZED, DataFailCause.VSNCP_PDN_LIMIT_EXCEEDED, DataFailCause.VSNCP_NO_PDN_GATEWAY_ADDRESS, DataFailCause.VSNCP_PDN_GATEWAY_UNREACHABLE, diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 795de57e834f..a7e52ea21758 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -17,7 +17,6 @@ package android.telephony; import android.Manifest; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -28,7 +27,6 @@ import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; -import android.net.ipsec.ike.SaProposal; import android.os.PersistableBundle; import android.os.RemoteException; import android.service.carrier.CarrierService; @@ -38,6 +36,8 @@ import android.telephony.ims.ImsReasonInfo; import com.android.internal.telephony.ICarrierConfigLoader; import com.android.telephony.Rlog; +import java.util.concurrent.TimeUnit; + /** * Provides access to telephony configuration values that are carrier-specific. */ @@ -840,7 +840,8 @@ public class CarrierConfigManager { /** * The default flag specifying whether ETWS/CMAS test setting is forcibly disabled in * Settings->More->Emergency broadcasts menu even though developer options is turned on. - * @deprecated moved to cellbroadcastreceiver resource show_test_settings + * @deprecated Use {@code com.android.cellbroadcastreceiver.CellBroadcastReceiver} resource + * {@code show_test_settings} to control whether to show test alert settings or not. */ @Deprecated public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = @@ -1989,6 +1990,13 @@ public class CarrierConfigManager { "carrier_allow_deflect_ims_call_bool"; /** + * Flag indicating whether the carrier supports explicit call transfer for an IMS call. + * @hide + */ + public static final String KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL = + "carrier_allow_transfer_ims_call_bool"; + + /** * Flag indicating whether the carrier always wants to play an "on-hold" tone when a call has * been remotely held. * <p> @@ -2018,10 +2026,15 @@ public class CarrierConfigManager { "allow_add_call_during_video_call"; /** - * When false, indicates that holding a video call is disabled + * When {@code true}, indicates that video calls can be put on hold in order to swap to another + * call (e.g. a new outgoing call). + * When {@code false}, indicates that video calls will be disconnected when swapping to another + * call. + * <p> + * This is {@code true} by default. */ - public static final String KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL = - "allow_holding_video_call"; + public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL = + "allow_hold_video_call_bool"; /** * When true, indicates that the HD audio icon in the in-call screen should not be shown for @@ -2468,6 +2481,21 @@ public class CarrierConfigManager { "parameters_use_for_5g_nr_signal_bar_int"; /** + * String array of default bandwidth values per network type. + * The entries should be of form "network_name:downstream,upstream", with values in Kbps. + * @hide + */ + public static final String KEY_BANDWIDTH_STRING_ARRAY = "bandwidth_string_array"; + + /** + * For NR (non-standalone), whether to use the LTE value instead of NR value as the default for + * upstream bandwidth. Downstream bandwidth will still use the NR value as the default. + * @hide + */ + public static final String KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPSTREAM_BOOL = + "bandwidth_nr_nsa_use_lte_value_for_upstream_bool"; + + /** * Key identifying if voice call barring notification is required to be shown to the user. * @hide */ @@ -2969,6 +2997,33 @@ public class CarrierConfigManager { "5g_icon_display_grace_period_sec_int"; /** + * Controls time in milliseconds until DcTracker reevaluates 5G connection state. + */ + public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long"; + + /** + * Whether NR (non-standalone) should be unmetered for all frequencies. + * If either {@link #KEY_UNMETERED_NR_NSA_MMWAVE_BOOL} or + * {@link #KEY_UNMETERED_NR_NSA_SUB6_BOOL} are true, then this value will be ignored. + * @hide + */ + public static final String KEY_UNMETERED_NR_NSA_BOOL = "unmetered_nr_nsa_bool"; + + /** + * Whether NR (non-standalone) frequencies above 6GHz (millimeter wave) should be unmetered. + * If this is true, then the value for {@link #KEY_UNMETERED_NR_NSA_BOOL} will be ignored. + * @hide + */ + public static final String KEY_UNMETERED_NR_NSA_MMWAVE_BOOL = "unmetered_nr_nsa_mmwave_bool"; + + /** + * Whether NR (non-standalone) frequencies below 6GHz (sub6) should be unmetered. + * If this is true, then the value for {@link #KEY_UNMETERED_NR_NSA_BOOL} will be ignored. + * @hide + */ + public static final String KEY_UNMETERED_NR_NSA_SUB6_BOOL = "unmetered_nr_nsa_sub6_bool"; + + /** * Support ASCII 7-BIT encoding for long SMS. This carrier config is used to enable * this feature. * @hide @@ -3040,11 +3095,6 @@ public class CarrierConfigManager { "ping_test_before_data_switch_bool"; /** - * Controls time in milliseconds until DcTracker reevaluates 5G connection state. - */ - public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = - "5g_watchdog_time_long"; - /** * Controls whether to switch data to primary from opportunistic subscription * if primary is out of service. This control only affects system or 1st party app * initiated data switch, but will not override data switch initiated by privileged carrier apps @@ -3499,369 +3549,6 @@ public class CarrierConfigManager { public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = "show_forwarded_number_bool"; - /** - * Configs used for epdg tunnel bring up. - * - * @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange - * Protocol Version 2 (IKEv2)</a> - */ - public static final class Iwlan { - /** Prefix of all Epdg.KEY_* constants. */ - public static final String KEY_PREFIX = "iwlan."; - - /** - * Time in seconds after which the child security association session is terminated if - * rekey procedure is not successful. If not set or set to <= 0, the default value is - * 3600 seconds. - */ - public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT = - KEY_PREFIX + "child_sa_rekey_hard_timer_sec_int"; - - /** - * Time in seconds after which the child session rekey procedure is started. If not set or - * set to <= 0, default value is 3000 seconds. - */ - public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT = - KEY_PREFIX + "child_sa_rekey_soft_timer_sec_int"; - - /** Supported DH groups for IKE negotiation. - * Possible values are {@link #DH_GROUP_NONE}, {@link #DH_GROUP_1024_BIT_MODP}, - * {@link #DH_GROUP_2048_BIT_MODP} - */ - public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY = - KEY_PREFIX + "diffie_hellman_groups_int_array"; - - /** - * Time in seconds after which a dead peer detection (DPD) request is sent. - * If not set or set to <= 0, default value is 120 seconds. - */ - public static final String KEY_DPD_TIMER_SEC_INT = KEY_PREFIX + "dpd_timer_sec_int"; - - /** - * Method used to authenticate epdg server. - * Possible values are {@link #AUTHENTICATION_METHOD_EAP_ONLY}, - * {@link #AUTHENTICATION_METHOD_CERT} - */ - public static final String KEY_EPDG_AUTHENTICATION_METHOD_INT = - KEY_PREFIX + "epdg_authentication_method_int"; - - /** - * A priority list of ePDG addresses to be used. - * Possible values are {@link #EPDG_ADDRESS_STATIC}, {@link #EPDG_ADDRESS_PLMN}, - * {@link #EPDG_ADDRESS_PCO} - */ - public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY = - KEY_PREFIX + "epdg_address_priority_int_array"; - - /** Epdg static IP address or FQDN */ - public static final String KEY_EPDG_STATIC_ADDRESS_STRING = - KEY_PREFIX + "epdg_static_address_string"; - - /** Epdg static IP address or FQDN for roaming */ - public static final String KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING = - KEY_PREFIX + "epdg_static_address_roaming_string"; - - /** - * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of child - * session. - * Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, - * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256} - */ - public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = - KEY_PREFIX + "child_session_aes_cbc_key_size_int_array"; - - /** - * List of supported key sizes for AES counter (CTR) encryption mode of child session. - * Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, - * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256} - */ - public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = - KEY_PREFIX + "child_encryption_aes_ctr_key_size_int_array"; - - /** - * List of supported encryption algorithms for child session. - * Possible values are {@link #ENCRYPTION_ALGORITHM_3DES}, - * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_8}, - * {@link #ENCRYPTION_ALGORITHM_AES_GCM_12}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_16} - */ - public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = - KEY_PREFIX + "supported_child_session_encryption_algorithms_int_array"; - - /** Controls if IKE message fragmentation is enabled. */ - public static final String KEY_IKE_FRAGMENTATION_ENABLED_BOOL = - KEY_PREFIX + "ike_fragmentation_enabled_bool"; - - /** - * Time in seconds after which the IKE session is terminated if rekey procedure is not - * successful. If not set or set to <= 0, default value is 3600 seconds. - */ - public static final String KEY_IKE_REKEY_HARD_TIMER_SEC_INT = - KEY_PREFIX + "ike_rekey_hard_timer_in_sec"; - - /** - * Time in seconds after which the IKE session rekey procedure is started. If not set or - * set to <= 0, default value is 3000 seconds. - */ - public static final String KEY_IKE_REKEY_SOFT_TIMER_SEC_INT = - KEY_PREFIX + "ike_rekey_soft_timer_sec_int"; - - /** - * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of IKE - * session. - * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, - * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256} - */ - public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = - KEY_PREFIX + "ike_session_encryption_aes_cbc_key_size_int_array"; - - /** - * List of supported key sizes for AES counter (CTR) encryption mode of IKE session. - * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, - * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256} - */ - public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = - KEY_PREFIX + "ike_session_aes_ctr_key_size_int_array"; - - /** - * List of supported encryption algorithms for IKE session. - * Possible values are {@link #ENCRYPTION_ALGORITHM_3DES}, - * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_8}, - * {@link #ENCRYPTION_ALGORITHM_AES_GCM_12}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_16} - */ - public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = - KEY_PREFIX + "supported_ike_session_encryption_algorithms_int_array"; - - /** - * List of supported integrity algorithms for IKE session - * Possible values are {@link #INTEGRITY_ALGORITHM_NONE}, - * {@link #INTEGRITY_ALGORITHM_HMAC_SHA1_96}, {@link #INTEGRITY_ALGORITHM_AES_XCBC_96}, - * {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_256_128}, - * {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_384_192}, - * {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_512_256} - */ - public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY = - KEY_PREFIX + "supported_integrity_algorithms_int_array"; - - /** Maximum number of retries for tunnel establishment. */ - public static final String KEY_MAX_RETRIES_INT = KEY_PREFIX + "max_retries_int"; - - /** Controls if nat traversal should be enabled. */ - public static final String KEY_NATT_ENABLED_BOOL = KEY_PREFIX + "natt_enabled_bool"; - - /** - * Time in seconds after which a NATT keep alive message is sent. If not set or set to <= 0, - * default value is 20 seconds. - */ - public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT = - KEY_PREFIX + "natt_keep_alive_timer_sec_int"; - - /** List of comma separated MCC/MNCs used to create ePDG FQDN as per 3GPP TS 23.003 */ - public static final String KEY_MCC_MNCS_STRING_ARRAY = KEY_PREFIX + "mcc_mncs_string_array"; - - /** - * List of supported pseudo random function algorithms for IKE session - * Possible values are {@link #PSEUDORANDOM_FUNCTION_HMAC_SHA1}, - * {@link #PSEUDORANDOM_FUNCTION_AES128_XCBC} - */ - public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = KEY_PREFIX + - "supported_prf_algorithms_int_array"; - - /** - * Time in seconds after which IKE message is retransmitted. If not set or set to <= 0, - * default value is 2 seconds. - */ - public static final String KEY_RETRANSMIT_TIMER_SEC_INT = - KEY_PREFIX + "retransmit_timer_sec_int"; - - /** @hide */ - @IntDef({ - AUTHENTICATION_METHOD_EAP_ONLY, - AUTHENTICATION_METHOD_CERT - }) - public @interface AuthenticationMethodType {} - - /** - * Certificate sent from the server is ignored. Only Extensible Authentication Protocol - * (EAP) is used to authenticate the server. - * EAP_ONLY_AUTH payload is added to IKE_AUTH request if supported. - * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998</a> - */ - public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0; - /** Server is authenticated using its certificate. */ - public static final int AUTHENTICATION_METHOD_CERT = 1; - - /** @hide */ - @IntDef({ - EPDG_ADDRESS_STATIC, - EPDG_ADDRESS_PLMN, - EPDG_ADDRESS_PCO - }) - public @interface EpdgAddressType {} - - /** Use static epdg address. */ - public static final int EPDG_ADDRESS_STATIC = 0; - /** Construct the epdg address using plmn. */ - public static final int EPDG_ADDRESS_PLMN = 1; - /** - * Use the epdg address received in protocol configuration options (PCO) from the - * network. - */ - public static final int EPDG_ADDRESS_PCO = 2; - - /** @hide */ - @IntDef({ - KEY_LEN_UNUSED, - KEY_LEN_AES_128, - KEY_LEN_AES_192, - KEY_LEN_AES_256 - }) - public @interface EncrpytionKeyLengthType {} - - public static final int KEY_LEN_UNUSED = SaProposal.KEY_LEN_UNUSED; - /** AES Encryption/Ciphering Algorithm key length 128 bits. */ - public static final int KEY_LEN_AES_128 = SaProposal.KEY_LEN_AES_128; - /** AES Encryption/Ciphering Algorithm key length 192 bits. */ - public static final int KEY_LEN_AES_192 = SaProposal.KEY_LEN_AES_192; - /** AES Encryption/Ciphering Algorithm key length 256 bits. */ - public static final int KEY_LEN_AES_256 = SaProposal.KEY_LEN_AES_256; - - /** @hide */ - @IntDef({ - DH_GROUP_NONE, - DH_GROUP_1024_BIT_MODP, - DH_GROUP_2048_BIT_MODP - }) - public @interface DhGroup {} - - /** None Diffie-Hellman Group. */ - public static final int DH_GROUP_NONE = SaProposal.DH_GROUP_NONE; - /** 1024-bit MODP Diffie-Hellman Group. */ - public static final int DH_GROUP_1024_BIT_MODP = SaProposal.DH_GROUP_1024_BIT_MODP; - /** 2048-bit MODP Diffie-Hellman Group. */ - public static final int DH_GROUP_2048_BIT_MODP = SaProposal.DH_GROUP_2048_BIT_MODP; - - /** @hide */ - @IntDef({ - ENCRYPTION_ALGORITHM_3DES, - ENCRYPTION_ALGORITHM_AES_CBC, - ENCRYPTION_ALGORITHM_AES_GCM_8, - ENCRYPTION_ALGORITHM_AES_GCM_12, - ENCRYPTION_ALGORITHM_AES_GCM_16 - }) - public @interface EncryptionAlgorithm {} - - /** 3DES Encryption/Ciphering Algorithm. */ - public static final int ENCRYPTION_ALGORITHM_3DES = SaProposal.ENCRYPTION_ALGORITHM_3DES; - /** AES-CBC Encryption/Ciphering Algorithm. */ - public static final int ENCRYPTION_ALGORITHM_AES_CBC = - SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; - - /** - * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 8-octet ICV - * (truncation). - */ - public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = - SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8; - /** - * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 12-octet ICV - * (truncation). - */ - public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = - SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; - /** - * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 16-octet ICV - * (truncation). - */ - public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = - SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16; - - /** @hide */ - @IntDef({ - INTEGRITY_ALGORITHM_NONE, - INTEGRITY_ALGORITHM_HMAC_SHA1_96, - INTEGRITY_ALGORITHM_AES_XCBC_96, - INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, - INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, - INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 - }) - public @interface IntegrityAlgorithm {} - - /** None Authentication/Integrity Algorithm. */ - public static final int INTEGRITY_ALGORITHM_NONE = SaProposal.INTEGRITY_ALGORITHM_NONE; - /** HMAC-SHA1 Authentication/Integrity Algorithm. */ - public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = - SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96; - /** AES-XCBC-96 Authentication/Integrity Algorithm. */ - public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = - SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96; - /** HMAC-SHA256 Authentication/Integrity Algorithm with 128-bit truncation. */ - public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = - SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128; - /** HMAC-SHA384 Authentication/Integrity Algorithm with 192-bit truncation. */ - public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = - SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192; - /** HMAC-SHA512 Authentication/Integrity Algorithm with 256-bit truncation. */ - public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = - SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256; - - /** @hide */ - @IntDef({ - PSEUDORANDOM_FUNCTION_HMAC_SHA1, - PSEUDORANDOM_FUNCTION_AES128_XCBC - }) - public @interface PseudorandomFunction {} - - /** HMAC-SHA1 Pseudorandom Function. */ - public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = - SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1; - /** AES128-XCBC Pseudorandom Function. */ - public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = - SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; - - private Iwlan() {} - - private static PersistableBundle getDefaults() { - PersistableBundle defaults = new PersistableBundle(); - defaults.putInt(KEY_IKE_REKEY_SOFT_TIMER_SEC_INT, 3000); - defaults.putInt(KEY_IKE_REKEY_HARD_TIMER_SEC_INT, 3600); - defaults.putInt(KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT, 3000); - defaults.putInt(KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT, 3600); - defaults.putInt(KEY_RETRANSMIT_TIMER_SEC_INT, 2); - defaults.putInt(KEY_DPD_TIMER_SEC_INT, 120); - defaults.putInt(KEY_MAX_RETRIES_INT, 3); - defaults.putIntArray(KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY, - new int[]{DH_GROUP_1024_BIT_MODP, DH_GROUP_2048_BIT_MODP}); - defaults.putIntArray(KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY, - new int[]{ENCRYPTION_ALGORITHM_3DES, ENCRYPTION_ALGORITHM_AES_CBC}); - defaults.putIntArray(KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY, - new int[]{ENCRYPTION_ALGORITHM_3DES, ENCRYPTION_ALGORITHM_AES_CBC}); - defaults.putIntArray(KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY, - new int[]{INTEGRITY_ALGORITHM_AES_XCBC_96, INTEGRITY_ALGORITHM_HMAC_SHA1_96, - INTEGRITY_ALGORITHM_HMAC_SHA2_256_128}); - defaults.putIntArray(KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY, - new int[]{PSEUDORANDOM_FUNCTION_HMAC_SHA1, PSEUDORANDOM_FUNCTION_AES128_XCBC}); - defaults.putBoolean(KEY_NATT_ENABLED_BOOL, true); - defaults.putInt(KEY_EPDG_AUTHENTICATION_METHOD_INT, AUTHENTICATION_METHOD_CERT); - defaults.putString(KEY_EPDG_STATIC_ADDRESS_STRING, ""); - defaults.putString(KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING, ""); - defaults.putInt(KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT, 20); - defaults.putIntArray(KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY, - new int[]{KEY_LEN_AES_128, KEY_LEN_AES_256}); - defaults.putIntArray(KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY, - new int[]{KEY_LEN_AES_128}); - defaults.putIntArray(KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY, - new int[]{KEY_LEN_AES_128, KEY_LEN_AES_256}); - defaults.putIntArray(KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY, - new int[]{KEY_LEN_AES_128}); - defaults.putBoolean(KEY_IKE_FRAGMENTATION_ENABLED_BOOL, false); - defaults.putIntArray(KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY, new int[]{EPDG_ADDRESS_PLMN, - EPDG_ADDRESS_STATIC}); - defaults.putStringArray(KEY_MCC_MNCS_STRING_ARRAY, new String[]{}); - - return defaults; - } - } - /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -3870,6 +3557,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_CARRIER_CONFIG_VERSION_STRING, ""); sDefaults.putBoolean(KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL, true); sDefaults.putBoolean(KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL, false); + sDefaults.putBoolean(KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL, false); sDefaults.putBoolean(KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL, false); sDefaults.putBoolean(KEY_AUTO_RETRY_FAILED_WIFI_EMERGENCY_CALL, false); sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true); @@ -4166,7 +3854,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL, false); sDefaults.putBoolean(KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL, true); sDefaults.putBoolean(KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL, true); - sDefaults.putBoolean(KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL, true); + sDefaults.putBoolean(KEY_ALLOW_HOLD_VIDEO_CALL_BOOL, true); sDefaults.putBoolean(KEY_WIFI_CALLS_CAN_BE_HD_AUDIO, true); sDefaults.putBoolean(KEY_VIDEO_CALLS_CAN_BE_HD_AUDIO, true); sDefaults.putBoolean(KEY_GSM_CDMA_CALLS_CAN_BE_HD_AUDIO, false); @@ -4282,6 +3970,13 @@ public class CarrierConfigManager { }); sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, CellSignalStrengthNr.USE_SSRSRP); + sDefaults.putStringArray(KEY_BANDWIDTH_STRING_ARRAY, new String[]{ + "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA-IS95A:14,14", "CDMA-IS95B:14,14", + "1xRTT:30,30", "EvDo-rev.0:750,48", "EvDo-rev.A:950,550", "HSDPA:4300,620", + "HSUPA:4300,1800", "HSPA:4300,1800", "EvDo-rev.B:1500,550:", "eHRPD:750,48", + "HSPAP:13000,3400", "TD-SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,15000", + "NR_NSA_MMWAVE:145000,15000", "NR_SA:145000,15000"}); + sDefaults.putBoolean(KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPSTREAM_BOOL, false); sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi"); sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false); sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false); @@ -4297,6 +3992,11 @@ public class CarrierConfigManager { sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING, "connected_mmwave:5G,connected:5G"); sDefaults.putInt(KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 0); + /* Default value is 1 hour. */ + sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000); + sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false); + sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false); + sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_SUB6_BOOL, false); sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false); /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108); @@ -4315,8 +4015,6 @@ public class CarrierConfigManager { /* Default value is 3 seconds. */ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000); sDefaults.putBoolean(KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL, true); - /* Default value is 1 hour. */ - sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000); sDefaults.putBoolean(KEY_SWITCH_DATA_TO_PRIMARY_IF_PRIMARY_IS_OOS_BOOL, true); /* Default value is 60 seconds. */ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG, 60000); @@ -4358,8 +4056,7 @@ public class CarrierConfigManager { sDefaults.putAll(Wifi.getDefaults()); sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false); sDefaults.putBoolean(KEY_SHOW_FORWARDED_NUMBER_BOOL, false); - sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, 0); - sDefaults.putAll(Iwlan.getDefaults()); + sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, TimeUnit.DAYS.toMillis(1)); } /** diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index e1c4bef0dd65..8b7a243c30e6 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -30,10 +30,8 @@ import java.util.Map; import java.util.Set; /** - * Returned as the reason for a data connection failure as defined by modem and some local errors. - * @hide + * DataFailCause collects data connection failure causes code from different sources. */ -@SystemApi public final class DataFailCause { /** There is no failure */ public static final int NONE = 0; @@ -841,8 +839,19 @@ public final class DataFailCause { /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request because the requested APN is unauthorized. + * + * @deprecated Use {@link #VSNCP_APN_UNAUTHORIZED} instead. + * + * @hide + */ + @SystemApi + @Deprecated + public static final int VSNCP_APN_UNATHORIZED = 0x8BE; // NOTYPO + /** + * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP + * configuration request because the requested APN is unauthorized. */ - public static final int VSNCP_APN_UNATHORIZED = 0x8BE; + public static final int VSNCP_APN_UNAUTHORIZED = 0x8BE; /** * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP * configuration request because the PDN limit has been exceeded. @@ -1318,6 +1327,7 @@ public final class DataFailCause { sFailCauseMap.put(VSNCP_TIMEOUT, "VSNCP_TIMEOUT"); sFailCauseMap.put(VSNCP_GEN_ERROR, "VSNCP_GEN_ERROR"); sFailCauseMap.put(VSNCP_APN_UNATHORIZED, "VSNCP_APN_UNATHORIZED"); + sFailCauseMap.put(VSNCP_APN_UNAUTHORIZED, "VSNCP_APN_UNAUTHORIZED"); sFailCauseMap.put(VSNCP_PDN_LIMIT_EXCEEDED, "VSNCP_PDN_LIMIT_EXCEEDED"); sFailCauseMap.put(VSNCP_NO_PDN_GATEWAY_ADDRESS, "VSNCP_NO_PDN_GATEWAY_ADDRESS"); sFailCauseMap.put(VSNCP_PDN_GATEWAY_UNREACHABLE, "VSNCP_PDN_GATEWAY_UNREACHABLE"); @@ -1423,8 +1433,8 @@ public final class DataFailCause { if (configManager != null) { PersistableBundle b = configManager.getConfigForSubId(subId); if (b != null) { - String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager. - KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS); + String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager + .KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS); if (permanentFailureStrings != null) { permanentFailureSet = new HashSet<>(); for (Map.Entry<Integer, String> e : sFailCauseMap.entrySet()) { diff --git a/telephony/java/android/telephony/ModemInfo.java b/telephony/java/android/telephony/ModemInfo.java new file mode 100644 index 000000000000..c0833af954d8 --- /dev/null +++ b/telephony/java/android/telephony/ModemInfo.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Information of a single logical modem indicating + * its id, supported rats and whether it supports voice or data, etc. + * @hide + */ +public class ModemInfo implements Parcelable { + public final int modemId; + public final int rat; /* bitset */ + public final boolean isVoiceSupported; + public final boolean isDataSupported; + + // TODO b/121394331: Clean up this class after V1_1.PhoneCapability cleanup. + public ModemInfo(int modemId) { + this(modemId, 0, true, true); + } + + public ModemInfo(int modemId, int rat, boolean isVoiceSupported, boolean isDataSupported) { + this.modemId = modemId; + this.rat = rat; + this.isVoiceSupported = isVoiceSupported; + this.isDataSupported = isDataSupported; + } + + public ModemInfo(Parcel in) { + modemId = in.readInt(); + rat = in.readInt(); + isVoiceSupported = in.readBoolean(); + isDataSupported = in.readBoolean(); + } + + @Override + public String toString() { + return "modemId=" + modemId + " rat=" + rat + " isVoiceSupported:" + isVoiceSupported + + " isDataSupported:" + isDataSupported; + } + + @Override + public int hashCode() { + return Objects.hash(modemId, rat, isVoiceSupported, isDataSupported); + } + + @Override + public boolean equals(Object o) { + if (o == null || !(o instanceof ModemInfo) || hashCode() != o.hashCode()) { + return false; + } + + if (this == o) { + return true; + } + + ModemInfo s = (ModemInfo) o; + + return (modemId == s.modemId + && rat == s.rat + && isVoiceSupported == s.isVoiceSupported + && isDataSupported == s.isDataSupported); + } + + /** + * {@link Parcelable#describeContents} + */ + public @ContentsFlags int describeContents() { + return 0; + } + + /** + * {@link Parcelable#writeToParcel} + */ + public void writeToParcel(Parcel dest, @WriteFlags int flags) { + dest.writeInt(modemId); + dest.writeInt(rat); + dest.writeBoolean(isVoiceSupported); + dest.writeBoolean(isDataSupported); + } + + public static final @android.annotation.NonNull Parcelable.Creator<ModemInfo> CREATOR = new Parcelable.Creator() { + public ModemInfo createFromParcel(Parcel in) { + return new ModemInfo(in); + } + + public ModemInfo[] newArray(int size) { + return new ModemInfo[size]; + } + }; +} diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java index a53792802d92..6571858fc4ae 100644 --- a/telephony/java/android/telephony/PhoneCapability.java +++ b/telephony/java/android/telephony/PhoneCapability.java @@ -16,20 +16,12 @@ package android.telephony; -import android.annotation.LongDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.AccessNetworkConstants.AccessNetworkType; -import android.telephony.AccessNetworkConstants.RadioAccessNetworkType; -import android.telephony.TelephonyManager.NetworkTypeBitMask; -import com.android.internal.telephony.util.TelephonyUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -38,365 +30,69 @@ import java.util.Objects; * are shared between those modems defined by list of modem IDs. */ public final class PhoneCapability implements Parcelable { - /** Modem feature indicating 3GPP2 capability. */ - public static final long MODEM_FEATURE_3GPP2_REG = 1 << 0; - /** Modem feature indicating 3GPP capability. */ - public static final long MODEM_FEATURE_3GPP_REG = 1 << 1; - /** Modem feature indicating CDMA 2000 with EHRPD capability. */ - public static final long MODEM_FEATURE_CDMA2000_EHRPD_REG = 1 << 2; - /** Modem feature indicating GSM capability. */ - public static final long MODEM_FEATURE_GERAN_REG = 1 << 3; - /** Modem feature indicating UMTS capability. */ - public static final long MODEM_FEATURE_UTRAN_REG = 1 << 4; - /** Modem feature indicating LTE capability. */ - public static final long MODEM_FEATURE_EUTRAN_REG = 1 << 5; - /** Modem feature indicating 5G capability.*/ - public static final long MODEM_FEATURE_NGRAN_REG = 1 << 6; - /** Modem feature indicating EN-DC capability. */ - public static final long MODEM_FEATURE_EUTRA_NR_DUAL_CONNECTIVITY_REG = 1 << 7; - /** Modem feature indicating VoLTE capability (IMS registered). */ - public static final long MODEM_FEATURE_PS_VOICE_REG = 1 << 8; - /** Modem feature indicating CS voice call capability. */ - public static final long MODEM_FEATURE_CS_VOICE_SESSION = 1 << 9; - /** Modem feature indicating Internet connection capability. */ - public static final long MODEM_FEATURE_INTERACTIVE_DATA_SESSION = 1 << 10; - /** - * Modem feature indicating dedicated bearer capability. - * For services that require a high level QoS (eg. VoLTE), the network can create - * a dedicated bearer with the required QoS on top of an established default bearer. - * This will provide a dedicated tunnel for one or more specific traffic types. - */ - public static final long MODEM_FEATURE_DEDICATED_BEARER = 1 << 11; - /** Modem feature indicating network scan capability. */ - public static final long MODEM_FEATURE_NETWORK_SCAN = 1 << 12; - /** Modem feature indicating corresponding SIM has CDMA capability. */ - public static final long MODEM_FEATURE_CSIM = 1 << 13; - + // Hardcoded default DSDS capability. /** @hide */ - @LongDef(flag = true, prefix = {"MODEM_FEATURE_" }, value = { - MODEM_FEATURE_3GPP2_REG, - MODEM_FEATURE_3GPP_REG, - MODEM_FEATURE_CDMA2000_EHRPD_REG, - MODEM_FEATURE_GERAN_REG, - MODEM_FEATURE_UTRAN_REG, - MODEM_FEATURE_EUTRAN_REG, - MODEM_FEATURE_NGRAN_REG, - MODEM_FEATURE_EUTRA_NR_DUAL_CONNECTIVITY_REG, - MODEM_FEATURE_PS_VOICE_REG, - MODEM_FEATURE_CS_VOICE_SESSION, - MODEM_FEATURE_INTERACTIVE_DATA_SESSION, - MODEM_FEATURE_DEDICATED_BEARER, - MODEM_FEATURE_NETWORK_SCAN, - MODEM_FEATURE_CSIM, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ModemFeature { - } - - /** - * Hardcoded default DSDS capability. - * @hide - */ public static final PhoneCapability DEFAULT_DSDS_CAPABILITY; - /** - * Hardcoded default Single SIM single standby capability. - * @hide - */ + // Hardcoded default Single SIM single standby capability. + /** @hide */ public static final PhoneCapability DEFAULT_SSSS_CAPABILITY; static { - List<List<Long>> capabilities = new ArrayList<>(); - List<Long> modem1 = new ArrayList<>(); - List<Long> modem2 = new ArrayList<>(); - modem1.add(MODEM_FEATURE_GERAN_REG | MODEM_FEATURE_UTRAN_REG | MODEM_FEATURE_EUTRAN_REG - | MODEM_FEATURE_PS_VOICE_REG | MODEM_FEATURE_CS_VOICE_SESSION - | MODEM_FEATURE_INTERACTIVE_DATA_SESSION | MODEM_FEATURE_DEDICATED_BEARER); - modem2.add(MODEM_FEATURE_GERAN_REG | MODEM_FEATURE_UTRAN_REG | MODEM_FEATURE_EUTRAN_REG - | MODEM_FEATURE_PS_VOICE_REG | MODEM_FEATURE_INTERACTIVE_DATA_SESSION - | MODEM_FEATURE_DEDICATED_BEARER); - capabilities.add(modem1); - capabilities.add(modem2); - List<String> uuids = new ArrayList<>(); - uuids.add("com.xxxx.lm0"); - uuids.add("com.xxxx.lm1"); - long rats = TelephonyManager.NETWORK_TYPE_BITMASK_GSM - | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS - | TelephonyManager.NETWORK_TYPE_BITMASK_EDGE - | TelephonyManager.NETWORK_TYPE_BITMASK_UMTS - | TelephonyManager.NETWORK_TYPE_BITMASK_LTE; - DEFAULT_DSDS_CAPABILITY = new PhoneCapability(0, 0, 0, 0, 0, rats, null, null, null, null, - uuids, null, capabilities); - - capabilities = new ArrayList<>(); - capabilities.add(modem1); - uuids = new ArrayList<>(); - uuids.add("com.xxxx.lm0"); - DEFAULT_SSSS_CAPABILITY = new PhoneCapability(0, 0, 0, 0, 0, rats, null, null, null, null, - uuids, null, capabilities); - } + ModemInfo modemInfo1 = new ModemInfo(0, 0, true, true); + ModemInfo modemInfo2 = new ModemInfo(1, 0, true, true); - private final int mUtranUeCategoryDl; - private final int mUtranUeCategoryUl; - private final int mEutranUeCategoryDl; - private final int mEutranUeCategoryUl; - private final long mPsDataConnectionLingerTimeMillis; - private final @NetworkTypeBitMask long mSupportedRats; - private final List<Integer> mGeranBands; - private final List<Integer> mUtranBands; - private final List<Integer> mEutranBands; - private final List<Integer> mNgranBands; - private final List<String> mLogicalModemUuids; - private final List<SimSlotCapability> mSimSlotCapabilities; - private final @ModemFeature List<List<Long>> mConcurrentFeaturesSupport; - - /** - * Default constructor to create a PhoneCapability object. - * @param utranUeCategoryDl 3GPP UE category for UTRAN downlink. - * @param utranUeCategoryUl 3GPP UE category for UTRAN uplink. - * @param eutranUeCategoryDl 3GPP UE category for EUTRAN downlink. - * @param eutranUeCategoryUl 3GPP UE category for EUTRAN uplink. - * @param psDataConnectionLingerTimeMillis length of the grace period to allow a smooth - * "handover" between data connections. - * @param supportedRats all radio access technologies this phone is capable of supporting. - * @param geranBands list of supported {@link AccessNetworkConstants.GeranBand}. - * @param utranBands list of supported {@link AccessNetworkConstants.UtranBand}. - * @param eutranBands list of supported {@link AccessNetworkConstants.EutranBand}. - * @param ngranBands list of supported {@link AccessNetworkConstants.NgranBands}. - * @param logicalModemUuids list of logical modem UUIDs, typically of the form - * "com.xxxx.lmX", where X is the logical modem ID. - * @param simSlotCapabilities list of {@link SimSlotCapability} for the device - * @param concurrentFeaturesSupport list of list of concurrently supportable modem feature sets. - * @hide - */ - public PhoneCapability(int utranUeCategoryDl, int utranUeCategoryUl, int eutranUeCategoryDl, - int eutranUeCategoryUl, long psDataConnectionLingerTimeMillis, - @NetworkTypeBitMask long supportedRats, @Nullable List<Integer> geranBands, - @Nullable List<Integer> utranBands, @Nullable List<Integer> eutranBands, - @Nullable List<Integer> ngranBands, @Nullable List<String> logicalModemUuids, - @Nullable List<SimSlotCapability> simSlotCapabilities, - @Nullable @ModemFeature List<List<Long>> concurrentFeaturesSupport) { - this.mUtranUeCategoryDl = utranUeCategoryDl; - this.mUtranUeCategoryUl = utranUeCategoryUl; - this.mEutranUeCategoryDl = eutranUeCategoryDl; - this.mEutranUeCategoryUl = eutranUeCategoryUl; - this.mPsDataConnectionLingerTimeMillis = psDataConnectionLingerTimeMillis; - this.mSupportedRats = supportedRats; - this.mGeranBands = TelephonyUtils.emptyIfNull(geranBands); - this.mUtranBands = TelephonyUtils.emptyIfNull(utranBands); - this.mEutranBands = TelephonyUtils.emptyIfNull(eutranBands); - this.mNgranBands = TelephonyUtils.emptyIfNull(ngranBands); - this.mLogicalModemUuids = TelephonyUtils.emptyIfNull(logicalModemUuids); - this.mSimSlotCapabilities = TelephonyUtils.emptyIfNull(simSlotCapabilities); - this.mConcurrentFeaturesSupport = TelephonyUtils.emptyIfNull(concurrentFeaturesSupport); - } + List<ModemInfo> logicalModemList = new ArrayList<>(); + logicalModemList.add(modemInfo1); + logicalModemList.add(modemInfo2); + DEFAULT_DSDS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false); - private PhoneCapability(Parcel in) { - mUtranUeCategoryDl = in.readInt(); - mUtranUeCategoryUl = in.readInt(); - mEutranUeCategoryDl = in.readInt(); - mEutranUeCategoryUl = in.readInt(); - mPsDataConnectionLingerTimeMillis = in.readLong(); - mSupportedRats = in.readLong(); - mGeranBands = new ArrayList<>(); - in.readList(mGeranBands, Integer.class.getClassLoader()); - mUtranBands = new ArrayList<>(); - in.readList(mUtranBands, Integer.class.getClassLoader()); - mEutranBands = new ArrayList<>(); - in.readList(mEutranBands, Integer.class.getClassLoader()); - mNgranBands = new ArrayList<>(); - in.readList(mNgranBands, Integer.class.getClassLoader()); - mLogicalModemUuids = in.createStringArrayList(); - mSimSlotCapabilities = in.createTypedArrayList(SimSlotCapability.CREATOR); - int length = in.readInt(); - mConcurrentFeaturesSupport = new ArrayList<>(); - for (int i = 0; i < length; i++) { - ArrayList<Long> feature = new ArrayList<>(); - in.readList(feature, Long.class.getClassLoader()); - mConcurrentFeaturesSupport.add(feature); - } + logicalModemList = new ArrayList<>(); + logicalModemList.add(modemInfo1); + DEFAULT_SSSS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false); } - /** - * 3GPP UE category for a given Radio Access Network and direction. - * - * References are: - * TS 25.306 Table 4.1a EUTRAN downlink - * TS 25.306 Table 5.1a-2 EUTRAN uplink - * TS 25.306 Table 5.1a UTRAN downlink - * TS 25.306 Table 5.1g UTRAN uplink - * - * @param uplink true for uplink direction and false for downlink direction. - * @param accessNetworkType accessNetworkType, defined in {@link AccessNetworkType}. - * @return the UE category, or -1 if it is not supported. - */ - public int getUeCategory(boolean uplink, @RadioAccessNetworkType int accessNetworkType) { - if (uplink) { - switch (accessNetworkType) { - case AccessNetworkType.UTRAN: return mUtranUeCategoryUl; - case AccessNetworkType.EUTRAN: return mEutranUeCategoryUl; - default: return -1; - } - } else { - switch (accessNetworkType) { - case AccessNetworkType.UTRAN: return mUtranUeCategoryDl; - case AccessNetworkType.EUTRAN: return mEutranUeCategoryDl; - default: return -1; - } - } - } - - /** - * In cellular devices that support a greater number of logical modems than - * Internet connections, some devices support a grace period to allow a smooth "handover" - * between those connections. If that feature is supported, then this API will provide - * the length of that grace period in milliseconds. If it is not supported, the default value - * for the grace period is 0. - * @return handover linger time in milliseconds, or 0 if it is not supported. - */ - public long getPsDataConnectionLingerTimeMillis() { - return mPsDataConnectionLingerTimeMillis; - } - - /** - * The radio access technologies this device is capable of supporting. - * @return a bitfield of all supported network types, defined in {@link TelephonyManager} - */ - public @NetworkTypeBitMask long getSupportedRats() { - return mSupportedRats; - } - - /** - * List of supported cellular bands for the given accessNetworkType. - * @param accessNetworkType accessNetworkType, defined in {@link AccessNetworkType}. - * @return a list of bands, or an empty list if the access network type is unsupported. - */ - public @NonNull List<Integer> getBands(@RadioAccessNetworkType int accessNetworkType) { - switch (accessNetworkType) { - case AccessNetworkType.GERAN: return mGeranBands; - case AccessNetworkType.UTRAN: return mUtranBands; - case AccessNetworkType.EUTRAN: return mEutranBands; - case AccessNetworkType.NGRAN: return mNgranBands; - default: return new ArrayList<>(); - } - } - - /** - * List of logical modem UUIDs, each typically "com.xxxx.lmX", where X is the logical modem ID. - * @return a list of modem UUIDs, one for every logical modem the device has. - */ - public @NonNull List<String> getLogicalModemUuids() { - return mLogicalModemUuids; - } - - /** - * List of {@link SimSlotCapability} for the device. The order of SIMs corresponds to the - * order of modems in {@link #getLogicalModemUuids}. - * @return a list of SIM slot capabilities, one for every SIM slot the device has. - */ - public @NonNull List<SimSlotCapability> getSimSlotCapabilities() { - return mSimSlotCapabilities; - } - - /** - * A List of Lists of concurrently supportable modem feature sets. - * - * Each entry in the top-level list is an independent configuration across all modems - * that describes the capabilities of the device as a whole. - * - * Each entry in the second-level list is a bitfield of ModemFeatures that describes - * the capabilities for a single modem. In the second-level list, the order of the modems - * corresponds to order of the UUIDs in {@link #getLogicalModemUuids}. - * - * For symmetric capabilities that can only be active on one modem at a time, there will be - * multiple configurations (equal to the number of modems) that shows it active on each modem. - * For asymmetric capabilities that are only available on one of the modems, all configurations - * will have that capability on just that one modem. - * - * The example below shows the concurrentFeaturesSupport for a 3-modem device with - * theoretical capabilities SYMMETRIC (available on all modems, but only one at a time) and - * ASYMMETRIC (only available on the first modem): - * { - * Configuration 1: ASYMMETRIC and SYMMETRIC on modem 1, modem 2 empty, modem 3 empty - * {(ASYMMETRIC | SYMMETRIC), (), ()}, - * - * Configuration 2: ASYMMETRIC on modem 1, SYMMETRIC on modem 2, modem 3 empty - * {(ASYMMETRIC), (SYMMETRIC), ()}, - * - * Configuration 3: ASYMMETRIC on modem 1, modem 2 empty, SYMMETRIC on modem 3 - * {(ASYMMETRIC), (), (SYMMETRIC)} - * } - * - * @return List of all concurrently supportable modem features. - */ - public @NonNull @ModemFeature List<List<Long>> getConcurrentFeaturesSupport() { - return mConcurrentFeaturesSupport; - } - - /** - * How many modems can simultaneously have PS attached. - * @return maximum number of active PS voice connections. - */ - public int getMaxActivePsVoice() { - return countFeature(MODEM_FEATURE_PS_VOICE_REG); - } - - /** - * How many modems can simultaneously support active data connections. - * For DSDS, this will be 1, and for DSDA this will be 2. - * @return maximum number of active Internet data sessions. - */ - public int getMaxActiveInternetData() { - return countFeature(MODEM_FEATURE_INTERACTIVE_DATA_SESSION); - } - - /** - * How many modems can simultaneously have dedicated bearer capability. - * @return maximum number of active dedicated bearers. - */ - public int getMaxActiveDedicatedBearers() { - return countFeature(MODEM_FEATURE_DEDICATED_BEARER); - } - - /** - * Whether the CBRS band 48 is supported or not. - * @return true if any RadioAccessNetwork supports CBRS and false if none do. - * @hide - */ - public boolean isCbrsSupported() { - return mEutranBands.contains(AccessNetworkConstants.EutranBand.BAND_48) - || mNgranBands.contains(AccessNetworkConstants.NgranBands.BAND_48); - } + /** @hide */ + public final int maxActiveVoiceCalls; + /** @hide */ + public final int maxActiveData; + /** @hide */ + public final int max5G; + /** @hide */ + public final boolean validationBeforeSwitchSupported; + /** @hide */ + public final List<ModemInfo> logicalModemList; - private int countFeature(@ModemFeature long feature) { - int count = 0; - for (long featureSet : mConcurrentFeaturesSupport.get(0)) { - if ((featureSet & feature) != 0) { - count++; - } - } - return count; + /** @hide */ + public PhoneCapability(int maxActiveVoiceCalls, int maxActiveData, int max5G, + List<ModemInfo> logicalModemList, boolean validationBeforeSwitchSupported) { + this.maxActiveVoiceCalls = maxActiveVoiceCalls; + this.maxActiveData = maxActiveData; + this.max5G = max5G; + // Make sure it's not null. + this.logicalModemList = logicalModemList == null ? new ArrayList<>() : logicalModemList; + this.validationBeforeSwitchSupported = validationBeforeSwitchSupported; } @Override public String toString() { - return "utranUeCategoryDl=" + mUtranUeCategoryDl - + " utranUeCategoryUl=" + mUtranUeCategoryUl - + " eutranUeCategoryDl=" + mEutranUeCategoryDl - + " eutranUeCategoryUl=" + mEutranUeCategoryUl - + " psDataConnectionLingerTimeMillis=" + mPsDataConnectionLingerTimeMillis - + " supportedRats=" + mSupportedRats + " geranBands=" + mGeranBands - + " utranBands=" + mUtranBands + " eutranBands=" + mEutranBands - + " ngranBands=" + mNgranBands + " logicalModemUuids=" + mLogicalModemUuids - + " simSlotCapabilities=" + mSimSlotCapabilities - + " concurrentFeaturesSupport=" + mConcurrentFeaturesSupport; + return "maxActiveVoiceCalls=" + maxActiveVoiceCalls + " maxActiveData=" + maxActiveData + + " max5G=" + max5G + "logicalModemList:" + + Arrays.toString(logicalModemList.toArray()); + } + + private PhoneCapability(Parcel in) { + maxActiveVoiceCalls = in.readInt(); + maxActiveData = in.readInt(); + max5G = in.readInt(); + validationBeforeSwitchSupported = in.readBoolean(); + logicalModemList = new ArrayList<>(); + in.readList(logicalModemList, ModemInfo.class.getClassLoader()); } @Override public int hashCode() { - return Objects.hash(mUtranUeCategoryDl, mUtranUeCategoryUl, mEutranUeCategoryDl, - mEutranUeCategoryUl, mPsDataConnectionLingerTimeMillis, mSupportedRats, mGeranBands, - mUtranBands, mEutranBands, mNgranBands, mLogicalModemUuids, mSimSlotCapabilities, - mConcurrentFeaturesSupport); + return Objects.hash(maxActiveVoiceCalls, maxActiveData, max5G, logicalModemList, + validationBeforeSwitchSupported); } @Override @@ -411,19 +107,11 @@ public final class PhoneCapability implements Parcelable { PhoneCapability s = (PhoneCapability) o; - return (mUtranUeCategoryDl == s.mUtranUeCategoryDl - && mUtranUeCategoryUl == s.mUtranUeCategoryUl - && mEutranUeCategoryDl == s.mEutranUeCategoryDl - && mEutranUeCategoryUl == s.mEutranUeCategoryUl - && mPsDataConnectionLingerTimeMillis == s.mPsDataConnectionLingerTimeMillis - && mSupportedRats == s.mSupportedRats - && mGeranBands.equals(s.mGeranBands) - && mUtranBands.equals(s.mUtranBands) - && mEutranBands.equals(s.mEutranBands) - && mNgranBands.equals(s.mNgranBands) - && mLogicalModemUuids.equals(s.mLogicalModemUuids) - && mSimSlotCapabilities.equals(s.mSimSlotCapabilities) - && mConcurrentFeaturesSupport.equals(s.mConcurrentFeaturesSupport)); + return (maxActiveVoiceCalls == s.maxActiveVoiceCalls + && maxActiveData == s.maxActiveData + && max5G == s.max5G + && validationBeforeSwitchSupported == s.validationBeforeSwitchSupported + && logicalModemList.equals(s.logicalModemList)); } /** @@ -436,33 +124,21 @@ public final class PhoneCapability implements Parcelable { /** * {@link Parcelable#writeToParcel} */ - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mUtranUeCategoryDl); - dest.writeInt(mUtranUeCategoryUl); - dest.writeInt(mEutranUeCategoryDl); - dest.writeInt(mEutranUeCategoryUl); - dest.writeLong(mPsDataConnectionLingerTimeMillis); - dest.writeLong(mSupportedRats); - dest.writeList(mGeranBands); - dest.writeList(mUtranBands); - dest.writeList(mEutranBands); - dest.writeList(mNgranBands); - dest.writeStringList(mLogicalModemUuids); - dest.writeTypedList(mSimSlotCapabilities); - dest.writeInt(mConcurrentFeaturesSupport.size()); - for (List<Long> feature : mConcurrentFeaturesSupport) { - dest.writeList(feature); - } + public void writeToParcel(@NonNull Parcel dest, @Parcelable.WriteFlags int flags) { + dest.writeInt(maxActiveVoiceCalls); + dest.writeInt(maxActiveData); + dest.writeInt(max5G); + dest.writeBoolean(validationBeforeSwitchSupported); + dest.writeList(logicalModemList); } - public static final @NonNull Parcelable.Creator<PhoneCapability> CREATOR = - new Parcelable.Creator() { - public PhoneCapability createFromParcel(Parcel in) { - return new PhoneCapability(in); - } + public static final @android.annotation.NonNull Parcelable.Creator<PhoneCapability> CREATOR = new Parcelable.Creator() { + public PhoneCapability createFromParcel(Parcel in) { + return new PhoneCapability(in); + } - public PhoneCapability[] newArray(int size) { - return new PhoneCapability[size]; - } - }; + public PhoneCapability[] newArray(int size) { + return new PhoneCapability[size]; + } + }; } diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java index 708adebb6db3..e37a9b9e7a8c 100644 --- a/telephony/java/android/telephony/PreciseDataConnectionState.java +++ b/telephony/java/android/telephony/PreciseDataConnectionState.java @@ -257,8 +257,7 @@ public final class PreciseDataConnectionState implements Parcelable { * Return the cause code for the most recent change in {@link #getState}. In the event of an * error, this cause code will be non-zero. */ - // FIXME(b144774287): some of these cause codes should have a prescribed meaning. - public int getLastCauseCode() { + public @DataFailureCause int getLastCauseCode() { return mFailCause; } diff --git a/telephony/java/android/telephony/SimSlotCapability.java b/telephony/java/android/telephony/SimSlotCapability.java deleted file mode 100644 index b4fef46725a4..000000000000 --- a/telephony/java/android/telephony/SimSlotCapability.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Objects; - -/** - * Capabilities for a SIM Slot. - */ -public final class SimSlotCapability implements Parcelable { - /** Slot type for UICC (removable SIM). */ - public static final int SLOT_TYPE_UICC = 1; - /** Slot type for iUICC/iSIM (integrated SIM). */ - public static final int SLOT_TYPE_IUICC = 2; - /** Slot type for eUICC/eSIM (embedded SIM). */ - public static final int SLOT_TYPE_EUICC = 3; - /** Slot type for soft SIM (no physical SIM). */ - public static final int SLOT_TYPE_SOFT_SIM = 4; - - /** @hide */ - @IntDef(prefix = {"SLOT_TYPE_" }, value = { - SLOT_TYPE_UICC, - SLOT_TYPE_IUICC, - SLOT_TYPE_EUICC, - SLOT_TYPE_SOFT_SIM, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface SlotType { - } - - private final int mPhysicalSlotIndex; - private final int mSlotType; - - /** @hide */ - public SimSlotCapability(int physicalSlotId, int slotType) { - this.mPhysicalSlotIndex = physicalSlotId; - this.mSlotType = slotType; - } - - private SimSlotCapability(Parcel in) { - mPhysicalSlotIndex = in.readInt(); - mSlotType = in.readInt(); - } - - /** - * @return physical SIM slot index - */ - public int getPhysicalSlotIndex() { - return mPhysicalSlotIndex; - } - - /** - * @return type of SIM {@link SlotType} - */ - public @SlotType int getSlotType() { - return mSlotType; - } - - @Override - public String toString() { - return "mPhysicalSlotIndex=" + mPhysicalSlotIndex + " slotType=" + mSlotType; - } - - @Override - public int hashCode() { - return Objects.hash(mPhysicalSlotIndex, mSlotType); - } - - @Override - public boolean equals(Object o) { - if (o == null || !(o instanceof SimSlotCapability) || hashCode() != o.hashCode()) { - return false; - } - - if (this == o) { - return true; - } - - SimSlotCapability s = (SimSlotCapability) o; - - return (mPhysicalSlotIndex == s.mPhysicalSlotIndex && mSlotType == s.mSlotType); - } - - /** - * {@link Parcelable#describeContents} - */ - public int describeContents() { - return 0; - } - - /** - * {@link Parcelable#writeToParcel} - */ - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mPhysicalSlotIndex); - dest.writeInt(mSlotType); - } - - public static final @NonNull Parcelable.Creator<SimSlotCapability> CREATOR = - new Parcelable.Creator() { - public SimSlotCapability createFromParcel(Parcel in) { - return new SimSlotCapability(in); - } - - public SimSlotCapability[] newArray(int size) { - return new SimSlotCapability[size]; - } - }; -} diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 6c920f1950ac..8479db64799c 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -2094,8 +2094,12 @@ public final class SmsManager { /** * Gets the total capacity of SMS storage on RUIM and SIM cards + * <p> + * This is the number of 176 byte EF-SMS records which can be stored on the RUIM or SIM card. + * <p> + * See 3GPP TS 31.102 - 4.2.25 - EF-SMS for more information * - * @return the total capacity count of SMS on RUIM and SIM cards + * @return the total number of SMS records which can be stored on the RUIM or SIM cards. * @hide */ @SystemApi diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 832771daa409..336aa0e6bda6 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -217,6 +217,20 @@ public class SubscriptionInfo implements Parcelable { private boolean mAreUiccApplicationsEnabled = true; /** + * Public copy constructor. + * @hide + */ + public SubscriptionInfo(SubscriptionInfo info) { + this(info.mId, info.mIccId, info.mSimSlotIndex, info.mDisplayName, info.mCarrierName, + info.mNameSource, info.mIconTint, info.mNumber, info.mDataRoaming, info.mIconBitmap, + info.mMcc, info.mMnc, info.mCountryIso, info.mIsEmbedded, info.mNativeAccessRules, + info.mCardString, info.mCardId, info.mIsOpportunistic, + info.mGroupUUID == null ? null : info.mGroupUUID.toString(), info.mIsGroupDisabled, + info.mCarrierId, info.mProfileClass, info.mSubscriptionType, info.mGroupOwner, + info.mCarrierConfigAccessRules, info.mAreUiccApplicationsEnabled); + } + + /** * @hide */ public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, @@ -291,13 +305,27 @@ public class SubscriptionInfo implements Parcelable { } /** - * @return the ICC ID. + * Returns the ICC ID if the calling app has been granted the READ_PRIVILEGED_PHONE_STATE + * permission, has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}), or + * is a device owner or profile owner that has been granted the READ_PHONE_STATE permission. + * The profile owner is an app that owns a managed profile on the device; for more details see + * <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile + * owner access is deprecated and will be removed in a future release. + * + * @return the ICC ID, or an empty string if one of these requirements is not met */ public String getIccId() { return this.mIccId; } /** + * @hide + */ + public void clearIccId() { + this.mIccId = ""; + } + + /** * @return the slot index of this Subscription's SIM card. */ public int getSimSlotIndex() { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 68b6683e5426..0660776c3868 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -47,7 +47,6 @@ import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.ConnectivityManager; -import android.net.NetworkStats; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; @@ -1877,24 +1876,6 @@ public class TelephonyManager { // /** - * Returns the {@link PhoneCapability} for the device or null if it is not available. - * <p> - * Requires Permission: READ_PHONE_STATE or that the calling app has - * carrier privileges (see {@link #hasCarrierPrivileges}). - */ - @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) - @Nullable - public PhoneCapability getPhoneCapability() { - try { - ITelephony telephony = getITelephony(); - return telephony == null ? null : - telephony.getPhoneCapability(getSubId(), getOpPackageName(), getFeatureId()); - } catch (RemoteException ex) { - return null; - } - } - - /** * Returns the software version number for the device, for example, * the IMEI/SV for GSM phones. Return null if the software version is * not available. @@ -6180,9 +6161,11 @@ public class TelephonyManager { * @param AID Application id. See ETSI 102.221 and 101.220. * @param p2 P2 parameter (described in ISO 7816-4). * @return an IccOpenLogicalChannelResponse object. - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.SEService#getUiccReader(int)}, + * {@link android.se.omapi.Reader#openSession()}, + * {@link android.se.omapi.Session#openLogicalChannel(byte[], byte)}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, int p2) { return iccOpenLogicalChannel(getSubId(), AID, p2); @@ -6214,9 +6197,11 @@ public class TelephonyManager { * @param p2 P2 parameter (described in ISO 7816-4). * @return an IccOpenLogicalChannelResponse object. * @hide - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.SEService#getUiccReader(int)}, + * {@link android.se.omapi.Reader#openSession()}, + * {@link android.se.omapi.Session#openLogicalChannel(byte[], byte)}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID, int p2) { try { @@ -6245,9 +6230,9 @@ public class TelephonyManager { * iccOpenLogicalChannel. * @return true if the channel was closed successfully. * @hide - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.Channel#close()}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @@ -6275,9 +6260,9 @@ public class TelephonyManager { * @param channel is the channel id to be closed as returned by a successful * iccOpenLogicalChannel. * @return true if the channel was closed successfully. - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.Channel#close()}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public boolean iccCloseLogicalChannel(int channel) { return iccCloseLogicalChannel(getSubId(), channel); @@ -6297,9 +6282,9 @@ public class TelephonyManager { * iccOpenLogicalChannel. * @return true if the channel was closed successfully. * @hide - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.Channel#close()}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public boolean iccCloseLogicalChannel(int subId, int channel) { try { @@ -6336,9 +6321,9 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at the end, or null if * there is an issue connecting to the Telephony service. * @hide - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @@ -6377,9 +6362,9 @@ public class TelephonyManager { * @param data Data to be sent with the APDU. * @return The APDU response from the ICC card with the status appended at * the end. - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public String iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data) { @@ -6409,9 +6394,9 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at * the end. * @hide - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public String iccTransmitApduLogicalChannel(int subId, int channel, int cla, int instruction, int p1, int p2, int p3, String data) { @@ -6448,9 +6433,12 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at * the end. * @hide - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.SEService#getUiccReader(int)}, + * {@link android.se.omapi.Reader#openSession()}, + * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)}, + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @@ -6487,9 +6475,12 @@ public class TelephonyManager { * @param data Data to be sent with the APDU. * @return The APDU response from the ICC card with the status appended at * the end. - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.SEService#getUiccReader(int)}, + * {@link android.se.omapi.Reader#openSession()}, + * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)}, + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public String iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, int p3, String data) { @@ -6517,9 +6508,12 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at * the end. * @hide - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.SEService#getUiccReader(int)}, + * {@link android.se.omapi.Reader#openSession()}, + * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)}, + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public String iccTransmitApduBasicChannel(int subId, int cla, int instruction, int p1, int p2, int p3, String data) { @@ -6548,9 +6542,12 @@ public class TelephonyManager { * @param p3 P3 value of the APDU command. * @param filePath * @return The APDU response. - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.SEService#getUiccReader(int)}, + * {@link android.se.omapi.Reader#openSession()}, + * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)}, + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, String filePath) { @@ -6573,9 +6570,12 @@ public class TelephonyManager { * @param filePath * @return The APDU response. * @hide - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.SEService#getUiccReader(int)}, + * {@link android.se.omapi.Reader#openSession()}, + * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)}, + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2, int p3, String filePath) { @@ -6602,9 +6602,12 @@ public class TelephonyManager { * @return The APDU response from the ICC card in hexadecimal format * with the last 4 bytes being the status word. If the command fails, * returns an empty string. - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.SEService#getUiccReader(int)}, + * {@link android.se.omapi.Reader#openSession()}, + * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)}, + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public String sendEnvelopeWithStatus(String content) { return sendEnvelopeWithStatus(getSubId(), content); @@ -6625,9 +6628,12 @@ public class TelephonyManager { * with the last 4 bytes being the status word. If the command fails, * returns an empty string. * @hide - * @deprecated Use {@link android.se.omapi.SEService} APIs instead. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See + * {@link android.se.omapi.SEService#getUiccReader(int)}, + * {@link android.se.omapi.Reader#openSession()}, + * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)}, + * {@link android.se.omapi.Channel#transmit(byte[])}. */ - // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. @Deprecated public String sendEnvelopeWithStatus(int subId, String content) { try { @@ -11082,28 +11088,6 @@ public class TelephonyManager { } /** - * Get aggregated video call data usage since boot. - * Permissions android.Manifest.permission.READ_NETWORK_USAGE_HISTORY is required. - * - * @param how one of the NetworkStats.STATS_PER_* constants depending on whether the request is - * for data usage per uid or overall usage. - * @return Snapshot of video call data usage - * @hide - */ - public NetworkStats getVtDataUsage(int how) { - boolean perUidStats = (how == NetworkStats.STATS_PER_UID); - try { - ITelephony service = getITelephony(); - if (service != null) { - return service.getVtDataUsage(getSubId(), perUidStats); - } - } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#getVtDataUsage", e); - } - return null; - } - - /** * Policy control of data connection. Usually used when data limit is passed. * @param enabled True if enabling the data, otherwise disabling. * @hide diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java index 1b583fd29965..80c38cbfc39a 100644..100755 --- a/telephony/java/android/telephony/ims/ImsCallSession.java +++ b/telephony/java/android/telephony/ims/ImsCallSession.java @@ -16,6 +16,8 @@ package android.telephony.ims; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Message; import android.os.RemoteException; import android.telephony.CallQuality; @@ -451,6 +453,21 @@ public class ImsCallSession { } /** + * Received success response for call transfer request. + */ + public void callSessionTransferred(@NonNull ImsCallSession session) { + // no-op + } + + /** + * Received failure response for call transfer request. + */ + public void callSessionTransferFailed(@NonNull ImsCallSession session, + @Nullable ImsReasonInfo reasonInfo) { + // no-op + } + + /** * Called when the IMS service reports a change to the call quality. */ public void callQualityChanged(CallQuality callQuality) { @@ -795,6 +812,41 @@ public class ImsCallSession { } /** + * Transfers an ongoing call. + * + * @param number number to be transferred to. + * @param isConfirmationRequired indicates blind or assured transfer. + */ + public void transfer(@NonNull String number, boolean isConfirmationRequired) { + if (mClosed) { + return; + } + + try { + miSession.transfer(number, isConfirmationRequired); + } catch (RemoteException e) { + } + } + + /** + * Transfers a call to another ongoing call. + * + * @param transferToSession the other ImsCallSession to which this session will be transferred. + */ + public void transfer(@NonNull ImsCallSession transferToSession) { + if (mClosed) { + return; + } + + try { + if (transferToSession != null) { + miSession.consultativeTransfer(transferToSession.getSession()); + } + } catch (RemoteException e) { + } + } + + /** * Terminates a call. * * @see Listener#callSessionTerminated @@ -1410,6 +1462,20 @@ public class ImsCallSession { } } + @Override + public void callSessionTransferred() { + if (mListener != null) { + mListener.callSessionTransferred(ImsCallSession.this); + } + } + + @Override + public void callSessionTransferFailed(@Nullable ImsReasonInfo reasonInfo) { + if (mListener != null) { + mListener.callSessionTransferFailed(ImsCallSession.this, reasonInfo); + } + } + /** * Call quality updated */ diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl index cc2ebb9b20bd..36d2067ad016 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl @@ -148,6 +148,12 @@ oneway interface IImsCallSessionListener { void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile); /** + * Notifies the result of transfer request. + */ + void callSessionTransferred(); + void callSessionTransferFailed(in ImsReasonInfo reasonInfo); + + /** * Notifies of a change to the call quality. * @param callQuality then updated call quality */ diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java index 75bd6a7dc648..06aa6428b1b2 100644..100755 --- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java +++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java @@ -16,6 +16,8 @@ package android.telephony.ims.compat.stub; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Message; import android.os.RemoteException; @@ -197,6 +199,29 @@ public class ImsCallSessionImplBase extends IImsCallSession.Stub { } /** + * Transfer an established call to given number, disconnecting the ongoing call + * when the transfer is complete. + * + * @param number number to transfer the call + * @param isConfirmationRequired when {@code true}, then the {@link ImsCallSessionImplBase} + * should wait until the transfer has successfully completed before disconnecting the current + * {@link ImsCallSessionImplBase}. When {@code false}, the {@link ImsCallSessionImplBase} + * should signal the network to perform the transfer, but should immediately disconnect the + * call regardless of the outcome of the transfer. + */ + @Override + public void transfer(@NonNull String number, boolean isConfirmationRequired) { + } + + /** + * Transfer an established call to an existing ongoing session. + * When the transfer is complete, the current call gets disconnected locally. + */ + @Override + public void consultativeTransfer(@NonNull IImsCallSession transferToSession) { + } + + /** * Rejects an incoming call or session update. * * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}. @@ -610,6 +635,17 @@ public class ImsCallSessionImplBase extends IImsCallSession.Stub { } @Override + public void callSessionTransferred() throws RemoteException { + mNewListener.callSessionTransferred(); + } + + @Override + public void callSessionTransferFailed(@Nullable ImsReasonInfo reasonInfo) + throws RemoteException { + mNewListener.callSessionTransferFailed(reasonInfo); + } + + @Override public void callQualityChanged(CallQuality callQuality) throws RemoteException { mNewListener.callQualityChanged(callQuality); } diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java index e8f69ea64a22..73ba0e393e78 100644 --- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java @@ -16,6 +16,7 @@ package android.telephony.ims.stub; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Message; @@ -183,6 +184,18 @@ public class ImsCallSessionImplBase implements AutoCloseable { } @Override + public void transfer(@NonNull String number, boolean isConfirmationRequired) { + ImsCallSessionImplBase.this.transfer(number, isConfirmationRequired); + } + + @Override + public void consultativeTransfer(@NonNull IImsCallSession transferToSession) { + ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase(); + otherSession.setServiceImpl(transferToSession); + ImsCallSessionImplBase.this.transfer(otherSession); + } + + @Override public void terminate(int reason) { ImsCallSessionImplBase.this.terminate(reason); } @@ -423,6 +436,26 @@ public class ImsCallSessionImplBase implements AutoCloseable { } /** + * Transfer an established call to given number + * + * @param number number to transfer the call + * @param isConfirmationRequired if {@code True}, indicates Assured transfer, + * if {@code False} it indicates Blind transfer. + * @hide + */ + public void transfer(@NonNull String number, boolean isConfirmationRequired) { + } + + /** + * Transfer an established call to another call session + * + * @param otherSession The other ImsCallSession to transfer the ongoing session to. + * @hide + */ + public void transfer(@NonNull ImsCallSessionImplBase otherSession) { + } + + /** * Terminates a call. * * @param reason reason code to terminate a call, defined in {@link ImsReasonInfo}. diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl index 15234e5c0e92..0466efc2f6c6 100644 --- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl +++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl @@ -18,7 +18,6 @@ package com.android.ims.internal; import android.os.Message; import android.telephony.ims.aidl.IImsCallSessionListener; - import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsStreamMediaProfile; import com.android.ims.internal.IImsVideoCallProvider; @@ -151,6 +150,22 @@ interface IImsCallSession { void reject(int reason); /** + * Transfer an established call to given number + * + * @param number number to transfer the call + * @param isConfirmationRequired if {@code True}, indicates Assured transfer, + * if {@code False} it indicates Blind transfer. + */ + void transfer(String number, boolean isConfirmationRequired); + + /** + * Transfer an established call to another call session + * + * @param transferToSession The other ImsCallSession to transfer the ongoing session to. + */ + void consultativeTransfer(in IImsCallSession transferToSession); + + /** * Terminates a call. * * @see Listener#callSessionTerminated diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl index b33a9f1ad23b..1c62cc48093c 100644 --- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl +++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl @@ -184,6 +184,12 @@ oneway interface IImsCallSessionListener { void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile); /** + * Notifies about the response for call transfer request. + */ + void callSessionTransferred(); + + void callSessionTransferFailed(in ImsReasonInfo reasonInfo); + /** * Notifies of a change to the call quality. * @param callQuality then updated call quality */ diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index 1449a62fbf35..f61d4e14f1d3 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -114,6 +114,7 @@ public class DctConstants { public static final int EVENT_SERVICE_STATE_CHANGED = BASE + 52; public static final int EVENT_5G_TIMER_HYSTERESIS = BASE + 53; public static final int EVENT_5G_TIMER_WATCHDOG = BASE + 54; + public static final int EVENT_UPDATE_CARRIER_CONFIGS = BASE + 55; /***** Constants *****/ @@ -123,4 +124,6 @@ public class DctConstants { public static final String APN_TYPE_KEY = "apnType"; public static final String PROVISIONING_URL_KEY = "provisioningUrl"; + public static final String BANDWIDTH_SOURCE_MODEM_KEY = "modem"; + public static final String BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY = "carrier_config"; } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 168c8b64c194..861925fd66e5 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -39,7 +39,6 @@ import android.telephony.ICellInfoCallback; import android.telephony.ModemActivityInfo; import android.telephony.NeighboringCellInfo; import android.telephony.NetworkScanRequest; -import android.telephony.PhoneCapability; import android.telephony.PhoneNumberRange; import android.telephony.RadioAccessFamily; import android.telephony.RadioAccessSpecifier; @@ -1624,16 +1623,6 @@ interface ITelephony { void carrierActionResetAll(int subId); /** - * Get aggregated video call data usage since boot. - * Permissions android.Manifest.permission.READ_NETWORK_USAGE_HISTORY is required. - * - * @param perUidStats True if requesting data usage per uid, otherwise overall usage. - * @return Snapshot of video call data usage - * @hide - */ - NetworkStats getVtDataUsage(int subId, boolean perUidStats); - - /** * Gets the voice call forwarding info {@link CallForwardingInfo}, given the call forward * reason. * @@ -1899,17 +1888,12 @@ interface ITelephony { /** * Return the network selection mode on the subscription with id {@code subId}. */ - int getNetworkSelectionMode(int subId); + int getNetworkSelectionMode(int subId); - /** - * Return the PhoneCapability for the device. - */ - PhoneCapability getPhoneCapability(int subId, String callingPackage, String callingFeatureId); - - /** + /** * Return true if the device is in emergency sms mode, false otherwise. */ - boolean isInEmergencySmsMode(); + boolean isInEmergencySmsMode(); /** * Return the modem radio power state for slot index. diff --git a/tests/BootImageProfileTest/TEST_MAPPING b/tests/BootImageProfileTest/DISABLED_TEST_MAPPING index 1b569f9455bf..1b569f9455bf 100644 --- a/tests/BootImageProfileTest/TEST_MAPPING +++ b/tests/BootImageProfileTest/DISABLED_TEST_MAPPING diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java index 52f6eba4072b..e616ac46830f 100644 --- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java +++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java @@ -27,6 +27,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.TimeUnit; + /** * Runs rollback tests for multiple users. */ @@ -41,7 +43,6 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test { @After public void tearDown() throws Exception { - getDevice().switchUser(mOriginalUserId); getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A"); removeSecondaryUserIfNecessary(); } @@ -49,9 +50,9 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test { @Before public void setup() throws Exception { mOriginalUserId = getDevice().getCurrentUser(); - installPackageAsUser("RollbackTest.apk", true, mOriginalUserId); - createAndSwitchToSecondaryUserIfNecessary(); - installPackageAsUser("RollbackTest.apk", true, mSecondaryUserId); + createAndStartSecondaryUser(); + // TODO(b/149733368): Remove the '-g' workaround when the bug is fixed. + installPackage("RollbackTest.apk", "-g --user all"); } @Test @@ -64,7 +65,6 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test { runPhaseForUsers("testMultipleUsersInstallV1", mOriginalUserId, mSecondaryUserId); runPhaseForUsers("testMultipleUsersUpgradeToV2", mOriginalUserId); runPhaseForUsers("testMultipleUsersUpdateUserData", mOriginalUserId, mSecondaryUserId); - switchToUser(mOriginalUserId); getDevice().executeShellCommand("pm rollback-app com.android.cts.install.lib.testapp.A"); runPhaseForUsers("testMultipleUsersVerifyUserdataRollback", mOriginalUserId, mSecondaryUserId); @@ -74,11 +74,11 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test { * Run the phase for the given user ids, in the order they are given. */ private void runPhaseForUsers(String phase, int... userIds) throws Exception { + final long timeout = TimeUnit.MINUTES.toMillis(10); for (int userId: userIds) { - switchToUser(userId); - assertTrue(runDeviceTests("com.android.tests.rollback", + assertTrue(runDeviceTests(getDevice(), "com.android.tests.rollback", "com.android.tests.rollback.MultiUserRollbackTest", - phase)); + phase, userId, timeout)); } } @@ -89,21 +89,7 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test { } } - private void createAndSwitchToSecondaryUserIfNecessary() throws Exception { - if (mSecondaryUserId == -1) { - mOriginalUserId = getDevice().getCurrentUser(); - mSecondaryUserId = getDevice().createUser("MultiUserRollbackTest_User" - + System.currentTimeMillis()); - switchToUser(mSecondaryUserId); - } - } - - private void switchToUser(int userId) throws Exception { - if (getDevice().getCurrentUser() == userId) { - return; - } - - assertTrue(getDevice().switchUser(userId)); + private void awaitUserUnlocked(int userId) throws Exception { for (int i = 0; i < SWITCH_USER_COMPLETED_NUMBER_OF_POLLS; ++i) { String userState = getDevice().executeShellCommand("am get-started-user-state " + userId); @@ -112,6 +98,14 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test { } Thread.sleep(SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS); } - fail("User switch to user " + userId + " timed out"); + fail("Timed out in unlocking user: " + userId); + } + + private void createAndStartSecondaryUser() throws Exception { + String name = "MultiUserRollbackTest_User" + System.currentTimeMillis(); + mSecondaryUserId = getDevice().createUser(name); + getDevice().startUser(mSecondaryUserId); + // Note we can't install apps on a locked user + awaitUserUnlocked(mSecondaryUserId); } } diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java index 0ffe041b0377..400bb04f0fab 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java @@ -17,13 +17,11 @@ package com.android.tests.rollback; import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat; -import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage; import static com.google.common.truth.Truth.assertThat; import android.Manifest; import android.content.rollback.RollbackInfo; -import android.content.rollback.RollbackManager; import com.android.cts.install.lib.Install; import com.android.cts.install.lib.InstallUtils; @@ -77,13 +75,10 @@ public class MultiUserRollbackTest { */ @Test public void testMultipleUsersUpgradeToV2() throws Exception { - RollbackManager rm = RollbackUtils.getRollbackManager(); assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); Install.single(TestApp.A2).setEnableRollback().commit(); assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); - RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TestApp.A); - assertThat(rollback).isNotNull(); + RollbackInfo rollback = RollbackUtils.waitForAvailableRollback(TestApp.A); assertThat(rollback).packagesContainsExactly( Rollback.from(TestApp.A2).to(TestApp.A1)); } diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml index 638b6d1d7b5a..480b12be91c8 100644 --- a/tests/net/AndroidManifest.xml +++ b/tests/net/AndroidManifest.xml @@ -50,6 +50,7 @@ <application> <uses-library android:name="android.test.runner" /> + <uses-library android:name="android.net.ipsec.ike" /> </application> <instrumentation diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt index 490c46794e3d..23caf4952991 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt @@ -26,6 +26,7 @@ import android.net.util.SharedLog import android.os.IBinder import com.android.networkstack.metrics.DataStallStatsUtils import com.android.networkstack.netlink.TcpSocketTracker +import com.android.server.NetworkStackService import com.android.server.NetworkStackService.NetworkMonitorConnector import com.android.server.NetworkStackService.NetworkStackConnector import com.android.server.connectivity.NetworkMonitor @@ -88,6 +89,7 @@ class TestNetworkStackService : Service() { val nm = NetworkMonitor(this@TestNetworkStackService, cb, this.network, mock(IpConnectivityLog::class.java), mock(SharedLog::class.java), + mock(NetworkStackService.NetworkStackServiceManager::class.java), NetworkMonitorDeps(privateDnsBypassNetwork), mock(DataStallStatsUtils::class.java), mock(TcpSocketTracker::class.java)) diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java index d6a2176d7e81..2273bc61225c 100644 --- a/tests/net/java/android/net/Ikev2VpnProfileTest.java +++ b/tests/net/java/android/net/Ikev2VpnProfileTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; import android.test.mock.MockContext; @@ -232,10 +231,12 @@ public class Ikev2VpnProfileTest { builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa); final VpnProfile profile = builder.build().toVpnProfile(); + final String expectedSecret = Ikev2VpnProfile.PREFIX_INLINE + + Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded()); verifyVpnProfileCommon(profile); assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert); assertEquals( - Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded()), + expectedSecret, profile.ipsecSecret); assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 220cdce0d178..6d4a1b265171 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -1180,6 +1180,10 @@ public class ConnectivityServiceTest { Arrays.asList(new UserInfo[] { new UserInfo(VPN_USER, "", 0), })); + final ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; + when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) + .thenReturn(applicationInfo); // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. // http://b/25897652 . @@ -3042,7 +3046,7 @@ public class ConnectivityServiceTest { networkCapabilities.addTransportType(TRANSPORT_WIFI) .setNetworkSpecifier(new MatchAllNetworkSpecifier()); mService.requestNetwork(networkCapabilities, null, 0, null, - ConnectivityManager.TYPE_WIFI, TEST_PACKAGE_NAME); + ConnectivityManager.TYPE_WIFI, mContext.getPackageName()); }); class NonParcelableSpecifier extends NetworkSpecifier { @@ -6439,17 +6443,89 @@ public class ConnectivityServiceTest { assertEquals(wifiLp, mService.getActiveLinkProperties()); } + private void setupLocationPermissions( + int targetSdk, boolean locationToggle, String op, String perm) throws Exception { + final ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.targetSdkVersion = targetSdk; + when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) + .thenReturn(applicationInfo); + + when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle); + + if (op != null) { + when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName()))) + .thenReturn(AppOpsManager.MODE_ALLOWED); + } + + if (perm != null) { + mServiceContext.setPermission(perm, PERMISSION_GRANTED); + } + } + + private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) { + final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid); + + return mService + .maybeSanitizeLocationInfoForCaller(netCap, callerUid, mContext.getPackageName()) + .getOwnerUid(); + } + + @Test + public void testMaybeSanitizeLocationInfoForCallerWithFineLocationAfterQ() throws Exception { + setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION); + + final int myUid = Process.myUid(); + assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); + } + + @Test + public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationPreQ() throws Exception { + setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION); + + final int myUid = Process.myUid(); + assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); + } + + @Test + public void testMaybeSanitizeLocationInfoForCallerLocationOff() throws Exception { + // Test that even with fine location permission, and UIDs matching, the UID is sanitized. + setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION); + + final int myUid = Process.myUid(); + assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); + } + + @Test + public void testMaybeSanitizeLocationInfoForCallerWrongUid() throws Exception { + // Test that even with fine location permission, not being the owner leads to sanitization. + setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION); + + final int myUid = Process.myUid(); + assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid)); + } + @Test - public void testNetworkCapabilitiesRestrictedForCallerPermissions() { - int callerUid = Process.myUid(); - final NetworkCapabilities originalNc = new NetworkCapabilities(); - originalNc.setOwnerUid(callerUid); + public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationAfterQ() throws Exception { + // Test that not having fine location permission leads to sanitization. + setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION); + + // Test that without the location permission, the owner field is sanitized. + final int myUid = Process.myUid(); + assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); + } - final NetworkCapabilities newNc = - mService.networkCapabilitiesRestrictedForCallerPermissions( - originalNc, Process.myPid(), callerUid); + @Test + public void testMaybeSanitizeLocationInfoForCallerWithoutLocationPermission() throws Exception { + setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */); - assertEquals(Process.INVALID_UID, newNc.getOwnerUid()); + // Test that without the location permission, the owner field is sanitized. + final int myUid = Process.myUid(); + assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); } private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) @@ -6735,21 +6811,6 @@ public class ConnectivityServiceTest { mContext.getOpPackageName())); } - private void setupLocationPermissions( - int targetSdk, boolean locationToggle, String op, String perm) throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); - applicationInfo.targetSdkVersion = targetSdk; - when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) - .thenReturn(applicationInfo); - - when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle); - - when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName()))) - .thenReturn(AppOpsManager.MODE_ALLOWED); - - mServiceContext.setPermission(perm, PERMISSION_GRANTED); - } - private void setUpConnectivityDiagnosticsCallback() throws Exception { final NetworkRequest request = new NetworkRequest.Builder().build(); when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder); diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 0e3b79761319..1994d1f2ed45 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -59,9 +59,15 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.net.Ikev2VpnProfile; +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.net.IpSecManager; +import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo.DetailedState; +import android.net.RouteInfo; import android.net.UidRange; import android.net.VpnManager; import android.net.VpnService; @@ -84,6 +90,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; +import com.android.server.IpSecService; import org.junit.Before; import org.junit.Test; @@ -93,6 +100,7 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.net.Inet4Address; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -125,6 +133,9 @@ public class VpnTest { } static final String TEST_VPN_PKG = "com.dummy.vpn"; + private static final String TEST_VPN_SERVER = "1.2.3.4"; + private static final String TEST_VPN_IDENTITY = "identity"; + private static final byte[] TEST_VPN_PSK = "psk".getBytes(); /** * Names and UIDs for some fake packages. Important points: @@ -151,23 +162,39 @@ public class VpnTest { @Mock private Vpn.SystemServices mSystemServices; @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator; @Mock private ConnectivityManager mConnectivityManager; + @Mock private IpSecService mIpSecService; @Mock private KeyStore mKeyStore; - private final VpnProfile mVpnProfile = new VpnProfile("key"); + private final VpnProfile mVpnProfile; + + private IpSecManager mIpSecManager; + + public VpnTest() throws Exception { + // Build an actual VPN profile that is capable of being converted to and from an + // Ikev2VpnProfile + final Ikev2VpnProfile.Builder builder = + new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY); + builder.setAuthPsk(TEST_VPN_PSK); + mVpnProfile = builder.build().toVpnProfile(); + } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mIpSecManager = new IpSecManager(mContext, mIpSecService); + when(mContext.getPackageManager()).thenReturn(mPackageManager); setMockedPackages(mPackages); - when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName()); + when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG); + when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG); when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager); when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps); when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE))) .thenReturn(mNotificationManager); when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE))) .thenReturn(mConnectivityManager); + when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager); when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)) .thenReturn(Resources.getSystem().getString( R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)); @@ -962,6 +989,26 @@ public class VpnTest { // a subsequent CL. } + @Test + public void testStartLegacyVpn() throws Exception { + final Vpn vpn = createVpn(primaryUser.id); + setMockedUsers(primaryUser); + + // Dummy egress interface + final String egressIface = "DUMMY0"; + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(egressIface); + + final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), + InetAddresses.parseNumericAddress("192.0.2.0"), egressIface); + lp.addRoute(defaultRoute); + + vpn.startLegacyVpn(mVpnProfile, mKeyStore, lp); + + // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in + // a subsequent CL. + } + /** * Mock some methods of vpn object. */ diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java index 957216e17925..26916bcffcfb 100644 --- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java +++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java @@ -38,6 +38,7 @@ public final class FrameworksTestsFilter extends SelectTest { "android.app.activity.ActivityThreadClientTest", // Test specifications for FrameworksCoreTests. "android.app.servertransaction.", // all tests under the package. + "android.view.CutoutSpecificationTest", "android.view.DisplayCutoutTest", "android.view.InsetsAnimationControlImplTest", "android.view.InsetsControllerTest", diff --git a/wifi/Android.bp b/wifi/Android.bp index 9f26203a3842..5c9fb4e86bc7 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -86,7 +86,6 @@ java_library { // TODO(b/146757305): should be unnecessary once // sdk_version="module_lib_current" "android_system_stubs_current", - "framework_mediaprovider_annotation", // for android.annotation.CurrentTimeMillisLong ], srcs: [ ":framework-wifi-updatable-sources", diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index af2f2461ac94..bab9a9ecefbf 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -46,6 +46,7 @@ import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.ProvisioningCallback; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; @@ -4920,7 +4921,10 @@ public class WifiManager { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage( + maxTargetSdk = Build.VERSION_CODES.Q, + publicAlternatives = "Use {@code #setVerboseLoggingEnabled(boolean)} instead." + ) @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void enableVerboseLogging (int verbose) { try { @@ -4948,7 +4952,10 @@ public class WifiManager { /** @hide */ // TODO(b/145484145): remove once SUW stops calling this via reflection - @UnsupportedAppUsage + @UnsupportedAppUsage( + maxTargetSdk = Build.VERSION_CODES.Q, + publicAlternatives = "Use {@code #isVerboseLoggingEnabled()} instead." + ) public int getVerboseLoggingLevel() { try { return mService.getVerboseLoggingLevel(); diff --git a/wifi/java/android/net/wifi/WifiOemMigrationHook.java b/wifi/java/android/net/wifi/WifiOemMigrationHook.java index 44dbb98a8ab8..5301dd013363 100755 --- a/wifi/java/android/net/wifi/WifiOemMigrationHook.java +++ b/wifi/java/android/net/wifi/WifiOemMigrationHook.java @@ -437,7 +437,7 @@ public final class WifiOemMigrationHook { Settings.Global.WIFI_SCAN_THROTTLE_ENABLED, 1) == 1) .setVerboseLoggingEnabled( Settings.Global.getInt(context.getContentResolver(), - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 1) == 1) + Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0) == 1) .build(); } } diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java index 7d9bdba81a76..4507cc2707d4 100644 --- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java +++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java @@ -900,12 +900,15 @@ public final class PasspointConfiguration implements Parcelable { } /** - * Get a unique identifier for a PasspointConfiguration object. + * Get a unique identifier for a PasspointConfiguration object. The identifier depends on the + * configuration that identify the service provider under the HomeSp subtree, and on the + * credential configuration under the Credential subtree. + * The method throws an {@link IllegalStateException} if the configuration under HomeSp subtree + * or the configuration under Credential subtree are not initialized. * * @return A unique identifier - * @throws IllegalStateException if Credential or HomeSP nodes are not initialized */ - public @NonNull String getUniqueId() throws IllegalStateException { + public @NonNull String getUniqueId() { if (mCredential == null || mHomeSp == null || TextUtils.isEmpty(mHomeSp.getFqdn())) { throw new IllegalStateException("Credential or HomeSP are not initialized"); } diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java index 8f6beb19091b..638efb9f14ee 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java @@ -426,17 +426,11 @@ public class PasspointConfigurationTest { * * @throws Exception */ - @Test + @Test (expected = IllegalStateException.class) public void validateUniqueIdExceptionWithEmptyHomeSp() throws Exception { PasspointConfiguration config = PasspointTestUtils.createConfig(); config.setHomeSp(null); - boolean exceptionCaught = false; - try { - String uniqueId = config.getUniqueId(); - } catch (IllegalStateException e) { - exceptionCaught = true; - } - assertTrue(exceptionCaught); + String uniqueId = config.getUniqueId(); } /** @@ -445,16 +439,10 @@ public class PasspointConfigurationTest { * * @throws Exception */ - @Test + @Test (expected = IllegalStateException.class) public void validateUniqueIdExceptionWithEmptyCredential() throws Exception { PasspointConfiguration config = PasspointTestUtils.createConfig(); config.setCredential(null); - boolean exceptionCaught = false; - try { - String uniqueId = config.getUniqueId(); - } catch (IllegalStateException e) { - exceptionCaught = true; - } - assertTrue(exceptionCaught); + String uniqueId = config.getUniqueId(); } } |