Merge "Revert "Migrate Statsd to the apex""
diff --git a/Android.bp b/Android.bp
index b3c9e2a..68efd59 100644
--- a/Android.bp
+++ b/Android.bp
@@ -393,7 +393,7 @@
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 +597,7 @@
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 +688,7 @@
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",
@@ -1127,7 +1128,6 @@
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 +1327,6 @@
libs: [
"framework-minus-apex",
"unsupportedappusage",
- "ike-stubs",
],
static_libs: [
"libphonenumber-platform",
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 7b3764a..aae33d7 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.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 @@
// 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 @@
@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 @@
}
@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 @@
@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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
if (shouldRemove) {
blobMetadata.getBlobFile().delete();
- mKnownBlobIds.remove(blobMetadata.getBlobId());
+ mActiveBlobIds.remove(blobMetadata.getBlobId());
deletedBlobIds.add(blobMetadata.getBlobId());
}
return shouldRemove;
@@ -837,7 +879,7 @@
if (shouldRemove) {
blobStoreSession.getSessionFile().delete();
- mKnownBlobIds.remove(blobStoreSession.getSessionId());
+ mActiveBlobIds.remove(blobStoreSession.getSessionId());
indicesToRemove.add(j);
deletedBlobIds.add(blobStoreSession.getSessionId());
}
@@ -884,7 +926,7 @@
}
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 dc72d6d..f8b598a 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 @@
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 789f20b..b63cc19 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.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 @@
| 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 @@
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 @@
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 9d6e012..932c25d 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.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.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 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 @@
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 e343478..a4ab31d 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.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 @@
* 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 @@
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 @@
}
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 @@
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 @@
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 @@
|| 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 @@
}
}
+ /**
+ * 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 @@
}
@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 @@
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 @@
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 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 @@
"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 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 @@
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/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
index 6c7f82a..0d163cf 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 @@
* @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 @@
* @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 @@
*
* @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 90b1c4b..205ffc2 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 @@
@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 @@
}
@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 @@
}
@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 2908a38..64d6545 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 @@
* @return the roles read
*/
@Nullable
- RolesState read(@NonNull UserHandle user);
+ RolesState readAsUser(@NonNull UserHandle user);
/**
* Write the roles to persistence.
@@ -50,7 +50,7 @@
* @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 @@
*
* @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 06fad77..3031c82 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 @@
@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 @@
}
@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 @@
}
@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 0e93110..86a3a7d 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -21,6 +21,8 @@
apex_defaults {
native_shared_libs: [
"libstats_jni",
+ "libstatspull",
+ "libstatssocket",
],
// binaries: ["vold"],
java_libs: [
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index f7a8176..487c8e1 100644
--- a/apex/statsd/aidl/Android.bp
+++ b/apex/statsd/aidl/Android.bp
@@ -38,6 +38,13 @@
},
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/api/current.txt b/api/current.txt
index a0b38cd..fd2ca59 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9,6 +9,7 @@
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 @@
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 @@
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);
@@ -12465,6 +12466,7 @@
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 +23176,7 @@
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 +23491,54 @@
}
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 +23849,7 @@
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 +23859,7 @@
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 +23891,7 @@
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);
@@ -31744,7 +31735,7 @@
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 +43394,12 @@
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";
}
@@ -46559,8 +46551,8 @@
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 +46805,6 @@
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 +47066,350 @@
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 +47572,8 @@
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 +47763,6 @@
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 +48119,6 @@
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();
@@ -53240,11 +53486,13 @@
method public android.graphics.Canvas lockHardwareCanvas();
method public void readFromParcel(android.os.Parcel);
method public void release();
- method public void setFrameRate(@FloatRange(from=0.0) float);
+ method public void setFrameRate(@FloatRange(from=0.0) float, int);
method @Deprecated public void unlockCanvas(android.graphics.Canvas);
method public void unlockCanvasAndPost(android.graphics.Canvas);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.Surface> CREATOR;
+ field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0
+ field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1
field public static final int ROTATION_0 = 0; // 0x0
field public static final int ROTATION_180 = 2; // 0x2
field public static final int ROTATION_270 = 3; // 0x3
@@ -53284,7 +53532,7 @@
method @NonNull public android.view.SurfaceControl.Transaction reparent(@NonNull android.view.SurfaceControl, @Nullable android.view.SurfaceControl);
method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float);
method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
- method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float);
+ method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int);
method @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.view.SurfaceControl.Transaction setVisibility(@NonNull android.view.SurfaceControl, boolean);
@@ -56479,7 +56727,7 @@
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;
}
@@ -56487,7 +56735,7 @@
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 a7dbf38..330d03f 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -118,6 +118,7 @@
field public static final String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
+ field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
@@ -136,7 +137,6 @@
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";
@@ -375,6 +375,7 @@
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";
@@ -887,7 +888,7 @@
field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
field public static final String ACTION_PROVISION_FINANCED_DEVICE = "android.app.action.PROVISION_FINANCED_DEVICE";
field public static final String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
- field public static final String ACTION_RESET_PROTECTION_POLICY_CHANGED = "android.app.action.RESET_PROTECTION_POLICY_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION) public static final String ACTION_RESET_PROTECTION_POLICY_CHANGED = "android.app.action.RESET_PROTECTION_POLICY_CHANGED";
field public static final String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
field public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
@@ -1957,6 +1958,11 @@
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();
@@ -3774,8 +3780,14 @@
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";
@@ -3822,7 +3834,6 @@
public final class GnssCapabilities {
method public boolean hasGeofencing();
- method public boolean hasGnssAntennaInfo();
method public boolean hasLowPowerMode();
method public boolean hasMeasurementCorrections();
method public boolean hasMeasurementCorrectionsExcessPathLength();
@@ -4162,7 +4173,6 @@
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);
@@ -9768,6 +9778,7 @@
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";
@@ -10211,6 +10222,7 @@
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";
}
@@ -11388,347 +11400,7 @@
}
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 957794c..8a0be69 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -846,6 +846,11 @@
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();
@@ -3145,6 +3150,7 @@
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 f56dd6e..95de6c5 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 @@
}
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 @@
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 @@
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 @@
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 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 93ea881..7202b45 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 @@
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 874604c..dade415 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 @@
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 @@
args.argi1 = id;
args.argi2 = vid;
args.argi3 = pid;
+ args.argi4 = bus;
if (name != null) {
args.arg1 = name;
} else {
@@ -115,7 +116,7 @@
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 62587a7..d4bf1d8 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 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 @@
return mPid;
}
+ public int getBus() {
+ return mBus.getValue();
+ }
+
public byte[] getReport() {
return mReport;
}
@@ -94,6 +114,7 @@
+ ", 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 @@
mEvent.mPid = pid;
}
+ public void setBus(Bus bus) {
+ mEvent.mBus = bus;
+ }
+
public void setDuration(int duration) {
mEvent.mDuration = duration;
}
@@ -206,6 +231,9 @@
case "pid":
eb.setPid(readInt());
break;
+ case "bus":
+ eb.setBus(readBus());
+ break;
case "report":
eb.setReport(readData());
break;
@@ -264,6 +292,11 @@
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 0ee2cc4..fac0ab2 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 @@
"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 93522d4..4991a95 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -299,6 +299,11 @@
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 +313,6 @@
shared_libs: [
"libprotobuf-cpp-lite",
- "libstatssocket"
],
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index a4e8fdc..43d0fce 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -392,6 +392,7 @@
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 @@
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 c1e2195..c373284 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -27,6 +27,7 @@
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.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 @@
* {@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 9912d2b..d537ce1 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -22,10 +22,12 @@
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 @@
* 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/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 9ed4798..8f02f15 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1035,10 +1035,12 @@
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 @@
@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 @@
OP_MANAGE_EXTERNAL_STORAGE,
OP_INTERACT_ACROSS_PROFILES,
OP_LOADER_USAGE_STATS,
+ OP_ACCESS_CALL_AUDIO,
};
/**
@@ -1525,6 +1531,7 @@
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 @@
OPSTR_INTERACT_ACROSS_PROFILES,
OPSTR_ACTIVATE_PLATFORM_VPN,
OPSTR_LOADER_USAGE_STATS,
+ OPSTR_ACCESS_CALL_AUDIO,
};
/**
@@ -1730,6 +1738,7 @@
"INTERACT_ACROSS_PROFILES",
"ACTIVATE_PLATFORM_VPN",
"LOADER_USAGE_STATS",
+ "ACCESS_CALL_AUDIO",
};
/**
@@ -1834,6 +1843,7 @@
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 @@
null, // INTERACT_ACROSS_PROFILES
null, // ACTIVATE_PLATFORM_VPN
null, // LOADER_USAGE_STATS
+ null, // ACCESS_CALL_AUDIO
};
/**
@@ -2041,6 +2052,7 @@
false, // INTERACT_ACROSS_PROFILES
false, // ACTIVATE_PLATFORM_VPN
false, // LOADER_USAGE_STATS
+ false, // ACCESS_CALL_AUDIO
};
/**
@@ -2143,6 +2155,7 @@
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 @@
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 130e2ec..6b1afda 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -256,10 +256,10 @@
};
@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 229bee5..5bc9992 100644
--- a/core/java/android/app/DexLoadReporter.java
+++ b/core/java/android/app/DexLoadReporter.java
@@ -28,9 +28,8 @@
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 @@
}
@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 0287564..8eb7e72 100644
--- a/core/java/android/app/SharedElementCallback.java
+++ b/core/java/android/app/SharedElementCallback.java
@@ -19,7 +19,6 @@
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 @@
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 @@
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 @@
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 @@
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 f1559f7..be87f5c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -186,6 +186,7 @@
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 @@
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 @@
* @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 @@
* @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 @@
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 d08dbc6..139b179 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1416,6 +1416,7 @@
* @see #setFactoryResetProtectionPolicy
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION)
@SystemApi
public static final String ACTION_RESET_PROTECTION_POLICY_CHANGED =
"android.app.action.RESET_PROTECTION_POLICY_CHANGED";
@@ -11989,4 +11990,21 @@
}
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 84332ca..25c1e12 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -478,4 +478,5 @@
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 4be7e6d..4ec9476 100644
--- a/core/java/android/content/integrity/AppInstallMetadata.java
+++ b/core/java/android/content/integrity/AppInstallMetadata.java
@@ -42,6 +42,9 @@
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 @@
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 @@
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 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 @@
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 @@
}
/**
+ * 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 d911eab..977a631 100644
--- a/core/java/android/content/integrity/AtomicFormula.java
+++ b/core/java/android/content/integrity/AtomicFormula.java
@@ -47,12 +47,14 @@
/** @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 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 @@
}
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 @@
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 @@
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 @@
}
/**
- * 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 @@
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 @@
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 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 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 @@
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 @@
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 @@
|| 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 c5e5c8a..fc177721 100644
--- a/core/java/android/content/integrity/IntegrityFormula.java
+++ b/core/java/android/content/integrity/IntegrityFormula.java
@@ -90,8 +90,7 @@
return new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
}
- private Application() {
- }
+ private Application() {}
}
/** Factory class for creating integrity formulas based on installer. */
@@ -117,26 +116,45 @@
*/
@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 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 @@
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/core/java/android/service/controls/IControlsLoadCallback.aidl b/core/java/android/content/pm/AndroidTestBaseUpdater.java
similarity index 61%
copy from core/java/android/service/controls/IControlsLoadCallback.aidl
copy to core/java/android/content/pm/AndroidTestBaseUpdater.java
index bfc61cd..1cbbdca 100644
--- a/core/java/android/service/controls/IControlsLoadCallback.aidl
+++ b/core/java/android/content/pm/AndroidTestBaseUpdater.java
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2020, 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.
* 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,13 @@
* limitations under the License.
*/
-package android.service.controls;
-
-import android.service.controls.Control;
+package android.content.pm;
/**
+ * 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
*/
-oneway interface IControlsLoadCallback {
- void accept(in IBinder token, in List<Control> controls);
-}
\ No newline at end of file
+public class AndroidTestBaseUpdater {
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index b89901a..e9cdbf28 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -482,19 +482,12 @@
* 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 9e85fc3..29a55b7 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -76,4 +76,6 @@
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 168679e..1de82450 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.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.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.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 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 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 @@
* 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 @@
}
/**
- * 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 @@
* <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 @@
* <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 @@
}
}
- 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 da7623a..30cf4e7 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_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 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 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/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 2863b26..fe4b36f 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -20,7 +20,6 @@
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 @@
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 bde4f61..49e8c05 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1726,11 +1726,11 @@
}
/**
- * @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 3eea3f6..35c99a1 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -24,6 +24,7 @@
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 @@
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 4cd201f..cdb1d22 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -22,7 +22,6 @@
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 @@
*
* 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 @@
* 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 @@
}
/**
- * 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 2003ce2..0000000
--- 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 b7595d2..0000000
--- 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 9087f42..4c6da03 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -50,7 +50,7 @@
/** @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 @@
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 905794b..0000000
--- 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 6852a8c..0000000
--- 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 d06865b..0000000
--- 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 72df189..0000000
--- 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 0000000..e7d91c2
--- /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 74a2640..aa93d80 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 @@
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 @@
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 @@
@Nullable SparseArray<int[]> splitDependencies
);
- ParsingPackage setAppMetaData(Bundle appMetaData);
+ ParsingPackage setMetaData(Bundle metaData);
ParsingPackage setForceQueryable(boolean forceQueryable);
@@ -119,8 +120,6 @@
ParsingPackage setMinAspectRatio(float minAspectRatio);
- ParsingPackage setName(String name);
-
ParsingPackage setPermission(String permission);
ParsingPackage setProcessName(String processName);
@@ -137,9 +136,9 @@
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 @@
ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting);
- ParsingPackage setIsOverlay(boolean isOverlay);
+ ParsingPackage setOverlay(boolean isOverlay);
ParsingPackage setBackupInForeground(boolean backupInForeground);
@@ -173,7 +172,7 @@
ParsingPackage setHasFragileUserData(boolean hasFragileUserData);
- ParsingPackage setIsGame(boolean isGame);
+ ParsingPackage setGame(boolean isGame);
ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading);
@@ -221,8 +220,6 @@
ParsingPackage setAppComponentFactory(String appComponentFactory);
- ParsingPackage setApplicationVolumeUuid(String applicationVolumeUuid);
-
ParsingPackage setBackupAgentName(String backupAgentName);
ParsingPackage setBanner(int banner);
@@ -233,8 +230,6 @@
ParsingPackage setClassName(String className);
- ParsingPackage setCodePath(String codePath);
-
ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp);
ParsingPackage setDescriptionRes(int descriptionRes);
@@ -247,8 +242,6 @@
ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
- ParsingPackage setIcon(int icon);
-
ParsingPackage setIconRes(int iconRes);
ParsingPackage setInstallLocation(int installLocation);
@@ -307,17 +300,17 @@
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 @@
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 0000000..c3eea2b
--- /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 0000000..048b924
--- /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 0000000..40754df
--- /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 0000000..ba61de1
--- /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 0000000..c4caedc
--- /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 0000000..5495c22
--- /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 0000000..555cdd0
--- /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 0000000..098d620
--- /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 0000000..b37b617
--- /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 0000000..b8a9098
--- /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 0000000..fb52801
--- /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 0000000..396a145
--- /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 0000000..89645fc
--- /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 0000000..0ba92cc
--- /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 0000000..a7b950b
--- /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 0000000..59e9a84
--- /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 0000000..6188f89
--- /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 0000000..6c36ecb
--- /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 0000000..741c00c
--- /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 0000000..1884a1e
--- /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 0000000..da7bf98
--- /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 0000000..4825066
--- /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 0000000..d2c531d
--- /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 0000000..aa5ea8d
--- /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 0000000..591eef7
--- /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 0000000..8a8a066
--- /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 0000000..c468506
--- /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 0000000..338048c
--- /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 0000000..9b22f09
--- /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 0a76bed..7714dd8 100644
--- a/core/java/android/debug/AdbManager.java
+++ b/core/java/android/debug/AdbManager.java
@@ -31,6 +31,114 @@
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 51eb7fc..0bd9f19 100644
--- a/core/java/android/debug/AdbManagerInternal.java
+++ b/core/java/android/debug/AdbManagerInternal.java
@@ -42,7 +42,7 @@
/**
* 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
similarity index 62%
rename from core/java/android/service/controls/IControlsLoadCallback.aidl
rename to core/java/android/debug/AdbTransportType.aidl
index bfc61cd..6904615 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 c48fc07..aea7633 100644
--- a/core/java/android/debug/IAdbManager.aidl
+++ b/core/java/android/debug/IAdbManager.aidl
@@ -43,6 +43,62 @@
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 77211fc93..f018813 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 0000000..2d5b446
--- /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 24d9311..cc0c1a30 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -688,17 +688,19 @@
* <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/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 41e1443..f0fab6a 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -267,7 +267,7 @@
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 @@
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)},
+ 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.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.YUV_420_888, SizeThreshold.s720p)},
- "In-app video / image processing with preview"),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)},
+ "Standard stil image capture"),
new StreamCombinationTemplate(new StreamTemplate [] {
- new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
- new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p)},
- "Standard Recording"),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)},
+ "Standard still image capture"),
};
/**
@@ -720,6 +735,7 @@
+ " 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 @@
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 086db10..d16f070 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 @@
* 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 @@
* 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 @@
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 @@
*/
@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 2a441de..f0b1eaa 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -19,7 +19,6 @@
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.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.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 @@
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 @@
@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 b1aa67e..20a4ab3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -34,7 +34,6 @@
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.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.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 @@
*/
@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 @@
// 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 @@
}
@MainThread
- private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName,
+ private void handleOnCreateInlineSuggestionsRequest(
+ @NonNull InlineSuggestionsRequestInfo requestInfo,
@NonNull IInlineSuggestionsRequestCallback callback) {
if (!mInputStarted) {
try {
@@ -779,8 +783,9 @@
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/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 42b4da1..f19a341 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -25,7 +25,10 @@
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 @@
* 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 @@
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 @@
@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 @@
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 @@
}
/**
+ * 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 @@
/** @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/os/UserManager.java b/core/java/android/os/UserManager.java
index 6d1f646..84fd580 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -33,8 +33,8 @@
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 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 @@
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 f4e1f96..dea495b 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -434,6 +434,11 @@
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 6516917..17adfc8 100644
--- a/core/java/android/os/incremental/V4Signature.java
+++ b/core/java/android/os/incremental/V4Signature.java
@@ -31,7 +31,9 @@
*/
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 @@
}
}
+ 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/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 4bd31f8..a2def7f 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -20,6 +20,8 @@
import android.annotation.Nullable;
import android.os.IVold;
+import java.util.Set;
+
/**
* Mount service local interface.
*
@@ -98,6 +100,12 @@
}
/**
+ * 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 4523acb..b9abdf8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8760,6 +8760,13 @@
"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 @@
* 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 @@
*
* @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 4aafb63..29069e7 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -25,6 +25,7 @@
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 @@
}
/**
+ * 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 de4c056..cb20db9 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 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 @@
* 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);
-
- /**
- * (Optional) 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.
- */
- public void loadSuggestedControls(int maxNumber, @NonNull Consumer<List<Control>> consumer) {
- // Override to change the default behavior
+ @Deprecated
+ public void loadAvailableControls(@NonNull Consumer<List<Control>> consumer) {
+ // pending removal
consumer.accept(Collections.emptyList());
}
/**
- * 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.
+ * 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) 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}. 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.
+ */
+ @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 {@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 @@
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 @@
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));
- break;
+ case MSG_LOAD: {
+ 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.publisherForAllAvailable();
+ if (publisher == null) {
+ ControlsProviderService.this.loadAvailableControls(consumerFor(proxy));
+ } else {
+ publisher.subscribe(proxy);
+ }
break;
+ }
- case MSG_SUBSCRIBE:
+ case MSG_LOAD_SUGGESTED: {
+ final IControlsSubscriber cs = (IControlsSubscriber) msg.obj;
+ final SubscriberProxy proxy = new SubscriberProxy(true, mToken, cs);
+
+ 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: {
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);
- break;
+ final SubscriberProxy proxy = new SubscriberProxy(false, mToken,
+ sMsg.mSubscriber);
- case MSG_ACTION:
+ ControlsProviderService.this.publisherFor(sMsg.mControlIds).subscribe(proxy);
+ break;
+ }
+
+ 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 @@
};
}
- 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 boolean isStatelessControl(Control control) {
- return (control.getStatus() == Control.STATUS_UNKNOWN
- && control.getControlTemplate().getTemplateType() == ControlTemplate.TYPE_NONE
- && TextUtils.isEmpty(control.getStatusText()));
+ 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;
+
+ 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 @@
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 4375fbb..0cb06b4 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 @@
* @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/view/Surface.java b/core/java/android/view/Surface.java
index 4ac6a66..13d6dd6 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.system.OsConstants.EINVAL;
+
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -89,7 +91,8 @@
private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled);
private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled);
- private static native int nativeSetFrameRate(long nativeObject, float frameRate);
+ private static native int nativeSetFrameRate(
+ long nativeObject, float frameRate, int compatibility);
public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
new Parcelable.Creator<Surface>() {
@@ -184,6 +187,28 @@
*/
public static final int ROTATION_270 = 3;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"},
+ value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE})
+ public @interface FrameRateCompatibility {}
+
+ // From native_window.h. Keep these in sync.
+ /**
+ * There are no inherent restrictions on the frame rate of this surface.
+ */
+ public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0;
+
+ /**
+ * This surface is being used to display content with an inherently fixed frame rate,
+ * e.g. a video that has a specific frame rate. When the system selects a frame rate
+ * other than what the app requested, the app will need to do pull down or use some
+ * other technique to adapt to the system's frame rate. The user experience is likely
+ * to be worse (e.g. more frame stuttering) than it would be if the system had chosen
+ * the app's requested frame rate.
+ */
+ public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1;
+
/**
* Create an empty surface, which will later be filled in by readFromParcel().
* @hide
@@ -864,11 +889,23 @@
* called. The frameRate param does *not* need to be a valid refresh rate for this
* device's display - e.g., it's fine to pass 30fps to a device that can only run the
* display at 60fps.
+ *
+ * @param compatibility The frame rate compatibility of this surface. The
+ * compatibility value may influence the system's choice of display frame rate. See
+ * the FRAME_RATE_COMPATIBILITY_* values for more info.
+ *
+ * @throws IllegalArgumentException If frameRate or compatibility are invalid.
*/
- public void setFrameRate(@FloatRange(from = 0.0) float frameRate) {
- int error = nativeSetFrameRate(mNativeObject, frameRate);
- if (error != 0) {
- throw new RuntimeException("Failed to set frame rate on Surface");
+ public void setFrameRate(
+ @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility);
+ if (error == -EINVAL) {
+ throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");
+ } else if (error != 0) {
+ throw new RuntimeException("Failed to set frame rate on Surface");
+ }
}
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 29371b0..0816e84 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -214,7 +214,7 @@
@Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius);
private static native void nativeSetFrameRate(
- long transactionObj, long nativeObject, float frameRate);
+ long transactionObj, long nativeObject, float frameRate, int compatibility);
private final CloseGuard mCloseGuard = CloseGuard.get();
private String mName;
@@ -2738,13 +2738,17 @@
* isn't called. The frameRate param does *not* need to be a valid refresh
* rate for this device's display - e.g., it's fine to pass 30fps to a
* device that can only run the display at 60fps.
+ * @param compatibility The frame rate compatibility of this surface. The compatibility
+ * value may influence the system's choice of display frame rate. See
+ * the Surface.FRAME_RATE_COMPATIBILITY_* values for more info.
* @return This transaction object.
*/
@NonNull
- public Transaction setFrameRate(
- @NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate) {
+ public Transaction setFrameRate(@NonNull SurfaceControl sc,
+ @FloatRange(from = 0.0) float frameRate,
+ @Surface.FrameRateCompatibility int compatibility) {
checkPreconditions(sc);
- nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate);
+ nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate, compatibility);
return this;
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index deff79d5..73707ca 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1586,6 +1586,19 @@
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 4c7307e..11ab572 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13442,8 +13442,7 @@
* @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/inline/InlinePresentationSpec.java b/core/java/android/view/inline/InlinePresentationSpec.java
index 8bda339..3cc04b8 100644
--- a/core/java/android/view/inline/InlinePresentationSpec.java
+++ b/core/java/android/view/inline/InlinePresentationSpec.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.os.Parcelable;
import android.util.Size;
@@ -40,15 +41,13 @@
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 @@
/* 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 @@
}
/**
- * 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 @@
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 @@
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 @@
private @NonNull Size mMinSize;
private @NonNull Size mMaxSize;
- private @Nullable String mStyle;
+ private @Nullable Bundle mStyle;
private long mBuilderFieldsSet = 0L;
@@ -247,13 +244,11 @@
}
/**
- * 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 @@
}
@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 91e15c1..71c9e33 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -21,17 +21,16 @@
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 @@
/**
* 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 dbab81b1..39d5f5c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -93,12 +93,7 @@
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 @@
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 @@
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 @@
*/
@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 @@
} 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 @@
}
@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 @@
*/
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 @@
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 12f245e..22af9af 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -83,6 +83,7 @@
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;
@@ -394,6 +395,19 @@
// 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.
@@ -440,8 +454,6 @@
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);
float aspectRatio = AppGlobals.getFloatCoreSetting(
@@ -454,13 +466,20 @@
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 +4921,12 @@
}
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 +5136,16 @@
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 {
@@ -6012,7 +6044,13 @@
@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()) {
@@ -6043,8 +6081,8 @@
}
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 +6095,58 @@
}
}
+ /**
+ * 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 +6169,8 @@
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 47ea1cb..a299b01 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -89,7 +89,7 @@
// 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 @@
}
/**
+ * 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 @@
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 @@
// 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 @@
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 @@
}
}
+ /**
+ * 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 @@
if (mBitmap != null) {
mBitmap.recycle();
}
+ mOverlay.setCallback(null);
}
private void doDraw() {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 2f1a15f..dc6942c 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -133,7 +133,7 @@
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 0ccc45e..04bf915 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.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 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 f699eb8..ffa347c 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 @@
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.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 @@
* 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 @@
@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 @@
* {@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 @@
/**
* Retrieves the singleton instance initialized by
- * {@link #initializeSystemInstance(AndroidPackageProvider)}.
+ * {@link #initializeSystemInstance(PackageProvider)}.
*/
@NonNull
public static OverlayConfig getSystemInstance() {
@@ -291,10 +291,10 @@
@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 bbae027..23b1ab5 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -18,6 +18,7 @@
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 @@
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 18066dc..27c7cb6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1000,6 +1000,8 @@
private int mMinLearnedBatteryCapacity = -1;
private int mMaxLearnedBatteryCapacity = -1;
+ private long mBatteryTimeToFullSeconds = -1;
+
private long[] mCpuFreqs;
@VisibleForTesting
@@ -12226,7 +12228,7 @@
@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 @@
mMinLearnedBatteryCapacity = Math.min(mMinLearnedBatteryCapacity, chargeFullUAh);
}
mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh);
+
+ mBatteryTimeToFullSeconds = chargeTimeToFullSeconds;
}
public static boolean isOnBattery(int plugType, int status) {
@@ -12578,19 +12582,10 @@
// 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 @@
if (msPerLevel <= 0) {
return -1;
}
- return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;
+ return (msPerLevel * (100 - mCurrentBatteryLevel)) * 1000;
}
/*@hide */
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 4dac542..9b2bcfb 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -186,6 +186,17 @@
}
/**
+ * 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 @@
}
/**
+ * 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 390c596..6258a69 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 @@
*/
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/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 475a321..fd4b5ab 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.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 @@
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 41f902e..4509032 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -28,6 +28,7 @@
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/android/service/controls/IControlsLoadCallback.aidl b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.aidl
similarity index 62%
copy from core/java/android/service/controls/IControlsLoadCallback.aidl
copy to core/java/com/android/internal/view/InlineSuggestionsRequestInfo.aidl
index bfc61cd..8125c0d 100644
--- a/core/java/android/service/controls/IControlsLoadCallback.aidl
+++ b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.aidl
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2020, 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.
* 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,6 @@
* limitations under the License.
*/
-package android.service.controls;
+package com.android.internal.view;
-import android.service.controls.Control;
-
-/**
- * @hide
- */
-oneway interface IControlsLoadCallback {
- void accept(in IBinder token, in List<Control> controls);
-}
\ No newline at end of file
+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 0000000..6148490
--- /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 a5964b5..f29e95c 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -89,57 +89,64 @@
*/
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 @@
*
* @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 @@
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 @@
* 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_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index b01083b..8a53bd0 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -413,10 +413,15 @@
return anw->perform(surface, NATIVE_WINDOW_SET_AUTO_REFRESH, int(enabled));
}
-static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate) {
+static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate,
+ jint compatibility) {
Surface* surface = reinterpret_cast<Surface*>(nativeObject);
ANativeWindow* anw = static_cast<ANativeWindow*>(surface);
- return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, float(frameRate));
+ // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and
+ // NATIVE_WINDOW_SET_FRAME_RATE takes an
+ // ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The values are identical
+ // though, so no need to explicitly convert.
+ return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, float(frameRate), compatibility);
}
// ----------------------------------------------------------------------------
@@ -453,7 +458,7 @@
(void*)nativeAttachAndQueueBufferWithColorSpace},
{"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled},
{"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
- {"nativeSetFrameRate", "(JF)I", (void*)nativeSetFrameRate},
+ {"nativeSetFrameRate", "(JFI)I", (void*)nativeSetFrameRate},
};
int register_android_view_Surface(JNIEnv* env)
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 741ce82..a9ef257 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -613,11 +613,14 @@
}
static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
- jfloat frameRate) {
+ jfloat frameRate, jint compatibility) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
const auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
- transaction->setFrameRate(ctrl, frameRate);
+ // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and
+ // Transaction::setFrameRate() takes an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The
+ // values are identical though, so no need to convert anything.
+ transaction->setFrameRate(ctrl, frameRate, static_cast<int8_t>(compatibility));
}
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
@@ -1467,7 +1470,7 @@
(void*)nativeSetLayerStack },
{"nativeSetShadowRadius", "(JJF)V",
(void*)nativeSetShadowRadius },
- {"nativeSetFrameRate", "(JJF)V",
+ {"nativeSetFrameRate", "(JJFI)V",
(void*)nativeSetFrameRate },
{"nativeGetPhysicalDisplayIds", "()[J",
(void*)nativeGetPhysicalDisplayIds },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 27c5a73..93449ff 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -186,6 +186,7 @@
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 d91911c..e4141e0 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -105,10 +105,12 @@
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 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 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 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 @@
}
}
+// 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 @@
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 6530036..ddfc4b8 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" />
@@ -645,6 +648,9 @@
<protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" />
+ <!-- Added in R -->
+ <protected-broadcast android:name="android.app.action.RESET_PROTECTION_POLICY_CHANGED" />
+
<!-- For tether entitlement recheck-->
<protected-broadcast
android:name="com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM" />
@@ -1197,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 -->
<!-- ====================================================================== -->
@@ -1951,6 +1966,18 @@
android:description="@string/permdesc_modifyAudioSettings"
android:protectionLevel="normal" />
+ <!-- ======================================== -->
+ <!-- Permissions for factory reset protection -->
+ <!-- ======================================== -->
+ <eat-comment />
+
+ <!-- @SystemApi Allows an application to set a factory reset protection (FRP) policy.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.MANAGE_FACTORY_RESET_PROTECTION"
+ android:protectionLevel="signature|privileged"/>
+
<!-- ================================== -->
<!-- Permissions for accessing hardware -->
<!-- ================================== -->
@@ -2747,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 c15b794..68c86b2 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 e6a93e5..d513e2b 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 85c2a2a..1c9e2cd 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/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 8e4e684..33fead6 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -83,21 +83,13 @@
":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 ddf75b2..0000000
--- 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 6cc5eba..0000000
--- 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 92b09ed..0000000
--- 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 82a7b2c..9f0af60 100644
--- a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
@@ -90,6 +90,12 @@
}
@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 62c9c98..7e4c138 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 @@
@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 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 @@
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 @@
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 @@
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 a24b4e0..78c88d7 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.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 @@
@Mock
private IControlsActionCallback.Stub mActionCallback;
@Mock
- private IControlsLoadCallback.Stub mLoadCallback;
- @Mock
private IControlsSubscriber.Stub mSubscriber;
@Mock
private IIntentSender mIIntentSender;
@@ -79,8 +78,6 @@
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 @@
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 @@
.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 @@
}
@Override
- public void loadSuggestedControls(int maxNumber, Consumer<List<Control>> cb) {
- cb.accept(mControls);
- }
-
- @Override
public Publisher<Control> publisherFor(List<String> ids) {
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));
+ }
+ };
+ }
+
+ @Override
+ public Publisher<Control> publisherForSuggested() {
+ return new Publisher<Control>() {
+ public void subscribe(final Subscriber s) {
+ s.onSubscribe(createSubscription(s, mControls));
}
};
}
@@ -269,7 +276,19 @@
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/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index a602fa3..d7abfcc 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.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 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;
@@ -50,9 +56,15 @@
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);
@@ -119,13 +131,11 @@
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 +143,15 @@
onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("7")));
onView(withId(R.id.textview)).check(hasSelection(not(emptyString())));
+ // 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.
- int index = text.indexOf("line9");
- onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index));
- onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line7"), text.indexOf("1")));
onView(withId(R.id.textview)).check(hasSelection(not(emptyString())));
}
@@ -154,13 +167,11 @@
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 +179,14 @@
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 +401,14 @@
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 +420,68 @@
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 +514,89 @@
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/com/android/internal/content/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
index 23655a0..fbf75df 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.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 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 @@
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 @@
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 @@
}
return scanner;
};
- mAndroidPackageProvider = null;
+ mPkgProvider = null;
mIteration = Iteration.ZYGOTE;
base.evaluate();
@@ -131,14 +131,15 @@
// 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 @@
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 08b30f7..78c7b76d 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -410,6 +410,7 @@
<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/location/java/android/location/GnssAntennaInfo.java b/location/java/android/location/GnssAntennaInfo.java
index dfcaf81..b2f9a0f 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 {
+ public interface Listener {
/**
- * 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;
-
- /**
- * 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 @@
* 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;
+ 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;
- @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 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<PhaseCenterOffsetCoordinates> CREATOR =
- new Creator<PhaseCenterOffsetCoordinates>() {
+ 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,33 +90,39 @@
}
@Override
- public PhaseCenterOffsetCoordinates[] newArray(int size) {
- return new PhaseCenterOffsetCoordinates[size];
+ public PhaseCenterOffset[] newArray(int size) {
+ return new PhaseCenterOffset[size];
}
};
- public double getXCoordMillimeters() {
- return mPhaseCenterOffsetCoordinateXMillimeters;
+ @FloatRange()
+ public double getXOffsetMm() {
+ return mOffsetXMm;
}
- public double getXCoordUncertaintyMillimeters() {
- return mPhaseCenterOffsetCoordinateXUncertaintyMillimeters;
+ @FloatRange()
+ public double getXOffsetUncertaintyMm() {
+ return mOffsetXUncertaintyMm;
}
- public double getYCoordMillimeters() {
- return mPhaseCenterOffsetCoordinateYMillimeters;
+ @FloatRange()
+ public double getYOffsetMm() {
+ return mOffsetYMm;
}
- public double getYCoordUncertaintyMillimeters() {
- return mPhaseCenterOffsetCoordinateYUncertaintyMillimeters;
+ @FloatRange()
+ public double getYOffsetUncertaintyMm() {
+ return mOffsetYUncertaintyMm;
}
- public double getZCoordMillimeters() {
- return mPhaseCenterOffsetCoordinateZMillimeters;
+ @FloatRange()
+ public double getZOffsetMm() {
+ return mOffsetZMm;
}
- public double getZCoordUncertaintyMillimeters() {
- return mPhaseCenterOffsetCoordinateZUncertaintyMillimeters;
+ @FloatRange()
+ public double getZOffsetUncertaintyMm() {
+ return mOffsetZUncertaintyMm;
}
@Override
@@ -167,30 +132,27 @@
@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);
+ 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("PhaseCenteroffset:\n");
- builder.append("X: " + mPhaseCenterOffsetCoordinateXMillimeters + " +/- "
- + mPhaseCenterOffsetCoordinateXUncertaintyMillimeters + "\n");
- builder.append("Y: " + mPhaseCenterOffsetCoordinateYMillimeters + " +/- "
- + mPhaseCenterOffsetCoordinateYUncertaintyMillimeters + "\n");
- builder.append("Z: " + mPhaseCenterOffsetCoordinateZMillimeters + " +/- "
- + mPhaseCenterOffsetCoordinateZUncertaintyMillimeters + "\n");
- return builder.toString();
+ return "PhaseCenterOffset{"
+ + "OffsetXMm=" + mOffsetXMm + " +/-" + mOffsetXUncertaintyMm
+ + ", OffsetYMm=" + mOffsetYMm + " +/-" + mOffsetYUncertaintyMm
+ + ", OffsetZMm=" + mOffsetZMm + " +/-" + mOffsetZUncertaintyMm
+ + '}';
}
}
/**
- * Class containing information about the phase center variation (PCV) corrections. The PCV
- * correction is added to the phase measurement 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.
*
@@ -203,229 +165,7 @@
* 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();
- }
-
- 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<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;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder("PhaseCenterVariationCorrections:\n");
- builder.append(super.toString());
- return builder.toString();
- }
- }
-
- /**
- * Class containing information about the signal gain (SG) corrections. The SG
- * correction is added to the signal gain 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 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 @@
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 @@
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 @@
}
}
- 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 @@
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 @@
@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 930180c..5734bf2 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
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 30bf5467..603ed6a 100644
--- a/location/java/android/location/IGnssAntennaInfoListener.aidl
+++ b/location/java/android/location/IGnssAntennaInfoListener.aidl
@@ -23,5 +23,4 @@
*/
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 03e1c75..19085bf 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1813,13 +1813,7 @@
/**
* 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 @@
}
/**
- * 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 @@
}
private class GnssAntennaInfoListenerManager extends
- AbstractListenerManager<Void, GnssAntennaInfo.Callback> {
+ AbstractListenerManager<Void, GnssAntennaInfo.Listener> {
@Nullable
private IGnssAntennaInfoListener mListenerTransport;
@@ -3075,11 +3070,6 @@
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/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index d058243..8deb0c4 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -512,15 +512,19 @@
* @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 5ecb8f0..2258ee5 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 @@
"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 a926d59..371ccc4 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 @@
private native Long nativeGetSourceTime();
private native int nativeClose();
+ private long mNativeContext;
+
private boolean mEnable = false;
// Called by JNI code
@@ -139,6 +143,9 @@
*/
@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_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index f4d2d03..4f31f6c 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -118,10 +118,12 @@
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 @@
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 @@
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 @@
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_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 @@
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 d899bbd..c5590b9 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::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 @@
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 @@
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/native/android/surface_control.cpp b/native/android/surface_control.cpp
index ba793e8..0af6cbf 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -547,16 +547,11 @@
}
void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* aSurfaceTransaction,
- ASurfaceControl* aSurfaceControl, float frameRate) {
+ ASurfaceControl* aSurfaceControl, float frameRate,
+ int8_t compatibility) {
CHECK_NOT_NULL(aSurfaceTransaction);
CHECK_NOT_NULL(aSurfaceControl);
-
- sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
- if (frameRate < 0) {
- ALOGE("Failed to set frame ate - invalid frame rate");
- return;
- }
-
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
- transaction->setFrameRate(surfaceControl, frameRate);
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ transaction->setFrameRate(surfaceControl, frameRate, compatibility);
}
diff --git a/packages/DynamicSystemInstallationService/AndroidManifest.xml b/packages/DynamicSystemInstallationService/AndroidManifest.xml
index d718eae..b4d520d 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 7595d2b..25b7fc1 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>
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 9bae223..7affe88 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -80,6 +80,7 @@
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 @@
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 @@
// 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 @@
}
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);
@@ -463,7 +469,12 @@
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 @@
break;
}
- Log.d(TAG, "status=" + statusString + ", cause=" + causeString);
+ Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail);
boolean notifyOnNotificationBar = true;
@@ -538,7 +549,7 @@
}
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 438c435..f8952ac 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 @@
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 @@
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 @@
InstallationAsyncTask(
String url,
String dsuSlot,
+ String publicKey,
long systemSize,
long userdataSize,
Context context,
@@ -122,12 +155,20 @@
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 @@
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 @@
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 @@
}
}
- private void installImages() throws IOException, InterruptedException {
+ private void installImages()
+ throws IOException, InterruptedException, ImageValidationException {
if (mStream != null) {
if (mIsZip) {
installStreamingZipUpdate();
@@ -306,12 +349,14 @@
}
}
- 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 @@
}
}
- 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 @@
}
}
- 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 @@
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 @@
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 123559a..a428cb3 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 fb3c065..4436aab 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
similarity index 98%
rename from packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
rename to packages/OsuLogin/src/com/android/hotspot2/osulogin/OsuLoginActivity.java
index 3a994d7..d554745 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 androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
-import com.android.hotspot2.R;
-
import java.net.MalformedURLException;
import java.net.URL;
@@ -194,7 +192,7 @@
// 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 @@
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 59881e7..2813640 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>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 571c4ae..11bf24d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -72,11 +72,12 @@
@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 @@
}
@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/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 8a5aad8..cf5a4d3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -443,20 +443,7 @@
mStateChange.orderChanged |= repackAll();
}
- if (reason == BubbleController.DISMISS_AGED) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "overflowing bubble: " + bubbleToRemove);
- }
- mOverflowBubbles.add(0, bubbleToRemove);
- if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
- // Remove oldest bubble.
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "Overflow full. Remove bubble: " + mOverflowBubbles.get(
- mOverflowBubbles.size() - 1));
- }
- mOverflowBubbles.remove(mOverflowBubbles.size() - 1);
- }
- }
+ overflowBubble(reason, bubbleToRemove);
// Note: If mBubbles.isEmpty(), then mSelectedBubble is now null.
if (Objects.equals(mSelectedBubble, bubbleToRemove)) {
@@ -468,6 +455,25 @@
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: " + bubble);
+ }
+ mOverflowBubbles.add(0, bubble);
+
+ if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
+ // Remove oldest bubble.
+ if (DEBUG_BUBBLE_DATA) {
+ Log.d(TAG, "Overflow full. Remove bubble: " + mOverflowBubbles.get(
+ mOverflowBubbles.size() - 1));
+ }
+ mOverflowBubbles.remove(mOverflowBubbles.size() - 1);
+ }
+ }
+ }
+
public void dismissAll(@DismissReason int reason) {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "dismissAll: reason=" + reason);
@@ -478,9 +484,7 @@
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 756c598..eb836b1 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 @@
private BubbleOverflowAdapter mAdapter;
private RecyclerView mRecyclerView;
private List<Bubble> mOverflowBubbles = new ArrayList<>();
- private int mMaxBubbles;
@Inject
public BubbleOverflowActivity(BubbleController controller) {
@@ -68,7 +67,6 @@
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 @@
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 7f45cc8..0329183 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 @@
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 957ea8d..a796f3c 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 @@
// 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 87bdfa8..6ff1bbc 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.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 @@
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 @@
return ControlsProviderLifecycleManager(
context,
backgroundExecutor,
- loadCallbackService,
actionCallbackService,
subscriberService,
currentUser,
@@ -130,7 +122,7 @@
callback: ControlsBindingController.LoadCallback
) {
val provider = retrieveLifecycleManager(component)
- provider.maybeBindAndLoad(callback)
+ provider.maybeBindAndLoad(LoadSubscriber(callback))
}
override fun subscribe(controls: List<ControlInfo>) {
@@ -216,7 +208,8 @@
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 @@
return
}
}
- provider.lastLoadCallback?.accept(list) ?: run {
- Log.w(TAG, "Null callback")
- }
+ callback.accept(list)
provider.unbindService()
}
}
@@ -277,7 +268,7 @@
) : 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 @@
) : 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 @@
}
}
}
+
+ 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 d7f3c73..883f8a9 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 @@
}
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 9ec71c7..a53fcd4 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.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 @@
*
* @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 @@
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 @@
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 @@
}
}
- 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 @@
}
/**
- * 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 @@
* Request unbind from the service.
*/
fun unbindService() {
- lastLoadCallback = null
onLoadCanceller?.run()
onLoadCanceller = null
@@ -344,7 +336,7 @@
*/
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 b90f892..b2afd3c 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 @@
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 @@
}
}
- 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 89caace..ac5e089 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 @@
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 9952b97..af4a977 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 @@
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 d893caa..8e47f64 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 @@
@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 98cdf28..f4fd375 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 @@
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 071198b..d3d4287 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 @@
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 @@
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)
+ decorView
+ attributes.systemUiVisibility =
+ (attributes.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 */)
+ 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 @@
}
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 45d7397..cca56c2 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 @@
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 @@
}
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 b1db7df..374153c 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.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 @@
* 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 @@
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 @@
// the properties of the keyguard
- private KeyguardUpdateMonitor mUpdateMonitor;
+ private final KeyguardUpdateMonitor mUpdateMonitor;
/**
* Last SIM state reported by the telephony system.
@@ -610,6 +611,7 @@
@Override
public void keyguardGone() {
Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardGone");
+ mNotificationShadeWindowController.setKeyguardGoingAway(false);
mKeyguardDisplayManager.hide();
Trace.endSection();
}
@@ -696,7 +698,9 @@
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 @@
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 @@
}
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 @@
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 2c023ca..2ba0315 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 @@
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 @@
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 6c69718..011893d 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 @@
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 84891ec..6663237 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 @@
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 @@
}
@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 6ad9c40..8dad08e 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.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 @@
/**
* 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 @@
/**
* 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 @@
mIsStarting = false;
mIsRecording = true;
for (RecordingStateChangeCallback cb : mListeners) {
- cb.onRecordingEnd();
+ cb.onCountdownEnd();
}
try {
startIntent.send();
@@ -120,7 +121,7 @@
mIsStarting = false;
for (RecordingStateChangeCallback cb : mListeners) {
- cb.onRecordingEnd();
+ cb.onCountdownEnd();
}
}
@@ -144,16 +145,12 @@
* 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 @@
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 566f12b..26973d0 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 @@
*/
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 @@
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 2daefbd..56cdff4 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 @@
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 aaf4849..711d6a6d 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 @@
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.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 @@
@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 @@
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 @@
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 d0af106..f8db922 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.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.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.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.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.Executor;
import dagger.Lazy;
@@ -110,7 +111,7 @@
@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 @@
Lazy<NotificationShadeWindowController> notificationShadeWindowController,
NotificationEntryManager notificationEntryManager,
MediaArtworkProcessor mediaArtworkProcessor,
- KeyguardBypassController keyguardBypassController) {
+ KeyguardBypassController keyguardBypassController,
+ @Main Executor mainExecutor) {
mContext = context;
mMediaArtworkProcessor = mediaArtworkProcessor;
mKeyguardBypassController = keyguardBypassController;
@@ -194,6 +196,7 @@
mStatusBarLazy = statusBarLazy;
mNotificationShadeWindowController = notificationShadeWindowController;
mEntryManager = notificationEntryManager;
+ mMainExecutor = mainExecutor;
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
@@ -623,7 +626,7 @@
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 @@
};
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 9c626f7..12add8c 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 @@
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 @@
}
private void updateIconColor() {
+ if (!mTintIcons) {
+ setColorFilter(null);
+ return;
+ }
+
if (mCurrentSetColor != NO_COLOR) {
if (mMatrixColorFilter == null) {
mMatrix = new float[4 * 5];
@@ -953,6 +959,19 @@
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 0b37c22..cd5bb77 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.policy.RemoteInputUriController;
import com.android.systemui.tracing.ProtoTracer;
+import java.util.concurrent.Executor;
+
import javax.inject.Singleton;
import dagger.Lazy;
@@ -88,14 +90,16 @@
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 f482d37..25a832d 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_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.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.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.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 @@
* 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 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 @@
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 @@
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 @@
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 @@
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 234ab93..5008133 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 @@
* 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 d016217..2dd42c2 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.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 @@
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 @@
mLpChanged = new LayoutParams();
mKeyguardBypassController = keyguardBypassController;
mColorExtractor = colorExtractor;
+ dumpController.registerDumpable(this);
mLockScreenDisplayTimeout = context.getResources()
.getInteger(R.integer.config_lockScreenDisplayTimeout);
@@ -594,7 +597,7 @@
}
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 260f94c..1ab36c5 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 @@
}
@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 @@
@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 0487ce6..ca4b67d 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 @@
*
* @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/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index daea7a7..5e4f971 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 @@
// 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 b412ca5..6677b80 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 @@
// 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 44454d9..e5ab9be 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 @@
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 40075c8..02bfc19e 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 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class ControlsBindingControllerTest : SysuiTestCase() {
+class ControlsBindingControllerImplTest : SysuiTestCase() {
companion object {
fun <T> any(): T = Mockito.any<T>()
@@ -95,7 +95,7 @@
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 ddd6b12..a3e59e5 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 @@
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 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 @@
@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 @@
manager = ControlsProviderLifecycleManager(
context,
executor,
- loadCallbackService,
actionCallbackService,
subscriberService,
UserHandle.of(0),
@@ -113,31 +109,29 @@
@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 @@
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 9e7ce06..cd82844 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 @@
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 @@
private lateinit var subscriber: IControlsSubscriber
@Mock
- private lateinit var loadCallback: IControlsLoadCallback
-
- @Mock
private lateinit var actionCallback: IControlsActionCallback
@Captor
@@ -81,16 +77,16 @@
@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 acc30d9..9a707caa 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 @@
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 @@
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 @@
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 0000000..e8e98b4
--- /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 0000000..b877c7f
--- /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 72e6df2..a27c085 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 6a6e5c8..98f12ce 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.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 @@
@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 @@
@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 @@
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 @@
mock(HighPriorityProvider.class)),
mEnvironment,
mFeatureFlags,
- () -> notificationRowBinder,
+ () -> mNotificationRowBinder,
() -> mRemoteInputManager,
mLeakDetector,
mock(ForegroundServiceDismissalFeatureController.class)
@@ -259,152 +204,45 @@
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
- ));
+ setUserSentiment(mSbn.getKey(), Ranking.USER_SENTIMENT_NEUTRAL);
}
- @After
- public void tearDown() {
- // CLEAN UP inflation tasks so they don't callback in a future test
- mEntry.abortTask();
- }
-
- // 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 @@
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 8e330c6..45c51d4 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.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 @@
}
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 @@
@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 0000000..ac40808
--- /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 7d52df7..2782f3d 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 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 @@
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private SysuiColorExtractor mColorExtractor;
@Mock ColorExtractor.GradientColors mGradientColors;
+ @Mock private DumpController mDumpController;
private NotificationShadeWindowController mNotificationShadeWindowController;
@@ -69,7 +71,8 @@
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 0000000..73254cd
--- /dev/null
+++ b/packages/Tethering/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "TetheringTests"
+ }
+ ]
+}
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index b4d49c0..3acc766 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.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.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 @@
/** 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 @@
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 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 @@
@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 @@
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 @@
}
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 @@
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 @@
}
}
+ 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 @@
}
}
break;
+ case CMD_NEIGHBOR_EVENT:
+ handleNeighborEvent((NeighborEvent) message.obj);
+ break;
default:
return false;
}
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 acedfab..33b3558 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_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.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.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.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.MockitoAnnotations;
import java.net.Inet4Address;
+import java.net.InetAddress;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -88,6 +98,8 @@
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 @@
@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 @@
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 @@
}).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 @@
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 @@
@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 @@
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 @@
*
* @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 8e5aaf2..f2074bd 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.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 @@
@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 @@
}
}).run();
}
+
+ public IpNeighborMonitor getIpNeighborMonitor(Handler h, SharedLog l,
+ IpNeighborMonitor.NeighborEventConsumer c) {
+ return mIpNeighborMonitor;
+ }
}
private class MockTetheringConfiguration extends TetheringConfiguration {
diff --git a/services/api/current.txt b/services/api/current.txt
index 8a82e61..26a65f2 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -3,9 +3,9 @@
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 @@
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 0b8658c..7e7441f 100644
--- a/services/api/lint-baseline.txt
+++ b/services/api/lint-baseline.txt
@@ -19,17 +19,3 @@
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 1fc48d2..6daa106 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 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 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 @@
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/core/Android.bp b/services/core/Android.bp
index 6fc6084..228d9be 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -113,6 +113,7 @@
"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 76f6ef6..0f8d57e 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.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.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 @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 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 @@
/**
* 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 @@
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 c8894e7..f1f5005 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.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 @@
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 @@
}
private boolean shouldShutdownLocked() {
+ if (mHealthInfo2p1.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) {
+ return (mHealthInfo2p1.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL);
+ }
if (mHealthInfo.batteryLevel > 0) {
return false;
}
@@ -416,22 +422,23 @@
}
}
- 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 @@
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 @@
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/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 05820d2..7ec2a34 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 @@
/**
* {@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 @@
if (cur == null) {
break;
}
- if (filterEquals(cur, matching)) {
+ if (filterEquals(getIntentFilter(cur), matching)) {
if (res == null) {
res = new ArrayList<>();
}
@@ -178,7 +180,7 @@
} 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 @@
}
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 @@
if (printer == null) {
printer = new PrintWriterPrinter(out);
}
- filter.dump(printer, fprefix + " ");
+ getIntentFilter(filter).dump(printer, fprefix + " ");
}
}
}
@@ -527,7 +530,7 @@
* @see android.content.IntentFilter#getAutoVerify()
*/
protected boolean isFilterVerified(F filter) {
- return filter.isVerified();
+ return getIntentFilter(filter).isVerified();
}
/**
@@ -591,7 +594,7 @@
}
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 @@
}
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 @@
}
// 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 @@
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 @@
if (debug) {
dumpFilter(logPrintWriter, " ", filter);
logPrintWriter.flush();
- filter.dump(logPrinter, " ");
+ intentFilter.dump(logPrinter, " ");
}
}
} else {
@@ -875,4 +880,11 @@
* 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 6fb7b26..93859b3 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -103,7 +103,7 @@
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 3b0a1a3..d86b223 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2120,8 +2120,6 @@
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 @@
} 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 @@
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/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 1099413..f16e3ce 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.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 @@
}
/**
- * 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 c125b1b..f2a8615 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.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.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 @@
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 @@
}
@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 @@
}
}
- 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);
+ 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 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);
- }
-
- @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;
- }
+ // 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);
}
}
+ 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 @@
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 @@
mDebuggingManager = new AdbDebuggingManager(context);
}
- mHandler = new AdbHandler(FgThread.get().getLooper());
-
+ initAdbState();
LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl());
}
@@ -219,7 +212,7 @@
// 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 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 @@
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
+ }
- if (enable == mAdbEnabled) {
+ @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
+ }
+
+ @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/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9082807..6bf5aa3 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 @@
}
@Override
+ protected IntentFilter getIntentFilter(@NonNull BroadcastFilter input) {
+ return input;
+ }
+
+ @Override
protected BroadcastFilter[] newArray(int size) {
return new BroadcastFilter[size];
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ed6ace3..119394f 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 @@
@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 @@
// 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 @@
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/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index ffa7d92..0dc44f7 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.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 @@
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";
@@ -379,6 +385,8 @@
private boolean mAppDataIsolationEnabled = false;
+ private boolean mVoldAppDataIsolationEnabled = false;
+
private ArrayList<String> mAppDataIsolationWhitelistedApps;
/**
@@ -691,6 +699,8 @@
// 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());
@@ -2113,6 +2123,13 @@
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 40acfe1..7462f7f 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.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.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 3138639..e484ca0 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 @@
// 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 @@
}
/** 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 @@
// 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 @@
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 @@
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 c2af29c..1139d28 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 @@
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 9f76e1e..eac2d24 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 @@
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 @@
* 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 @@
@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 47622f3..87262a8 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.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.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 @@
}
}
+ 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 @@
@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 @@
}
}
- 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 @@
}
@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 @@
+ " 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 @@
@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 @@
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 @@
}
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 @@
// ---------------------------------------------------------------
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 @@
}
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 @@
}
@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 54af694..4904061 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.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.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 @@
@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 b9a30bb..63054cf 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.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.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 @@
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 4ba2bfb..0000000
--- 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 11e8d91..a290eb3 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 @@
}
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 @@
}
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 @@
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 @@
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 09af655..bc50ebc 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.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 @@
@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 36136f4..5f44e04 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 @@
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 1039cf6..b57c261 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 @@
* {@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 0662400..ee5a4fe 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 @@
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 @@
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 @@
}
/**
- * 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 3b564c3..f45e66e 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 @@
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 @@
@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 8bea119..cadb8e4 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 @@
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 a440c62..d12e03d 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.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.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 a1250cb..1205a33 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.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.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 @@
/** 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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 0dacadc..85810e3 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 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.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 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 @@
* 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 @@
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 @@
return null;
}
return PackageInfoUtils.generateProviderInfo(pkg, p, flags,
- ps.readUserState(userId), userId);
+ ps.readUserState(userId), userId, ps);
}
}
@@ -354,12 +356,12 @@
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 @@
/** 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 @@
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 @@
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 @@
+ " 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 @@
}
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 @@
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 @@
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 @@
@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 @@
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 @@
* <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 @@
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 @@
}
}
- 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 @@
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 @@
* <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 @@
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 @@
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 @@
}
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
}
}
- 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 @@
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 @@
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 @@
}
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 @@
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 @@
}
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 @@
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 @@
}
@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 @@
}
@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 @@
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 @@
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 @@
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 @@
}
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 @@
@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 @@
}
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 @@
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 @@
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 @@
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 @@
}
@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;
+ ParsedProvider provider = pair.first;
+ ParsedIntentInfo filter = pair.second;
- 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;
- }
- }
- }
-
- if (provider == null) {
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(provider.getPackageName());
+ if (pkg == null) {
return null;
}
@@ -1757,7 +1684,7 @@
}
PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
- filter.getPackageName());
+ provider.getPackageName());
if (ps == null) {
return null;
}
@@ -1779,8 +1706,8 @@
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 @@
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 @@
@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 @@
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 @@
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 @@
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 @@
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 @@
}
@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 @@
}
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 @@
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 @@
@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 @@
}
@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 @@
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 @@
/** 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 @@
/** 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 @@
/** 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 @@
/** 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 0e0096d..8e6b89a 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 @@
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 bcfe577..cf85b0f 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.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.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 @@
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 @@
} 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 @@
// 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 0a065eb..2d42107 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 @@
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 c97d85d..9dc545a 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 @@
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 @@
setState(STATE_VERIFICATION_PENDING);
}
- public ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> getFilters() {
+ public ArrayList<ParsedIntentInfo> getFilters() {
return mFilters;
}
@@ -123,7 +123,7 @@
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 f9cfee1..dabcc35 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 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 3a16217..261caba 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.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.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 @@
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 @@
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 ae7a4a7..2df4a92 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 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 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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 d7c161c..e355bb9 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 @@
* 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 @@
*
* 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 @@
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 482fc49..0bd8b28 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.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 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 @@
}
@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 @@
// 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 @@
}
@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 @@
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 @@
// 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 @@
}
// 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 @@
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 @@
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 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 @@
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 @@
} 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 2b42221..e625aef 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 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.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 @@
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 @@
* <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 @@
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 @@
* 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 @@
// 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 @@
// 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 @@
* 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 @@
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 @@
// 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 @@
/**
* 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 @@
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 @@
// 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 @@
}
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 @@
* 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 @@
* 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 0e554f8..41988d6 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.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.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 @@
*/
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 2a3f7ed..92507e5 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.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.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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
@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 @@
}
}
- 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 @@
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 @@
// 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 @@
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 @@
}
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
+ (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 @@
// 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 @@
+ (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 @@
// 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 @@
// 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 @@
}
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 @@
* 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 @@
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 @@
}
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 @@
? 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 @@
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 @@
}
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
}
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
@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 @@
+ loadingPackageName + ", user=" + userId);
return;
}
- mDexManager.notifyDexLoad(ai, classLoaderNames, classPaths, loaderIsa, userId);
+ mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId);
}
@Override
@@ -9541,19 +9550,21 @@
// 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 @@
}
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 @@
// 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 @@
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 @@
}
}
}
- return pdo.performDexOpt(p, instructionSets,
+
+ return pdo.performDexOpt(p, pkgSetting, instructionSets,
getOrCreateCompilerPackageStats(p),
mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options);
}
@@ -9655,11 +9670,11 @@
}
}
- 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 @@
}
}
- 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 void shutdown() {
- mPackageUsage.writeNow(mPackages);
+ mPackageUsage.writeNow(mSettings.mPackages);
mCompilerStats.writeNow();
mDexManager.writePackageDexUsageNow();
PackageWatchdog.getInstance(mContext).writeNow();
@@ -9808,9 +9824,11 @@
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 @@
// 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 @@
// 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 @@
@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 @@
// 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 @@
}
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 @@
@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 @@
}
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 @@
@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 @@
@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 @@
@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 @@
this.scanFlags = scanFlags;
this.isPlatformPackage = isPlatformPackage;
this.user = user;
+ this.cpuAbiOverride = cpuAbiOverride;
}
}
@@ -10451,7 +10486,7 @@
@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 @@
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 @@
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 @@
}
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 @@
}
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 @@
/** 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 @@
*/
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 @@
}
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 (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);
}
- if (changedAbiCodePath == null) {
- changedAbiCodePath = new ArrayList<>();
- }
- changedAbiCodePath.add(ps.codePathString);
}
}
}
@@ -10766,6 +10809,8 @@
/**
* 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 @@
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 @@
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 @@
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 @@
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 @@
}
// 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 @@
}
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
.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 @@
// 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 @@
// 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 @@
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 @@
}
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 @@
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 @@
*/
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 @@
* 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 @@
parsedPackage.setAllComponentsDirectBootAware(true);
}
if (compressedFileExists(parsedPackage.getCodePath())) {
- parsedPackage.setIsStub(true);
+ parsedPackage.setStub(true);
}
} else {
parsedPackage
@@ -11237,14 +11286,14 @@
) == 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 @@
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 @@
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 @@
}
// 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 @@
+ " 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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
}
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
|| (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 @@
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 @@
if (dataOwnerPkg != null) {
if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
- dataOwnerPkg.getFlags())) {
+ dataOwnerPkg.isDebuggable())) {
try {
checkDowngrade(dataOwnerPkg, pkgLite);
} catch (PackageManagerException e) {
@@ -14213,7 +14253,7 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
}
// 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
| 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 @@
}
}
- // 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 @@
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 @@
// 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 @@
+ " 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 @@
}
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 @@
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 @@
// 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 @@
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 @@
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 @@
+ ", 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 @@
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 @@
// 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 @@
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 @@
}
@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 @@
}
}
- 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 @@
}
private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
- if (isExternal(pkg)) {
+ if (pkg.isExternalStorage()) {
if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
return mSettings.getExternalVersion();
} else {
@@ -17649,10 +17639,11 @@
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 @@
Slog.i(TAG, "Enabling system stub after removal; pkg: "
+ stubPkg.getPackageName());
}
- enableCompressedPackage(stubPkg);
+ enableCompressedPackage(stubPkg, stubPs);
}
}
}
@@ -18046,9 +18037,12 @@
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 @@
// 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 @@
} else {
flags = 0;
}
- prepareAppDataContentsLIF(pkg, userId, flags);
+ prepareAppDataContentsLIF(pkg, ps, userId, flags);
return true;
}
@@ -19966,7 +19961,7 @@
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 @@
// 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 @@
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 @@
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 @@
final int appId = UserHandle.getAppId(pkg.getUid());
- Preconditions.checkNotNull(pkg.getSeInfo());
+ String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
- final String seInfo =
- pkg.getSeInfo() + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
+ Preconditions.checkNotNull(pkgSeInfo);
+
+ 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 @@
}
}
- 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 @@
// 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 @@
|| 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 @@
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 @@
"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 @@
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 @@
}
@Override
- public Object getDisabledSystemPackage(@NonNull String packageName) {
+ public PackageSetting getDisabledSystemPackage(@NonNull String packageName) {
synchronized (mLock) {
return mSettings.getDisabledSystemPkgLPr(packageName);
}
@@ -23363,7 +23365,7 @@
}
@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 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 @@
}
@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 @@
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 @@
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 @@
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 a9035b2..91afd84 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.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.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.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 @@
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 @@
// 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 @@
// 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 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 @@
*/
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 @@
}
}
// 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 @@
// 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 @@
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 @@
* 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 @@
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 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 d83e6f4..2bd1a26 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 @@
/**
* 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 @@
@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 @@
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 @@
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 7d95b19..18bc879 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 @@
/**
* 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 ce2c9e7..ef37a20 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.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.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 @@
}
@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 @@
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 @@
}
@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 @@
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 @@
}
}
- 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 @@
}
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 @@
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 @@
}
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 448dad0..21334c0 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 @@
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 @@
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 @@
@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 ef29cb3..08a87d8 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 @@
}
@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 bce24d7..a261e29 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 @@
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 466f19c..67e1994 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 @@
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 60c8b94..42b2eeb 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.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.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.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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
}
}
- 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 @@
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 @@
}
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 @@
packagePermissions, sharedUserPermissions);
}
- mPersistence.write(runtimePermissions, UserHandle.of(userId));
+ mPersistence.writeAsUser(runtimePermissions, UserHandle.of(userId));
}
@NonNull
@@ -5457,12 +5461,13 @@
}
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 bbd319c..6103f558 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 @@
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 @@
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 @@
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 @@
* 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 @@
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 c37ceb3..2de9858 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 @@
}
/**
+ * 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 12f7d5c..54f9f76 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.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 @@
}
@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 614cc3f..fe99229 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.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.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.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 @@
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 @@
+ "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 @@
// 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 cb755f9..df3c83a 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 @@
/**
* 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 @@
"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 @@
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 @@
* {@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 @@
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 4c40448..d6480d3 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.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 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 @@
// 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 0caab6d..51e07faf 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.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.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 @@
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 @@
*/
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 df24c013..117cc5e 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.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 @@
* 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 @@
@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 @@
// 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 @@
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 @@
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 6e6b137..6807388 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 @@
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 @@
}
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 @@
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 @@
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 e68c238..08763e7 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 @@
"=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 @@
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 @@
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 @@
|| !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 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 b7443f3..5506a52 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 @@
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 0000000..e5e1b0b
--- /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 0000000..23bdf5f
--- /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 0000000..f99791a
--- /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
similarity index 71%
rename from core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java
rename to services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java
index 81b4bc5..ebb96bb 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
similarity index 87%
rename from core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
rename to services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
index 5fbe5b9..432394a 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 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 @@
}
@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
similarity index 78%
rename from core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
rename to services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
index 613a06b..7de457e 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 @@
}
@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
similarity index 62%
rename from core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
rename to services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
index 1220fc4..1d018c4 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 @@
// 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 @@
}
/**
- * 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 @@
* @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 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 @@
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 @@
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
similarity index 94%
rename from core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java
rename to services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java
index 8b27d14..123b808 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 @@
*
* @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
similarity index 91%
rename from core/java/android/content/pm/parsing/library/SharedLibraryNames.java
rename to services/core/java/com/android/server/pm/parsing/library/SharedLibraryNames.java
index 7b691c0..f62f014 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
similarity index 100%
rename from core/java/android/content/pm/parsing/AndroidPackage.aidl
rename to 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 0000000..7929579
--- /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 0000000..780b234
--- /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 0000000..2b508ea
--- /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
similarity index 71%
rename from core/java/android/content/pm/parsing/ParsedPackage.java
rename to services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
index 05cf586..2660f2b 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 @@
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 @@
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 @@
ParsedPackage setSplitCodePaths(String[] splitCodePaths);
- ParsedPackage initForUser(int userId);
-
ParsedPackage setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa);
ParsedPackage setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware);
@@ -104,8 +85,6 @@
ParsedPackage setSystemExt(boolean systemExt);
- ParsedPackage setUpdatedSystemApp(boolean updatedSystemApp);
-
ParsedPackage setVendor(boolean vendor);
ParsedPackage removePermission(int index);
@@ -114,19 +93,9 @@
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 @@
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 0000000..0cb425f
--- /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 0000000..89330a9
--- /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 e323c98..f8e5082 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.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.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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 e6eaf21..9c945d5 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 @@
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 @@
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 @@
}
}
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 36697f9..980aaed 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.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.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 @@
}
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 @@
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 @@
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 @@
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 @@
// 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 @@
}
}
+ // 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 @@
}
} 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 @@
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 @@
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 @@
}
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 @@
*/
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 @@
}
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 @@
&& !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 @@
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 @@
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 @@
// 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 @@
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 @@
}
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 58a9f42..048e487 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.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 254b720..355e243 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 @@
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 @@
* 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 0000000..c008d93
--- /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 ec8e1a0..139c844 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.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.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 @@
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 @@
/**
* 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 @@
}
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 @@
}
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 @@
} 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 @@
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 @@
* @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 740472e..90babcd 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.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 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 @@
* @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 @@
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 @@
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 9f4ca3c..97ce6bd 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 @@
(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 @@
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 0000000..870d909
--- /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 cd5e360..aa1558e 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 @@
* 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/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e1615af..336934e 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_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_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 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 @@
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 @@
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 @@
gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.z,
gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.zUncertainty);
- return phaseCenterOffsetCoordinates;
+ return phaseCenterOffset;
}
jobject GnssAntennaInfoCallback::translatePhaseCenterVariationCorrections(
@@ -1185,8 +1190,7 @@
}
jobject phaseCenterVariationCorrections =
- env->NewObject(class_phaseCenterVariationCorrections,
- method_phaseCenterVariationCorrectionsCtor,
+ env->NewObject(class_sphericalCorrections, method_sphericalCorrectionsCtor,
phaseCenterVariationCorrectionsArray,
phaseCenterVariationCorrectionsUncertaintiesArray);
@@ -1212,7 +1216,7 @@
}
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::translateSingleGnssAntennaInfo(
JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo) {
- jobject phaseCenterOffsetCoordinates =
- translatePhaseCenterOffsetCoordinates(env, gnssAntennaInfo);
+ jobject phaseCenterOffset = translatePhaseCenterOffset(env, gnssAntennaInfo);
// Nullable
jobject phaseCenterVariationCorrections =
@@ -1233,13 +1236,29 @@
// 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 @@
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 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 phaseCenterOffsetCoordinatesClass =
- env->FindClass("android/location/GnssAntennaInfo$PhaseCenterOffsetCoordinates");
- class_phaseCenterOffsetCoordinates =
- (jclass)env->NewGlobalRef(phaseCenterOffsetCoordinatesClass);
- method_phaseCenterOffsetCoordinatesCtor =
- env->GetMethodID(class_phaseCenterOffsetCoordinates, "<init>", "(DDDDDD)V");
+ jclass phaseCenterOffsetClass =
+ env->FindClass("android/location/GnssAntennaInfo$PhaseCenterOffset");
+ class_phaseCenterOffset = (jclass)env->NewGlobalRef(phaseCenterOffsetClass);
+ method_phaseCenterOffsetCtor = env->GetMethodID(class_phaseCenterOffset, "<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 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 @@
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 @@
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 @@
.horizontalPositionUncertaintyMeters = horizontalPositionUncertaintyMeters,
.verticalPositionUncertaintyMeters = verticalPositionUncertaintyMeters,
.toaGpsNanosecondsOfWeek = static_cast<uint64_t>(toaGpsNanosOfWeek),
- .satCorrections = list,
};
if (gnssCorrectionsIface_V1_1 != nullptr) {
@@ -3218,17 +3266,25 @@
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 9b85a7b..eff222a 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 @@
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 731cd1e..421bfa4 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_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.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.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 @@
* 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 |
@@ -2290,6 +2291,11 @@
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 +2754,11 @@
}
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);
}
}
@@ -7036,9 +7042,13 @@
saveSettingsLocked(userId);
}
- mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser(
- new Intent(DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
- UserHandle.getUserHandleForUid(frpManagementAgentUid)));
+ final Intent intent = new Intent(
+ DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED).addFlags(
+ Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND);
+
+ mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser(intent,
+ UserHandle.getUserHandleForUid(frpManagementAgentUid),
+ android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_FACTORY_RESET_PROTECTION)
@@ -10036,35 +10046,6 @@
}
}
- 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) {
@@ -14513,12 +14494,15 @@
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;
}
@@ -15666,8 +15650,8 @@
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) {
@@ -15802,4 +15786,34 @@
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/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
index 203e980..7672cd0 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 @@
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 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 @@
}
mScheduledFuture = mScheduledExecutorService.schedule(this::flushScheduledData,
- mWriteDelayMs, TimeUnit.MILLISECONDS);
+ DEFAULT_DISK_WRITE_DELAY, TimeUnit.MILLISECONDS);
}
/**
@@ -183,7 +186,13 @@
*/
@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 @@
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 @@
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 3afb209..62e9da8 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.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 @@
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 @@
*/
@MainThread
void loadConversationsFromDisk() {
- mScheduledExecutorService.submit(() -> {
+ mScheduledExecutorService.execute(() -> {
synchronized (this) {
ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
getConversationInfosProtoDiskReadWriter();
@@ -194,6 +191,15 @@
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 @@
}
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 @@
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 @@
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 6b97c98..7eb2176 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 @@
}
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 81411c0..a929f6f 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.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 @@
/** 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 @@
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 @@
/** 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 @@
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 6bef1db..85661c6 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,11 +171,35 @@
@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) {
+ synchronized void addEvent(Event event) {
+ pruneOldEvents();
+ addEventInMemory(event);
+ mEventsProtoDiskReadWriter.scheduleEventsSave(mRecentEvents);
+ mEventIndexesProtoDiskReadWriter.scheduleIndexesSave(mEventIndexArray);
+ }
+
+ synchronized void onDestroy() {
+ mEventIndexArray.clear();
+ mRecentEvents.clear();
+ mEventsProtoDiskReadWriter.deleteRecentEventsFile();
+ mEventIndexesProtoDiskReadWriter.deleteIndexesFile();
+ }
+
+ /** Deletes the events data that exceeds the retention period. */
+ 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();
@@ -78,22 +209,180 @@
mRecentEvents.add(event);
}
- void onDestroy() {
- mEventIndexArray.clear();
- mRecentEvents.clear();
- // TODO: STOPSHIP: Delete the data files.
- }
-
- /** Deletes the events data that exceeds the retention period. */
- void pruneOldEvents(long currentTimeMillis) {
- // TODO: STOPSHIP: Delete the old events data files.
- }
-
@VisibleForTesting
static class Injector {
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 b74a3fa..47b6207 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.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.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 @@
* </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 @@
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 @@
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 @@
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 d770f91..3788d6c 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 @@
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 @@
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 @@
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 c8d44ac..00d4241 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 @@
@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 @@
* 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 @@
* 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 @@
* @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 @@
}
/** 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 @@
*
* @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 @@
}
}
}
+
+ 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 c55f972..d47e2cc 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.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 @@
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 @@
}
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 7ca4b6c..d3cecce 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 @@
// 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 6190802..fa0febd 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.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 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 @@
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 @@
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 2d5fa23..959dc05 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.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 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 3778e17..e5450a9 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 d7a3cfd..1bf9c2a 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 @@
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 @@
@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 @@
@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 @@
@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 @@
}
@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 @@
@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 bf2b9be..d148c21 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -93,6 +93,7 @@
},
data: [":JobTestApp"],
+ resource_zips: [":FrameworksServicesTests_apks_as_resources"],
}
java_library {
@@ -115,3 +116,28 @@
"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 0000000..3e11604
--- /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 0000000..1b62aa2
--- /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
similarity index 93%
rename from core/tests/coretests/apks/install-split-base/AndroidManifest.xml
rename to services/tests/servicestests/apks/install-split-base/AndroidManifest.xml
index c2bfedd..2979395 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
similarity index 100%
rename from core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java
rename to 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
similarity index 60%
rename from core/tests/coretests/apks/install-split-feature-a/Android.bp
rename to services/tests/servicestests/apks/install-split-feature-a/Android.bp
index 9ec9893..45d8917 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
similarity index 93%
rename from core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml
rename to services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml
index 3221c75..a3dd55f 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
similarity index 100%
rename from core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java
rename to 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 0000000..59c8524
--- /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
similarity index 87%
rename from core/tests/coretests/apks/install_intent_filters/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_intent_filters/AndroidManifest.xml
index d7ee76e..fc7134d2 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
similarity index 100%
rename from core/tests/coretests/apks/install_intent_filters/src/com/android/frameworks/coretests/TestActivity.java
rename to 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 0000000..c24aa2b
--- /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
similarity index 92%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-0.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
index 634228b..215384b 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
similarity index 93%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-q0.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0.xml
index 8994966..c0e5867 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
similarity index 93%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
index 0d0d8b9..5d22577 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
similarity index 92%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r0.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
index a987afa..c1244f2 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
similarity index 93%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r5.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
index 9860096..3410938 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
similarity index 100%
rename from core/tests/coretests/apks/install_uses_sdk/res/values/strings.xml
rename to 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
similarity index 100%
rename from core/tests/coretests/res/raw/com_android_tzdata.apex
rename to services/tests/servicestests/res/raw/com_android_tzdata.apex
Binary files differ
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 9574a08..40b0e71 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.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.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 @@
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 @@
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 3a8258b..853151f 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 @@
}
@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 37ce510..dbf2f14 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_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;
@@ -2097,7 +2098,8 @@
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
}
public void testSetFactoryResetProtectionPolicyFailWithPO() throws Exception {
@@ -2144,7 +2146,8 @@
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
}
public void testGetFactoryResetProtectionPolicyWithFrpManagementAgent()
@@ -2171,7 +2174,8 @@
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
}
private void assertPoliciesAreEqual(FactoryResetProtectionPolicy expectedPolicy,
@@ -6045,6 +6049,86 @@
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 3dc26af..ab21ab0 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 @@
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 19cbb0e..a99c982 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.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 @@
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 @@
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 @@
}
@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 ef12948..063cd5da 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 @@
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 b614a4f..443718d 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 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 @@
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 5e104a5..f73a4b5 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.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 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 43e1001..825ca10 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 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 @@
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 @@
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 8b8ba12..aecbc8d 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 @@
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 @@
@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 @@
@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 @@
}
@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 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 @@
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 d444466..418067f 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 @@
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 @@
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 @@
scheduledExecutorService, rootDir, helper);
mConversationStore = new TestConversationStore(rootDir, scheduledExecutorService,
helper);
+ mEventStore = new TestEventStore(rootDir, scheduledExecutorService);
}
@Override
@@ -261,8 +265,31 @@
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 @@
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 9670658..5d5c714 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.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 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 @@
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 @@
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 @@
filter.schemesIterator().forEachRemaining(info::addDataScheme);
}
activity.addIntent(info);
- activity.exported = true;
+ activity.setExported(true);
}
return pkg(packageName)
@@ -135,7 +136,7 @@
}
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 @@
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 @@
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 @@
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 df2b3ef..6c769485 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 @@
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 56ac7c5..d2ec500 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.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.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.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 @@
@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 @@
@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 @@
@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 @@
@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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
)
.setUse32BitAbi(true)
.setVolumeUuid("foo3")
- .setCodePath("foo4")
.addPermission(permission)
.addPermissionGroup(new ParsedPermissionGroup())
.addActivity(new ParsedActivity())
@@ -532,7 +552,7 @@
.addOriginalPackage("foo14")
.setRealPackage("foo15")
.addAdoptPermission("foo16")
- .setAppMetaData(bundle)
+ .setMetaData(bundle)
.setVersionName("foo17")
.setSharedUserId("foo18")
.setSigningDetails(
@@ -547,8 +567,7 @@
.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 @@
.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 841cea2..d12ea894 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 @@
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 da5986f7..9d3ac17 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 @@
/**
* Tests for {@link ParallelPackageParser}
*/
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class ParallelPackageParserTest {
private static final String TAG = ParallelPackageParserTest.class.getSimpleName();
@@ -44,7 +48,7 @@
@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 @@
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 30108c6..efc1c05 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.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 @@
}
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 11f154b..12fb400 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 @@
private int mScanFlags;
private UserHandle mUser;
private boolean mIsPlatformPackage;
+ @Nullable
+ private String mCpuAbiOverride;
ScanRequestBuilder(ParsedPackage pkg) {
this.mPkg = pkg;
@@ -97,10 +102,16 @@
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 583cf58..09f946d 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.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.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 @@
@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 @@
@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 @@
@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 @@
.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 @@
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 @@
createBasicPackageSettingBuilder("original.package").build();
final ParsedPackage basicPackage =
- createBasicPackage(DUMMY_PACKAGE_NAME)
+ (ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME)
.hideAsParsed();
@@ -411,8 +412,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 2936bdd..56460fb 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 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 3db832b..ce21099 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.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 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 @@
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 f5e5e2a..d69e1b8 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 @@
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 @@
// 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
similarity index 86%
rename from core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
rename to services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index 1e0bfb0..f87f68d 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.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 @@
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 @@
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 @@
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 @@
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 @@
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 66a4946..3846be0 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.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 @@
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 @@
.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 27d02e1..0a32e4a 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.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 @@
* 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 925af7f..191c038 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 @@
* 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 afd6e18..ca6b296 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.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 @@
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 @@
.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 @@
}
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 @@
}
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
similarity index 91%
rename from core/tests/coretests/src/android/content/pm/PackageParserTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index 46e992e..66cd466 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 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.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 @@
}
}
+ 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 @@
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 @@
/**
* 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 @@
@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 @@
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 @@
// 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 @@
@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 @@
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
similarity index 67%
rename from core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
index 21479c0..6b60042 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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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
similarity index 68%
rename from core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
index 65ae219..f536052 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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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
similarity index 68%
rename from core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
index 38755b9..77197e3 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 @@
/**
* 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 @@
@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
similarity index 97%
rename from core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/OptionalClassRunner.java
index 05db8ee..0ebfe1a 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
similarity index 68%
rename from core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
index 4c7899b..95b8d3f 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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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
similarity index 71%
rename from core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index 00d468d..ca38860 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 @@
*/
@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 @@
}
after.addUsesLibrary(ORG_APACHE_HTTP_LEGACY);
- checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal());
+ checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal());
}
/**
@@ -105,16 +108,16 @@
+ 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 @@
*/
@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 @@
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
similarity index 88%
rename from core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
index e7a80e1a..a71572f 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 @@
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
similarity index 69%
rename from core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index fd3ba2b..1122490 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 @@
/**
* Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary}
*/
+@Presubmit
@SmallTest
@RunWith(JUnit4.class)
public class RemoveUnnecessaryAndroidTestBaseLibraryTest
@@ -42,13 +45,13 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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
similarity index 68%
rename from core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index d3494d9..3cc8475 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 @@
/**
* Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary}
*/
+@Presubmit
@SmallTest
@RunWith(JUnit4.class)
public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest
@@ -42,13 +45,13 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 9e57763..0fdffd5 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.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 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 @@
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 @@
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 @@
@Override
int[] getRunningUserIds() {
- return new int[] {USER_ID};
+ return mRunningUsers;
}
@Override
@@ -248,6 +254,11 @@
return false;
}
+ @Override
+ public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
+ return mCrossProfileTargets;
+ }
+
// Internal methods
void setDisplayOn(boolean on) {
@@ -379,10 +390,15 @@
}
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 @@
}
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 @@
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 bc2766c..cee486f 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 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 @@
}
@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 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/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index df5b311..0d1b352 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 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.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 @@
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 @@
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 @@
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 db26d88..b7779fd 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.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 @@
});
}
- 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);
}
- mDatabase.dump(pw, compact);
+ if (CollectionUtils.isEmpty(pkgs)) {
+ mDatabase.dump(pw, compact);
+ }
}
void dumpDatabaseInfo(IndentingPrintWriter ipw) {
@@ -894,7 +898,8 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
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 6407ec7..84f411f 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.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 @@
}
@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 @@
}
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
old mode 100644
new mode 100755
index 52213d8..c5fcf67
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -465,8 +465,27 @@
* @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 @@
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 @@
}
/**
+ * 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
old mode 100644
new mode 100755
index 3b0ba25..3564add
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -387,8 +387,25 @@
* @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 @@
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 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:
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
old mode 100644
new mode 100755
index 2aea723..0dca006
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -128,6 +128,8 @@
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 @@
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 @@
}
@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 @@
}
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 @@
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
old mode 100644
new mode 100755
index 9d291740..dd6c153
--- 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 @@
}
/**
+ * 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 a397d77..fb54179 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -81,6 +81,11 @@
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
old mode 100644
new mode 100755
index 9beff22..edf1cf4
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -36,6 +36,10 @@
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 a27c480..9ae86c8 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -432,7 +432,7 @@
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 795de57..a7e52ea 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.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 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 @@
/**
* 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 @@
"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 @@
"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 @@
"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 @@
"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 @@
"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 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 @@
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 @@
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 @@
});
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 @@
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 @@
/* 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 @@
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 e1c4bef..8b7a243 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -30,10 +30,8 @@
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 @@
/**
* 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
*/
- public static final int VSNCP_APN_UNATHORIZED = 0x8BE;
+ @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_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 @@
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 @@
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 0000000..c0833af
--- /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 a537928..6571858 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 @@
* 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);
+ ModemInfo modemInfo1 = new ModemInfo(0, 0, true, true);
+ ModemInfo modemInfo2 = new ModemInfo(1, 0, true, true);
- 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);
+ List<ModemInfo> logicalModemList = new ArrayList<>();
+ logicalModemList.add(modemInfo1);
+ logicalModemList.add(modemInfo2);
+ DEFAULT_DSDS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false);
+
+ logicalModemList = new ArrayList<>();
+ logicalModemList.add(modemInfo1);
+ DEFAULT_SSSS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false);
}
- 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;
+ /** @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;
- /**
- * 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);
- }
-
- 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);
- }
- }
-
- /**
- * 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);
- }
-
- 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 @@
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 @@
/**
* {@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 708adeb..e37a9b9 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -257,8 +257,7 @@
* 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 b4fef46..0000000
--- 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 6c920f1..8479db6 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2094,8 +2094,12 @@
/**
* 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 832771d..336aa0e 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -217,6 +217,20 @@
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 @@
}
/**
- * @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 68b6683..0660776 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -47,7 +47,6 @@
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 @@
//
/**
- * 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 @@
* @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 @@
* @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 @@
* 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 @@
* @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 @@
* 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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* 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 @@
}
/**
- * 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
old mode 100644
new mode 100755
index 1b583fd..80c38cb
--- 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
}
+ @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 cc2ebb9..36d2067 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -148,6 +148,12 @@
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
old mode 100644
new mode 100755
index 75bd6a7..06aa642
--- 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 @@
}
/**
+ * 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 @@
}
@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 e8f69ea..73ba0e3 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 @@
}
@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 @@
}
/**
+ * 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 15234e5..0466efc 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
@@ -18,7 +18,6 @@
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 @@
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 b33a9f1..1c62cc4 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
@@ -184,6 +184,12 @@
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 1449a62..f61d4e1 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -114,6 +114,7 @@
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 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 168c8b6..861925f 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.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 @@
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 @@
/**
* 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/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java
index d6a2176..2273bc6 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.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 @@
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/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 0e3b797..1994d1f 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.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 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.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 @@
}
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 @@
@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 @@
// 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/wifi/Android.bp b/wifi/Android.bp
index 9f26203..5c9fb4e 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -86,7 +86,6 @@
// 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 af2f246..bab9a9e 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.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 @@
}
/** @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 @@
/** @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/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 7d9bdba..4507cc2 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -900,12 +900,15 @@
}
/**
- * 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 8f6beb1..638efb9 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 @@
*
* @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 @@
*
* @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();
}
}