Merge "Allow com.android.* classes in system_service stubs"
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/StubLibraries.bp b/StubLibraries.bp
index 4616ced..7f23df7 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -49,7 +49,6 @@
":opt-net-voip-srcs",
":core-current-stubs-source",
":core_public_api_files",
- ":ike-api-srcs",
],
// TODO(b/147699819): remove below aidl includes.
aidl: {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index d4ceabd..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,
@@ -334,7 +365,8 @@
throw new SecurityException("Caller not allowed to access " + blobHandle
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
}
- if (leaseExpiryTimeMillis != 0 && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) {
+ if (leaseExpiryTimeMillis != 0 && blobHandle.expiryTimeMillis != 0
+ && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) {
throw new IllegalArgumentException(
"Lease expiry cannot be later than blobs expiry time");
}
@@ -384,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,
@@ -424,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) {
@@ -485,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();
@@ -574,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();
@@ -698,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);
}
}
@@ -718,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);
}
}
@@ -741,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());
}
}
@@ -751,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) {
@@ -771,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);
}
@@ -806,7 +849,7 @@
if (shouldRemove) {
blobMetadata.getBlobFile().delete();
- mKnownBlobIds.remove(blobMetadata.getBlobId());
+ mActiveBlobIds.remove(blobMetadata.getBlobId());
deletedBlobIds.add(blobMetadata.getBlobId());
}
return shouldRemove;
@@ -836,7 +879,7 @@
if (shouldRemove) {
blobStoreSession.getSessionFile().delete();
- mKnownBlobIds.remove(blobStoreSession.getSessionId());
+ mActiveBlobIds.remove(blobStoreSession.getSessionId());
indicesToRemove.add(j);
deletedBlobIds.add(blobStoreSession.getSessionId());
}
@@ -883,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..2f3e2ac 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -21,14 +21,16 @@
apex_defaults {
native_shared_libs: [
"libstats_jni",
+ "libstatspull",
+ "libstatssocket",
],
- // binaries: ["vold"],
+ binaries: ["statsd"],
java_libs: [
"framework-statsd",
"service-statsd",
],
compile_multilib: "both",
- // prebuilts: ["my_prebuilt"],
+ prebuilts: ["com.android.os.statsd.init.rc"],
name: "com.android.os.statsd-defaults",
key: "com.android.os.statsd.key",
certificate: ":com.android.os.statsd.certificate",
@@ -47,6 +49,12 @@
certificate: "com.android.os.statsd",
}
+prebuilt_etc {
+ name: "com.android.os.statsd.init.rc",
+ src: "statsd.rc",
+ filename: "init.rc",
+ installable: false,
+}
// JNI library for StatsLog.write
cc_library_shared {
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index 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/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index ab669d4..5533ed8 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -48,17 +48,8 @@
java_defaults {
name: "framework-statsd-defaults",
-
- // TODO(b/146757305): Use "module_current" once it's ready.
- sdk_version: "core_current",
-
- libs: [
- "framework-annotations-lib",
-
- // TODO(b/146757305): should be unnecessary once
- // sdk_version="module_lib_current" or "module_current"
- "android_module_lib_stubs_current",
- ],
+ sdk_version: "module_current",
+ libs: [ "framework-annotations-lib" ],
}
java_library {
@@ -72,16 +63,6 @@
":framework-statsd-sources",
],
- aidl: {
- // TODO(b/146757305): should be unnecessary once
- // sdk_version="module_lib_current" or "module_current"
- include_dirs: [
- // To refer:
- // android.app.PendintIntent
- "frameworks/base/core/java",
- ],
- },
-
permitted_packages: [
"android.app",
"android.os",
diff --git a/cmds/statsd/statsd.rc b/apex/statsd/statsd.rc
similarity index 67%
rename from cmds/statsd/statsd.rc
rename to apex/statsd/statsd.rc
index a98ecd5..605da2a 100644
--- a/cmds/statsd/statsd.rc
+++ b/apex/statsd/statsd.rc
@@ -12,19 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-service statsd /system/bin/statsd
+service statsd /apex/com.android.os.statsd/bin/statsd
class main
socket statsdw dgram+passcred 0222 statsd statsd
user statsd
group statsd log
writepid /dev/cpuset/system-background/tasks
-
-on property:ro.statsd.enable=false
- stop statsd
-
-on post-fs-data
- # Create directory for statsd
- mkdir /data/misc/stats-data/ 0770 statsd system
- mkdir /data/misc/stats-service/ 0770 statsd system
- mkdir /data/misc/stats-active-metric/ 0770 statsd system
- mkdir /data/misc/train-info/ 0770 statsd system
diff --git a/api/current.txt b/api/current.txt
index ac42e66..71b27bc 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);
@@ -36633,6 +36624,7 @@
method public void addThermalStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.PowerManager.OnThermalStatusChangedListener);
method public int getCurrentThermalStatus();
method public int getLocationPowerSaveMode();
+ method public float getThermalHeadroom(@IntRange(from=0, to=60) int);
method public boolean isDeviceIdleMode();
method public boolean isIgnoringBatteryOptimizations(String);
method public boolean isInteractive();
@@ -40585,13 +40577,13 @@
field public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
field public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
field @Deprecated public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
- field public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
- field public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
+ field @Deprecated public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
+ field @Deprecated public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
field public static final String WIFI_ON = "wifi_on";
- field public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
- field public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0
- field public static final int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2
- field public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1
+ field @Deprecated public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
+ field @Deprecated public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0
+ field @Deprecated public static final int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2
+ field @Deprecated public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1
field public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
field public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale";
}
@@ -43402,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";
}
@@ -45653,7 +45646,7 @@
method public final android.telecom.CallAudioState getCallAudioState();
method public final String getCallerDisplayName();
method public final int getCallerDisplayNamePresentation();
- method public int getCallerNumberVerificationStatus();
+ method public final int getCallerNumberVerificationStatus();
method public final android.telecom.Conference getConference();
method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
method public final int getConnectionCapabilities();
@@ -45706,7 +45699,7 @@
method public final void setAudioModeIsVoip(boolean);
method public final void setAudioRoute(int);
method public final void setCallerDisplayName(String, int);
- method public void setCallerNumberVerificationStatus(int);
+ method public final void setCallerNumberVerificationStatus(int);
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
method public final void setConnectionCapabilities(int);
@@ -46558,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";
@@ -46812,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();
@@ -47126,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();
@@ -47288,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 {
@@ -47503,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);
@@ -47871,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();
@@ -53239,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
@@ -53283,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);
@@ -53891,6 +54140,7 @@
method public boolean requestRectangleOnScreen(android.graphics.Rect);
method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
method public final void requestUnbufferedDispatch(android.view.MotionEvent);
+ method public final void requestUnbufferedDispatch(int);
method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
method public void resetPivot();
method public static int resolveSize(int, int);
@@ -55604,6 +55854,7 @@
method public CharSequence getContentDescription();
method public int getDrawingOrder();
method public CharSequence getError();
+ method @Nullable public android.view.accessibility.AccessibilityNodeInfo.ExtraRenderingInfo getExtraRenderingInfo();
method public android.os.Bundle getExtras();
method public CharSequence getHintText();
method public int getInputType();
@@ -55756,6 +56007,7 @@
field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
field @NonNull public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
+ field public static final String EXTRA_DATA_RENDERING_INFO_KEY = "android.view.accessibility.extra.DATA_RENDERING_INFO_KEY";
field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
@@ -55843,6 +56095,12 @@
method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean);
}
+ public static final class AccessibilityNodeInfo.ExtraRenderingInfo {
+ method @Nullable public android.util.Size getLayoutParams();
+ method public float getTextSizeInPx();
+ method public int getTextSizeUnit();
+ }
+
public static final class AccessibilityNodeInfo.RangeInfo {
ctor public AccessibilityNodeInfo.RangeInfo(int, float, float, float);
method public float getCurrent();
@@ -56469,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;
}
@@ -56477,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);
}
}
@@ -60825,6 +61083,7 @@
method @Nullable public android.graphics.drawable.Drawable getTextSelectHandleLeft();
method @Nullable public android.graphics.drawable.Drawable getTextSelectHandleRight();
method @android.view.ViewDebug.ExportedProperty(category="text") public float getTextSize();
+ method public int getTextSizeUnit();
method public int getTotalPaddingBottom();
method public int getTotalPaddingEnd();
method public int getTotalPaddingLeft();
diff --git a/api/system-current.txt b/api/system-current.txt
index f974380..9663c0c 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);
@@ -6737,337 +6747,6 @@
}
-package android.net.eap {
-
- public final class EapSessionConfig {
- }
-
- public static final class EapSessionConfig.Builder {
- ctor public EapSessionConfig.Builder();
- method @NonNull public android.net.eap.EapSessionConfig build();
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaConfig(int, int);
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaPrimeConfig(int, int, @NonNull String, boolean);
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapIdentity(@NonNull byte[]);
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapMsChapV2Config(@NonNull String, @NonNull String);
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapSimConfig(int, int);
- }
-
- public static class EapSessionConfig.EapAkaConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
- }
-
- public static class EapSessionConfig.EapAkaPrimeConfig extends android.net.eap.EapSessionConfig.EapAkaConfig {
- method public boolean allowsMismatchedNetworkNames();
- method @NonNull public String getNetworkName();
- }
-
- public abstract static class EapSessionConfig.EapMethodConfig {
- method public int getMethodType();
- }
-
- public static class EapSessionConfig.EapMsChapV2Config extends android.net.eap.EapSessionConfig.EapMethodConfig {
- method @NonNull public String getPassword();
- method @NonNull public String getUsername();
- }
-
- public static class EapSessionConfig.EapSimConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
- }
-
- public abstract static class EapSessionConfig.EapUiccConfig extends android.net.eap.EapSessionConfig.EapMethodConfig {
- method public int getAppType();
- method public int getSubId();
- }
-
-}
-
-package android.net.ipsec.ike {
-
- public final class ChildSaProposal extends android.net.ipsec.ike.SaProposal {
- }
-
- public static final class ChildSaProposal.Builder {
- ctor public ChildSaProposal.Builder();
- method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addDhGroup(int);
- method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addEncryptionAlgorithm(int, int);
- method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addIntegrityAlgorithm(int);
- method @NonNull public android.net.ipsec.ike.ChildSaProposal build();
- }
-
- public interface ChildSessionCallback {
- method public void onClosed();
- method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
- method public void onIpSecTransformCreated(@NonNull android.net.IpSecTransform, int);
- method public void onIpSecTransformDeleted(@NonNull android.net.IpSecTransform, int);
- method public void onOpened(@NonNull android.net.ipsec.ike.ChildSessionConfiguration);
- }
-
- public final class ChildSessionConfiguration {
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getInboundTrafficSelectors();
- method @NonNull public java.util.List<android.net.LinkAddress> getInternalAddresses();
- method @NonNull public java.util.List<java.net.InetAddress> getInternalDhcpServers();
- method @NonNull public java.util.List<java.net.InetAddress> getInternalDnsServers();
- method @NonNull public java.util.List<android.net.IpPrefix> getInternalSubnets();
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors();
- }
-
- public abstract class ChildSessionParams {
- method public long getHardLifetime();
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors();
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors();
- method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals();
- method public long getSoftLifetime();
- }
-
- public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeFqdnIdentification(@NonNull String);
- field @NonNull public final String fqdn;
- }
-
- public abstract class IkeIdentification {
- }
-
- public final class IkeIpv4AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeIpv4AddrIdentification(@NonNull java.net.Inet4Address);
- field @NonNull public final java.net.Inet4Address ipv4Address;
- }
-
- public class IkeIpv6AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeIpv6AddrIdentification(@NonNull java.net.Inet6Address);
- field @NonNull public final java.net.Inet6Address ipv6Address;
- }
-
- public final class IkeKeyIdIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeKeyIdIdentification(@NonNull byte[]);
- field @NonNull public final byte[] keyId;
- }
-
- public final class IkeRfc822AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeRfc822AddrIdentification(@NonNull String);
- field @NonNull public final String rfc822Name;
- }
-
- public final class IkeSaProposal extends android.net.ipsec.ike.SaProposal {
- method @NonNull public java.util.List<java.lang.Integer> getPseudorandomFunctions();
- }
-
- public static final class IkeSaProposal.Builder {
- ctor public IkeSaProposal.Builder();
- method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addDhGroup(int);
- method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addEncryptionAlgorithm(int, int);
- method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addIntegrityAlgorithm(int);
- method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addPseudorandomFunction(int);
- method @NonNull public android.net.ipsec.ike.IkeSaProposal build();
- }
-
- public final class IkeSession implements java.lang.AutoCloseable {
- ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionParams, @NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback);
- method public void close();
- method public void closeChildSession(@NonNull android.net.ipsec.ike.ChildSessionCallback);
- method public void kill();
- method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull android.net.ipsec.ike.ChildSessionCallback);
- }
-
- public interface IkeSessionCallback {
- method public void onClosed();
- method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
- method public void onError(@NonNull android.net.ipsec.ike.exceptions.IkeProtocolException);
- method public void onOpened(@NonNull android.net.ipsec.ike.IkeSessionConfiguration);
- }
-
- public final class IkeSessionConfiguration {
- method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
- method @NonNull public String getRemoteApplicationVersion();
- method @NonNull public java.util.List<byte[]> getRemoteVendorIDs();
- method public boolean isIkeExtensionEnabled(int);
- field public static final int EXTENSION_TYPE_FRAGMENTATION = 1; // 0x1
- field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2
- }
-
- public final class IkeSessionParams {
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest> getConfigurationRequests();
- method public long getHardLifetime();
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig();
- method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification();
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig();
- method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification();
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals();
- method @NonNull public java.net.InetAddress getServerAddress();
- method public long getSoftLifetime();
- method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket();
- }
-
- public static final class IkeSessionParams.Builder {
- ctor public IkeSessionParams.Builder();
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(@NonNull java.net.InetAddress);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(int);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams build();
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@Nullable java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLifetime(long, long);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setServerAddress(@NonNull java.net.InetAddress);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
- }
-
- public static interface IkeSessionParams.ConfigRequestIpv4PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
- method @Nullable public java.net.Inet4Address getAddress();
- }
-
- public static interface IkeSessionParams.ConfigRequestIpv6PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
- method @Nullable public java.net.Inet6Address getAddress();
- }
-
- public abstract static class IkeSessionParams.IkeAuthConfig {
- }
-
- public static class IkeSessionParams.IkeAuthDigitalSignLocalConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
- method @NonNull public java.security.cert.X509Certificate getClientEndCertificate();
- method @NonNull public java.util.List<java.security.cert.X509Certificate> getIntermediateCertificates();
- method @NonNull public java.security.PrivateKey getPrivateKey();
- }
-
- public static class IkeSessionParams.IkeAuthDigitalSignRemoteConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
- method @Nullable public java.security.cert.X509Certificate getRemoteCaCert();
- }
-
- public static class IkeSessionParams.IkeAuthEapConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
- method @NonNull public android.net.eap.EapSessionConfig getEapConfig();
- }
-
- public static class IkeSessionParams.IkeAuthPskConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
- method @NonNull public byte[] getPsk();
- }
-
- public static interface IkeSessionParams.IkeConfigRequest {
- }
-
- public final class IkeTrafficSelector {
- ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress);
- field public final int endPort;
- field @NonNull public final java.net.InetAddress endingAddress;
- field public final int startPort;
- field @NonNull public final java.net.InetAddress startingAddress;
- }
-
- public abstract class SaProposal {
- method @NonNull public java.util.List<java.lang.Integer> getDhGroups();
- method @NonNull public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getEncryptionAlgorithms();
- method @NonNull public java.util.List<java.lang.Integer> getIntegrityAlgorithms();
- field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
- field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
- field public static final int DH_GROUP_NONE = 0; // 0x0
- field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3
- field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
- field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13
- field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14
- field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12
- field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
- field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
- field public static final int KEY_LEN_AES_128 = 128; // 0x80
- field public static final int KEY_LEN_AES_192 = 192; // 0xc0
- field public static final int KEY_LEN_AES_256 = 256; // 0x100
- field public static final int KEY_LEN_UNUSED = 0; // 0x0
- field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
- field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
- }
-
- public final class TransportModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
- }
-
- public static final class TransportModeChildSessionParams.Builder {
- ctor public TransportModeChildSessionParams.Builder();
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams build();
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder setLifetime(long, long);
- }
-
- public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
- method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest> getConfigurationRequests();
- }
-
- public static final class TunnelModeChildSessionParams.Builder {
- ctor public TunnelModeChildSessionParams.Builder();
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet4Address);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet6Address, int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build();
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder setLifetime(long, long);
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet4Address getAddress();
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet4Address getAddress();
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet4Address getAddress();
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet6Address getAddress();
- method public int getPrefixLength();
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet6Address getAddress();
- }
-
- public static interface TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- }
-
-}
-
-package android.net.ipsec.ike.exceptions {
-
- public abstract class IkeException extends java.lang.Exception {
- }
-
- public final class IkeInternalException extends android.net.ipsec.ike.exceptions.IkeException {
- }
-
- public abstract class IkeProtocolException extends android.net.ipsec.ike.exceptions.IkeException {
- method @Nullable public byte[] getErrorData();
- method public int getErrorType();
- field public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24; // 0x18
- field public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44; // 0x2c
- field public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37; // 0x25
- field public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36; // 0x24
- field public static final int ERROR_TYPE_INVALID_IKE_SPI = 4; // 0x4
- field public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17; // 0x11
- field public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5; // 0x5
- field public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9; // 0x9
- field public static final int ERROR_TYPE_INVALID_SELECTORS = 39; // 0x27
- field public static final int ERROR_TYPE_INVALID_SYNTAX = 7; // 0x7
- field public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35; // 0x23
- field public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14; // 0xe
- field public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34; // 0x22
- field public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43; // 0x2b
- field public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38; // 0x26
- field public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1; // 0x1
- }
-
-}
-
package android.net.metrics {
public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -7536,6 +7215,7 @@
method public int getChannel();
method public int getMaxNumberOfClients();
method public int getShutdownTimeoutMillis();
+ method public boolean isAutoShutdownEnabled();
method public boolean isClientControlByUserEnabled();
method @Nullable public android.net.wifi.WifiConfiguration toWifiConfiguration();
field public static final int BAND_2GHZ = 1; // 0x1
@@ -7549,14 +7229,15 @@
ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration);
method @NonNull public android.net.wifi.SoftApConfiguration build();
method @NonNull public android.net.wifi.SoftApConfiguration.Builder enableClientControlByUser(boolean);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAutoShutdownEnabled(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientList(@NonNull java.util.List<android.net.MacAddress>, @NonNull java.util.List<android.net.MacAddress>);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(@IntRange(from=0) int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(@IntRange(from=0) int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
}
@@ -7750,6 +7431,7 @@
method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMeteredOverridePasspoint(@NonNull String, int);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanAlwaysAvailable(boolean);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanThrottleEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setVerboseLoggingEnabled(boolean);
@@ -7897,6 +7579,7 @@
public final class WifiOemMigrationHook {
method @Nullable public static android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData loadFromConfigStore();
+ method @NonNull public static android.net.wifi.WifiOemMigrationHook.SettingsMigrationData loadFromSettings(@NonNull android.content.Context);
}
public static final class WifiOemMigrationHook.ConfigStoreMigrationData implements android.os.Parcelable {
@@ -7914,6 +7597,31 @@
method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData.Builder setUserSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
}
+ public static final class WifiOemMigrationHook.SettingsMigrationData implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getP2pDeviceName();
+ method public boolean isP2pFactoryResetPending();
+ method public boolean isScanAlwaysAvailable();
+ method public boolean isScanThrottleEnabled();
+ method public boolean isSoftApTimeoutEnabled();
+ method public boolean isVerboseLoggingEnabled();
+ method public boolean isWakeUpEnabled();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiOemMigrationHook.SettingsMigrationData> CREATOR;
+ }
+
+ public static final class WifiOemMigrationHook.SettingsMigrationData.Builder {
+ ctor public WifiOemMigrationHook.SettingsMigrationData.Builder();
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData build();
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setP2pDeviceName(@Nullable String);
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setP2pFactoryResetPending(boolean);
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setScanAlwaysAvailable(boolean);
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setScanThrottleEnabled(boolean);
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setSoftApTimeoutEnabled(boolean);
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setVerboseLoggingEnabled(boolean);
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setWakeUpEnabled(boolean);
+ }
+
public class WifiScanner {
method @Deprecated public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
method @Deprecated public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
@@ -9720,18 +9428,11 @@
field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
field public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
- field public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled";
field public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled";
field public static final String TETHER_SUPPORTED = "tether_supported";
field public static final String THEATER_MODE_ON = "theater_mode_on";
field public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
field public static final String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds";
- field public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
- field public static final String WIFI_P2P_PENDING_FACTORY_RESET = "wifi_p2p_pending_factory_reset";
- field public static final String WIFI_SCAN_ALWAYS_AVAILABLE = "wifi_scan_always_enabled";
- field public static final String WIFI_SCAN_THROTTLE_ENABLED = "wifi_scan_throttle_enabled";
- field public static final String WIFI_SCORE_PARAMS = "wifi_score_params";
- field public static final String WIFI_VERBOSE_LOGGING_ENABLED = "wifi_verbose_logging_enabled";
field @Deprecated public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
}
@@ -9746,6 +9447,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";
@@ -10189,6 +9891,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";
}
@@ -11366,347 +11069,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..73a8f66 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -217,7 +217,10 @@
shared_libs: ["libgtest_prod"],
- init_rc: ["statsd.rc"],
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ ],
}
// ==============
@@ -299,6 +302,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 +316,6 @@
shared_libs: [
"libprotobuf-cpp-lite",
- "libstatssocket"
],
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index bf6afe7..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 //
//////////////////////////////////////////////////////////////////////
@@ -8231,14 +8278,6 @@
}
/**
- * HWUI renders pipeline type: GL (0) or Vulkan (1).
- */
-enum PipelineType {
- GL = 0;
- VULKAN = 1;
-}
-
-/**
* HWUI stats for a given app.
*/
message GraphicsStats {
@@ -8251,9 +8290,16 @@
// The start & end timestamps in UTC as
// milliseconds since January 1, 1970
// Compatible with java.util.Date#setTime()
- optional int64 stats_start = 3;
+ optional int64 start_millis = 3;
- optional int64 stats_end = 4;
+ optional int64 end_millis = 4;
+
+ // HWUI renders pipeline type: GL (1) or Vulkan (2).
+ enum PipelineType {
+ UNKNOWN = 0;
+ GL = 1;
+ VULKAN = 2;
+ }
// HWUI renders pipeline type: GL or Vulkan.
optional PipelineType pipeline = 5;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 83d609c..0a138cf 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -960,7 +960,7 @@
return false;
}
List<GestureDescription.GestureStep> steps =
- MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 100);
+ MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 16);
try {
synchronized (mLock) {
mGestureStatusCallbackSequence++;
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/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
index 265674a..c6f42f7 100644
--- a/core/java/android/accessibilityservice/OWNERS
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -1,3 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
+qasid@google.com
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 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/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 180507c..3c475c1 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -315,11 +315,6 @@
void positionTaskInStack(int taskId, int stackId, int position);
void reportSizeConfigurations(in IBinder token, in int[] horizontalSizeConfiguration,
in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations);
- /**
- * Dismisses split-screen multi-window mode.
- * {@param toTop} If true the current primary split-screen stack will be placed or left on top.
- */
- void dismissSplitScreenMode(boolean toTop);
/**
* Dismisses PiP
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 526c0b3..948546b 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -88,6 +88,7 @@
void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
void createNotificationChannelsForPackage(String pkg, int uid, in ParceledListSlice channelsList);
+ ParceledListSlice getConversations(boolean onlyImportant);
ParceledListSlice getConversationsForPackage(String pkg, int uid);
ParceledListSlice getNotificationChannelGroupsForPackage(String pkg, int uid, boolean includeDeleted);
NotificationChannelGroup getNotificationChannelGroupForPackage(String groupId, String pkg, int uid);
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 655dd9b4..be87f5c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -148,6 +148,7 @@
import android.os.IPowerManager;
import android.os.IRecoverySystem;
import android.os.ISystemUpdateManager;
+import android.os.IThermalService;
import android.os.IUserManager;
import android.os.IncidentManager;
import android.os.PowerManager;
@@ -185,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;
@@ -221,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 =
@@ -576,10 +580,12 @@
new CachedServiceFetcher<PowerManager>() {
@Override
public PowerManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(Context.POWER_SERVICE);
- IPowerManager service = IPowerManager.Stub.asInterface(b);
- return new PowerManager(ctx.getOuterContext(),
- service, ctx.mMainThread.getHandler());
+ IBinder powerBinder = ServiceManager.getServiceOrThrow(Context.POWER_SERVICE);
+ IPowerManager powerService = IPowerManager.Stub.asInterface(powerBinder);
+ IBinder thermalBinder = ServiceManager.getServiceOrThrow(Context.THERMAL_SERVICE);
+ IThermalService thermalService = IThermalService.Stub.asInterface(thermalBinder);
+ return new PowerManager(ctx.getOuterContext(), powerService, thermalService,
+ ctx.mMainThread.getHandler());
}});
registerService(Context.RECOVERY_SERVICE, RecoverySystem.class,
@@ -1370,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;
}
/**
@@ -1379,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;
}
/**
@@ -1676,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..546fef9 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -33,6 +33,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.Activity;
@@ -1416,6 +1417,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";
@@ -5739,6 +5741,25 @@
}
/**
+ * Returns whether the admin has enabled always-on VPN lockdown for the current user.
+ *
+ * Only callable by the system.
+ * @hide
+ */
+ @UserHandleAware
+ public boolean isAlwaysOnVpnLockdownEnabled() {
+ throwIfParentInstance("isAlwaysOnVpnLockdownEnabled");
+ if (mService != null) {
+ try {
+ return mService.isAlwaysOnVpnLockdownEnabledForUser(myUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Called by device or profile owner to query the set of packages that are allowed to access
* the network directly when always-on VPN is in lockdown mode but not connected. Returns
* {@code null} when always-on VPN is not active or not in lockdown mode.
@@ -5785,6 +5806,26 @@
}
/**
+ * Returns the VPN package name if the admin has enabled always-on VPN on the current user,
+ * or {@code null} if none is set.
+ *
+ * Only callable by the system.
+ * @hide
+ */
+ @UserHandleAware
+ public @Nullable String getAlwaysOnVpnPackage() {
+ throwIfParentInstance("getAlwaysOnVpnPackage");
+ if (mService != null) {
+ try {
+ return mService.getAlwaysOnVpnPackageForUser(myUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
* Called by an application that is administering the device to disable all cameras on the
* device, for this user. After setting this, no applications running as this user will be able
* to access any cameras on the device.
@@ -11989,4 +12030,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..d161e06 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -196,7 +196,9 @@
boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist);
String getAlwaysOnVpnPackage(in ComponentName who);
+ String getAlwaysOnVpnPackageForUser(int userHandle);
boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who);
+ boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle);
List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who);
void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
@@ -478,4 +480,5 @@
long getManagedProfileMaximumTimeOff(in ComponentName admin);
void setManagedProfileMaximumTimeOff(in ComponentName admin, long timeoutMs);
+ boolean canProfileOwnerResetPasswordWhenLocked(in int userId);
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 5b60b85..3e1a480 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -25,6 +25,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Handler;
@@ -1299,6 +1300,31 @@
return false;
}
+ private static final String BLUETOOTH_BONDING_CACHE_PROPERTY =
+ "cache_key.bluetooth.get_bond_state";
+ private final PropertyInvalidatedCache<BluetoothDevice, Integer> mBluetoothBondCache =
+ new PropertyInvalidatedCache<BluetoothDevice, Integer>(
+ 8, BLUETOOTH_BONDING_CACHE_PROPERTY) {
+ @Override
+ protected Integer recompute(BluetoothDevice query) {
+ try {
+ return sService.getBondState(query);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+ };
+
+ /** @hide */
+ public void disableBluetoothGetBondStateCache() {
+ mBluetoothBondCache.disableLocal();
+ }
+
+ /** @hide */
+ public static void invalidateBluetoothGetBondStateCache() {
+ PropertyInvalidatedCache.invalidateCache(BLUETOOTH_BONDING_CACHE_PROPERTY);
+ }
+
/**
* Get the bond state of the remote device.
* <p>Possible values for the bond state are:
@@ -1316,9 +1342,13 @@
return BOND_NONE;
}
try {
- return service.getBondState(this);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
+ return mBluetoothBondCache.query(this);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof RemoteException) {
+ Log.e(TAG, "", e);
+ } else {
+ throw e;
+ }
}
return BOND_NONE;
}
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/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index a69905e..3a93421 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -22,6 +22,7 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.LocusId;
import android.content.pm.LauncherApps.ShortcutQuery;
@@ -92,4 +93,11 @@
public abstract void uncacheShortcuts(int launcherUserId,
@NonNull String callingPackage, @NonNull String packageName,
@NonNull List<String> shortcutIds, int userId);
+
+ /**
+ * Retrieves all of the direct share targets that match the given IntentFilter for the specified
+ * user.
+ */
+ public abstract List<ShortcutManager.ShareShortcutInfo> getShareTargets(
+ @NonNull String callingPackage, @NonNull IntentFilter intentFilter, int userId);
}
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/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 17c83f3..743ce7b 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -140,6 +140,11 @@
* <p>The set of combinations doesn't contain physical cameras that can only be used as
* part of a logical multi-camera device.</p>
*
+ * <p> If a new camera id becomes available through
+ * {@link AvailabilityCallback#onCameraUnavailable(String)}, clients can call
+ * this method to check if new combinations of camera ids which can stream concurrently are
+ * available.
+ *
* @return The set of combinations of currently connected camera devices, that may have
* sessions configured concurrently. The set of combinations will be empty if no such
* combinations are supported by the camera subsystem.
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 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/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
new file mode 100644
index 0000000..6ad7fae
--- /dev/null
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -0,0 +1,224 @@
+/*
+ * 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.hardware.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Product-specific information about the display or the directly connected device on the
+ * display chain. For example, if the display is transitively connected, this field may contain
+ * product information about the intermediate device.
+ * @hide
+ */
+public final class DeviceProductInfo implements Parcelable {
+ final private String mName;
+ final private String mManufacturerPnpId;
+ final private String mProductId;
+ final private Integer mModelYear;
+ final private ManufactureDate mManufactureDate;
+
+ public DeviceProductInfo(
+ String name,
+ String manufacturerPnpId,
+ String productCode,
+ Integer modelYear,
+ ManufactureDate manufactureDate) {
+ this.mName = name;
+ this.mManufacturerPnpId = manufacturerPnpId;
+ this.mProductId = productCode;
+ this.mModelYear = modelYear;
+ this.mManufactureDate = manufactureDate;
+ }
+
+ private DeviceProductInfo(Parcel in) {
+ mName = in.readString();
+ mManufacturerPnpId = in.readString();
+ mProductId = (String) in.readValue(null);
+ mModelYear = (Integer) in.readValue(null);
+ mManufactureDate = (ManufactureDate) in.readValue(null);
+ }
+
+ /**
+ * @return Display name.
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * @return Manufacturer Plug and Play ID.
+ */
+ public String getManufacturerPnpId() {
+ return mManufacturerPnpId;
+ }
+
+ /**
+ * @return Manufacturer product ID.
+ */
+ public String getProductId() {
+ return mProductId;
+ }
+
+ /**
+ * @return Model year of the device. Typically exactly one of model year or
+ * manufacture date will be present.
+ */
+ public Integer getModelYear() {
+ return mModelYear;
+ }
+
+ /**
+ * @return Manufacture date. Typically exactly one of model year or manufacture
+ * date will be present.
+ */
+ public ManufactureDate getManufactureDate() {
+ return mManufactureDate;
+ }
+
+ @Override
+ public String toString() {
+ return "DeviceProductInfo{"
+ + "name="
+ + mName
+ + ", manufacturerPnpId="
+ + mManufacturerPnpId
+ + ", productId="
+ + mProductId
+ + ", modelYear="
+ + mModelYear
+ + ", manufactureDate="
+ + mManufactureDate
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DeviceProductInfo that = (DeviceProductInfo) o;
+ return Objects.equals(mName, that.mName)
+ && Objects.equals(mManufacturerPnpId, that.mManufacturerPnpId)
+ && Objects.equals(mProductId, that.mProductId)
+ && Objects.equals(mModelYear, that.mModelYear)
+ && Objects.equals(mManufactureDate, that.mManufactureDate);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate);
+ }
+
+ public static final Creator<DeviceProductInfo> CREATOR =
+ new Creator<DeviceProductInfo>() {
+ @Override
+ public DeviceProductInfo createFromParcel(Parcel in) {
+ return new DeviceProductInfo(in);
+ }
+
+ @Override
+ public DeviceProductInfo[] newArray(int size) {
+ return new DeviceProductInfo[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mName);
+ dest.writeString(mManufacturerPnpId);
+ dest.writeValue(mProductId);
+ dest.writeValue(mModelYear);
+ dest.writeValue(mManufactureDate);
+ }
+
+ /**
+ * Stores information about the date of manufacture.
+ *
+ * @hide
+ */
+ public static class ManufactureDate implements Parcelable {
+ final private Integer mWeek;
+ final private Integer mYear;
+
+ public ManufactureDate(Integer week, Integer year) {
+ mWeek = week;
+ mYear = year;
+ }
+
+ protected ManufactureDate(Parcel in) {
+ mWeek = (Integer) in.readValue(null);
+ mYear = (Integer) in.readValue(null);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeValue(mWeek);
+ dest.writeValue(mYear);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<ManufactureDate> CREATOR =
+ new Creator<ManufactureDate>() {
+ @Override
+ public ManufactureDate createFromParcel(Parcel in) {
+ return new ManufactureDate(in);
+ }
+
+ @Override
+ public ManufactureDate[] newArray(int size) {
+ return new ManufactureDate[size];
+ }
+ };
+
+ public int getYear() {
+ return mYear;
+ }
+
+ public int getWeek() {
+ return mWeek;
+ }
+
+ @Override
+ public String toString() {
+ return "ManufactureDate{week=" + mWeek + ", year=" + mYear + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ManufactureDate that = (ManufactureDate) o;
+ return Objects.equals(mWeek, that.mWeek) && Objects.equals(mYear, that.mYear);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mWeek, mYear);
+ }
+ }
+}
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/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ea26ede..62eff45 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1279,7 +1279,8 @@
@UnsupportedAppUsage
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
try {
- return mService.getDefaultNetworkCapabilitiesForUser(userId);
+ return mService.getDefaultNetworkCapabilitiesForUser(
+ userId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1361,7 +1362,7 @@
@Nullable
public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
try {
- return mService.getNetworkCapabilities(network);
+ return mService.getNetworkCapabilities(network, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4039,10 +4040,9 @@
@NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
- final String callingPackageName = mContext.getOpPackageName();
try {
mService.pendingRequestForNetwork(
- request.networkCapabilities, operation, callingPackageName);
+ request.networkCapabilities, operation, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
@@ -4154,10 +4154,9 @@
@NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
- final String callingPackageName = mContext.getOpPackageName();
try {
mService.pendingListenForNetwork(
- request.networkCapabilities, operation, callingPackageName);
+ request.networkCapabilities, operation, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 1c7628f..d84d05d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -60,7 +60,8 @@
NetworkInfo[] getAllNetworkInfo();
Network getNetworkForType(int networkType);
Network[] getAllNetworks();
- NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId);
+ NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
+ int userId, String callingPackageName);
boolean isNetworkSupported(int networkType);
@@ -69,7 +70,7 @@
LinkProperties getLinkPropertiesForType(int networkType);
LinkProperties getLinkProperties(in Network network);
- NetworkCapabilities getNetworkCapabilities(in Network network);
+ NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
@UnsupportedAppUsage
NetworkState[] getAllNetworkState();
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 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/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index f8b51dd..83f9980 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -830,6 +830,23 @@
* <p>This field keeps track of the UID of the app that created this network and is in charge of
* its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
* VPN, or Carrier Service app managing a cellular data connection.
+ *
+ * <p>For NetworkCapability instances being sent from ConnectivityService, this value MUST be
+ * reset to Process.INVALID_UID unless all the following conditions are met:
+ *
+ * <ol>
+ * <li>The destination app is the network owner
+ * <li>The destination app has the ACCESS_FINE_LOCATION permission granted
+ * <li>The user's location toggle is on
+ * </ol>
+ *
+ * This is because the owner UID is location-sensitive. The apps that request a network could
+ * know where the device is if they can tell for sure the system has connected to the network
+ * they requested.
+ *
+ * <p>This is populated by the network agents and for the NetworkCapabilities instance sent by
+ * an app to the System Server, the value MUST be reset to Process.INVALID_UID by the system
+ * server.
*/
private int mOwnerUid = Process.INVALID_UID;
@@ -842,7 +859,16 @@
}
/**
- * Retrieves the UID of the owner app.
+ * Retrieves the UID of the app that owns this network.
+ *
+ * <p>For user privacy reasons, this field will only be populated if:
+ *
+ * <ol>
+ * <li>The calling app is the network owner
+ * <li>The calling app has the ACCESS_FINE_LOCATION permission granted
+ * <li>The user's location toggle is on
+ * </ol>
+ *
*/
public int getOwnerUid() {
return mOwnerUid;
@@ -880,8 +906,9 @@
* @param administratorUids the UIDs to be set as administrators of this Network.
* @hide
*/
+ @NonNull
@SystemApi
- public @NonNull NetworkCapabilities setAdministratorUids(
+ public NetworkCapabilities setAdministratorUids(
@NonNull final List<Integer> administratorUids) {
mAdministratorUids.clear();
mAdministratorUids.addAll(administratorUids);
diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl
index 8c98960..ad00233 100644
--- a/core/java/android/os/IThermalService.aidl
+++ b/core/java/android/os/IThermalService.aidl
@@ -103,4 +103,11 @@
* {@hide}
*/
List<CoolingDevice> getCurrentCoolingDevicesWithType(in int type);
+
+ /**
+ * @param forecastSeconds how many seconds ahead to forecast the provided headroom
+ * @return forecasted thermal headroom, normalized such that 1.0 indicates that throttling will
+ * occur; returns NaN if the headroom or forecast is unavailable
+ */
+ float getThermalHeadroom(int forecastSeconds);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index a8fa6db..199b5d5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -18,7 +18,9 @@
import android.Manifest.permission;
import android.annotation.CallbackExecutor;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -39,6 +41,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicLong;
/**
* This class gives you control of the power state of the device.
@@ -916,20 +919,22 @@
final IPowerManager mService;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
final Handler mHandler;
+ final IThermalService mThermalService;
/** We lazily initialize it.*/
private DeviceIdleManager mDeviceIdleManager;
- IThermalService mThermalService;
private final ArrayMap<OnThermalStatusChangedListener, IThermalStatusListener>
mListenerMap = new ArrayMap<>();
/**
* {@hide}
*/
- public PowerManager(Context context, IPowerManager service, Handler handler) {
+ public PowerManager(Context context, IPowerManager service, IThermalService thermalService,
+ Handler handler) {
mContext = context;
mService = service;
+ mThermalService = thermalService;
mHandler = handler;
}
@@ -1877,18 +1882,11 @@
* thermal throttling.
*/
public @ThermalStatus int getCurrentThermalStatus() {
- synchronized (this) {
- if (mThermalService == null) {
- mThermalService = IThermalService.Stub.asInterface(
- ServiceManager.getService(Context.THERMAL_SERVICE));
- }
- try {
- return mThermalService.getCurrentThermalStatus();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ try {
+ return mThermalService.getCurrentThermalStatus();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
-
}
/**
@@ -1915,13 +1913,7 @@
*/
public void addThermalStatusListener(@NonNull OnThermalStatusChangedListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
- synchronized (this) {
- if (mThermalService == null) {
- mThermalService = IThermalService.Stub.asInterface(
- ServiceManager.getService(Context.THERMAL_SERVICE));
- }
- this.addThermalStatusListener(mContext.getMainExecutor(), listener);
- }
+ this.addThermalStatusListener(mContext.getMainExecutor(), listener);
}
/**
@@ -1934,35 +1926,29 @@
@NonNull OnThermalStatusChangedListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
Preconditions.checkNotNull(executor, "executor cannot be null");
- synchronized (this) {
- if (mThermalService == null) {
- mThermalService = IThermalService.Stub.asInterface(
- ServiceManager.getService(Context.THERMAL_SERVICE));
- }
- Preconditions.checkArgument(!mListenerMap.containsKey(listener),
- "Listener already registered: " + listener);
- IThermalStatusListener internalListener = new IThermalStatusListener.Stub() {
- @Override
- public void onStatusChange(int status) {
- final long token = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- listener.onThermalStatusChanged(status);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ Preconditions.checkArgument(!mListenerMap.containsKey(listener),
+ "Listener already registered: " + listener);
+ IThermalStatusListener internalListener = new IThermalStatusListener.Stub() {
+ @Override
+ public void onStatusChange(int status) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> {
+ listener.onThermalStatusChanged(status);
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- };
- try {
- if (mThermalService.registerThermalStatusListener(internalListener)) {
- mListenerMap.put(listener, internalListener);
- } else {
- throw new RuntimeException("Listener failed to set");
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
}
+ };
+ try {
+ if (mThermalService.registerThermalStatusListener(internalListener)) {
+ mListenerMap.put(listener, internalListener);
+ } else {
+ throw new RuntimeException("Listener failed to set");
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1973,22 +1959,72 @@
*/
public void removeThermalStatusListener(@NonNull OnThermalStatusChangedListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
- synchronized (this) {
- if (mThermalService == null) {
- mThermalService = IThermalService.Stub.asInterface(
- ServiceManager.getService(Context.THERMAL_SERVICE));
+ IThermalStatusListener internalListener = mListenerMap.get(listener);
+ Preconditions.checkArgument(internalListener != null, "Listener was not added");
+ try {
+ if (mThermalService.unregisterThermalStatusListener(internalListener)) {
+ mListenerMap.remove(listener);
+ } else {
+ throw new RuntimeException("Listener failed to remove");
}
- IThermalStatusListener internalListener = mListenerMap.get(listener);
- Preconditions.checkArgument(internalListener != null, "Listener was not added");
- try {
- if (mThermalService.unregisterThermalStatusListener(internalListener)) {
- mListenerMap.remove(listener);
- } else {
- throw new RuntimeException("Listener failed to remove");
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @CurrentTimeMillisLong
+ private final AtomicLong mLastHeadroomUpdate = new AtomicLong(0L);
+ private static final int MINIMUM_HEADROOM_TIME_MILLIS = 500;
+
+ /**
+ * Provides an estimate of how much thermal headroom the device currently has before hitting
+ * severe throttling.
+ *
+ * Note that this only attempts to track the headroom of slow-moving sensors, such as the skin
+ * temperature sensor. This means that there is no benefit to calling this function more
+ * frequently than about once per second, and attempts to call significantly more frequently may
+ * result in the function returning {@code NaN}.
+ *
+ * In addition, in order to be able to provide an accurate forecast, the system does not attempt
+ * to forecast until it has multiple temperature samples from which to extrapolate. This should
+ * only take a few seconds from the time of the first call, but during this time, no forecasting
+ * will occur, and the current headroom will be returned regardless of the value of
+ * {@code forecastSeconds}.
+ *
+ * The value returned is a non-negative float that represents how much of the thermal envelope
+ * is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is (or
+ * will be) throttled at {@link #THERMAL_STATUS_SEVERE}. Such throttling can affect the CPU,
+ * GPU, and other subsystems. Values may exceed 1.0, but there is no implied mapping to specific
+ * thermal status levels beyond that point. This means that values greater than 1.0 may
+ * correspond to {@link #THERMAL_STATUS_SEVERE}, but may also represent heavier throttling.
+ *
+ * A value of 0.0 corresponds to a fixed distance from 1.0, but does not correspond to any
+ * particular thermal status or temperature. Values on (0.0, 1.0] may be expected to scale
+ * linearly with temperature, though temperature changes over time are typically not linear.
+ * Negative values will be clamped to 0.0 before returning.
+ *
+ * @param forecastSeconds how many seconds in the future to forecast. Given that device
+ * conditions may change at any time, forecasts from further in the
+ * future will likely be less accurate than forecasts in the near future.
+ * @return a value greater than or equal to 0.0 where 1.0 indicates the SEVERE throttling
+ * threshold, as described above. Returns NaN if the device does not support this
+ * functionality or if this function is called significantly faster than once per
+ * second.
+ */
+ public float getThermalHeadroom(@IntRange(from = 0, to = 60) int forecastSeconds) {
+ // Rate-limit calls into the thermal service
+ long now = SystemClock.elapsedRealtime();
+ long timeSinceLastUpdate = now - mLastHeadroomUpdate.get();
+ if (timeSinceLastUpdate < MINIMUM_HEADROOM_TIME_MILLIS) {
+ return Float.NaN;
+ }
+
+ try {
+ float forecast = mThermalService.getThermalHeadroom(forecastSeconds);
+ mLastHeadroomUpdate.set(SystemClock.elapsedRealtime());
+ return forecast;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
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/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8d04df0..1454aac 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -29,6 +29,7 @@
import static android.app.AppOpsManager.OP_WRITE_MEDIA_VIDEO;
import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.UserHandle.PER_USER_RANGE;
import android.annotation.BytesLong;
import android.annotation.CallbackExecutor;
@@ -2324,17 +2325,34 @@
private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
- // Matches AID_MEDIA_RW in android_filesystem_config.h
- private static final int QUOTA_PROJECT_ID_MEDIA_NONE = 1023;
+ // Project IDs below must match android_projectid_config.h
+ /**
+ * Default project ID for files on external storage
+ *
+ * {@hide}
+ */
+ public static final int PROJECT_ID_EXT_DEFAULT = 1000;
- // Matches AID_MEDIA_IMAGE in android_filesystem_config.h
- private static final int QUOTA_PROJECT_ID_MEDIA_IMAGE = 1057;
+ /**
+ * project ID for audio files on external storage
+ *
+ * {@hide}
+ */
+ public static final int PROJECT_ID_EXT_MEDIA_AUDIO = 1001;
- // Matches AID_MEDIA_AUDIO in android_filesystem_config.h
- private static final int QUOTA_PROJECT_ID_MEDIA_AUDIO = 1055;
+ /**
+ * project ID for video files on external storage
+ *
+ * {@hide}
+ */
+ public static final int PROJECT_ID_EXT_MEDIA_VIDEO = 1002;
- // Matches AID_MEDIA_VIDEO in android_filesystem_config.h
- private static final int QUOTA_PROJECT_ID_MEDIA_VIDEO = 1056;
+ /**
+ * project ID for image files on external storage
+ *
+ * {@hide}
+ */
+ public static final int PROJECT_ID_EXT_MEDIA_IMAGE = 1003;
/**
* Constant for use with
@@ -2388,6 +2406,11 @@
private static native boolean setQuotaProjectId(String path, long projectId);
+ private static long getProjectIdForUser(int userId, int projectId) {
+ // Much like UserHandle.getUid(), store the user ID in the upper bits
+ return userId * PER_USER_RANGE + projectId;
+ }
+
/**
* Let StorageManager know that the quota type for a file on external storage should
* be updated. Android tracks quotas for various media types. Consequently, this should be
@@ -2417,18 +2440,27 @@
@QuotaType int quotaType) throws IOException {
long projectId;
final String filePath = path.getCanonicalPath();
+ final StorageVolume volume = getStorageVolume(path);
+ if (volume == null) {
+ throw new IllegalStateException("Failed to update quota type for " + filePath);
+ }
+
+ final int userId = volume.getOwner().getIdentifier();
+ if (userId < 0) {
+ throw new IllegalStateException("Failed to update quota type for " + filePath);
+ }
switch (quotaType) {
case QUOTA_TYPE_MEDIA_NONE:
- projectId = QUOTA_PROJECT_ID_MEDIA_NONE;
+ projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_DEFAULT);
break;
case QUOTA_TYPE_MEDIA_AUDIO:
- projectId = QUOTA_PROJECT_ID_MEDIA_AUDIO;
+ projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_AUDIO);
break;
case QUOTA_TYPE_MEDIA_VIDEO:
- projectId = QUOTA_PROJECT_ID_MEDIA_VIDEO;
+ projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_VIDEO);
break;
case QUOTA_TYPE_MEDIA_IMAGE:
- projectId = QUOTA_PROJECT_ID_MEDIA_IMAGE;
+ projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_IMAGE);
break;
default:
throw new IllegalArgumentException("Invalid quota type: " + quotaType);
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index e78aef5..a2def7f 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -16,9 +16,12 @@
package android.os.storage;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IVold;
+import java.util.Set;
+
/**
* Mount service local interface.
*
@@ -97,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.
@@ -124,4 +133,14 @@
* legacy storage, {@code false} otherwise.
*/
public abstract boolean hasLegacyExternalStorage(int uid);
+
+ /**
+ * Makes sure app-private data directories on external storage are setup correctly
+ * after an application is installed or upgraded. The main use for this is OBB dirs,
+ * which can be created/modified by the installer.
+ *
+ * @param packageName the package name of the package
+ * @param uid the uid of the package
+ */
+ public abstract void prepareAppDataAfterInstall(@NonNull String packageName, int uid);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f86c971..b9abdf8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8595,6 +8595,15 @@
public static final String NOTIFICATION_HISTORY_ENABLED = "notification_history_enabled";
/**
+ * When enabled conversations marked as favorites will be set to bubble.
+ *
+ * The value 1 - enable, 0 - disable
+ * @hide
+ */
+ public static final String BUBBLE_IMPORTANT_CONVERSATIONS
+ = "bubble_important_conversations";
+
+ /**
* Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
* swipe).
*
@@ -8751,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
@@ -9084,26 +9100,34 @@
* Set to one of {@link #WIFI_SLEEP_POLICY_DEFAULT},
* {@link #WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED}, or
* {@link #WIFI_SLEEP_POLICY_NEVER}.
+ * @deprecated This is no longer used or set by the platform.
*/
+ @Deprecated
public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
/**
* Value for {@link #WIFI_SLEEP_POLICY} to use the default Wi-Fi sleep
* policy, which is to sleep shortly after the turning off
* according to the {@link #STAY_ON_WHILE_PLUGGED_IN} setting.
+ * @deprecated This is no longer used by the platform.
*/
+ @Deprecated
public static final int WIFI_SLEEP_POLICY_DEFAULT = 0;
/**
* Value for {@link #WIFI_SLEEP_POLICY} to use the default policy when
* the device is on battery, and never go to sleep when the device is
* plugged in.
+ * @deprecated This is no longer used by the platform.
*/
+ @Deprecated
public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1;
/**
* Value for {@link #WIFI_SLEEP_POLICY} to never go to sleep.
+ * @deprecated This is no longer used by the platform.
*/
+ @Deprecated
public static final int WIFI_SLEEP_POLICY_NEVER = 2;
/**
@@ -10197,7 +10221,9 @@
/**
* Delay (in seconds) before repeating the Wi-Fi networks available notification.
* Connecting to a network will reset the timer.
+ * @deprecated This is no longer used or set by the platform.
*/
+ @Deprecated
public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
"wifi_networks_available_repeat_delay";
@@ -10227,7 +10253,9 @@
/**
* When the number of open networks exceeds this number, the
* least-recently-used excess networks will be removed.
+ * @deprecated This is no longer used or set by the platform.
*/
+ @Deprecated
public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
/**
@@ -10238,8 +10266,8 @@
/**
* Setting to allow scans to be enabled even wifi is turned off for connectivity.
* @hide
+ * @deprecated To be removed.
*/
- @SystemApi
public static final String WIFI_SCAN_ALWAYS_AVAILABLE =
"wifi_scan_always_enabled";
@@ -10248,8 +10276,8 @@
*
* Type: int (0 for false, 1 for true)
* @hide
+ * @deprecated To be removed.
*/
- @SystemApi
public static final String WIFI_P2P_PENDING_FACTORY_RESET =
"wifi_p2p_pending_factory_reset";
@@ -10258,8 +10286,8 @@
*
* Type: int (0 for false, 1 for true)
* @hide
+ * @deprecated To be removed.
*/
- @SystemApi
public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled";
/**
@@ -10304,6 +10332,7 @@
* Most readers of this setting should simply check if value == 1 to determined the
* enabled state.
* @hide
+ * @deprecated To be removed.
*/
public static final String NETWORK_RECOMMENDATIONS_ENABLED =
"network_recommendations_enabled";
@@ -10343,13 +10372,11 @@
/**
* Whether wifi scan throttle is enabled or not.
- * This is intended to be used via adb commands or a menu in developer option to turn off
- * the default wifi scan throttling mechanism for apps.
*
* Type: int (0 for false, 1 for true)
* @hide
+ * @deprecated To be removed.
*/
- @SystemApi
public static final String WIFI_SCAN_THROTTLE_ENABLED = "wifi_scan_throttle_enabled";
/**
@@ -10451,8 +10478,8 @@
* Setting to enable verbose logging in Wi-Fi; disabled by default, and setting to 1
* will enable it. In the future, additional values may be supported.
* @hide
+ * @deprecated To be removed.
*/
- @SystemApi
public static final String WIFI_VERBOSE_LOGGING_ENABLED =
"wifi_verbose_logging_enabled";
@@ -10477,8 +10504,8 @@
* Default values are provided by code or device configurations.
* Errors in the parameters will cause the entire setting to be ignored.
* @hide
+ * @deprecated This is no longer used or set by the platform.
*/
- @SystemApi
public static final String WIFI_SCORE_PARAMS =
"wifi_score_params";
@@ -10520,8 +10547,8 @@
/**
* The Wi-Fi peer-to-peer device name
* @hide
+ * @deprecated To be removed.
*/
- @SystemApi
public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
/**
@@ -11482,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>
@@ -14298,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/service/notification/ConversationChannelWrapper.java b/core/java/android/service/notification/ConversationChannelWrapper.java
index 9847695..ab465ab 100644
--- a/core/java/android/service/notification/ConversationChannelWrapper.java
+++ b/core/java/android/service/notification/ConversationChannelWrapper.java
@@ -33,6 +33,8 @@
private CharSequence mGroupLabel;
private CharSequence mParentChannelLabel;
private ShortcutInfo mShortcutInfo;
+ private String mPkg;
+ private int mUid;
public ConversationChannelWrapper() {}
@@ -41,6 +43,8 @@
mGroupLabel = in.readCharSequence();
mParentChannelLabel = in.readCharSequence();
mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
+ mPkg = in.readStringNoHelper();
+ mUid = in.readInt();
}
@Override
@@ -49,6 +53,8 @@
dest.writeCharSequence(mGroupLabel);
dest.writeCharSequence(mParentChannelLabel);
dest.writeParcelable(mShortcutInfo, flags);
+ dest.writeStringNoHelper(mPkg);
+ dest.writeInt(mUid);
}
@Override
@@ -103,6 +109,22 @@
mShortcutInfo = shortcutInfo;
}
+ public String getPkg() {
+ return mPkg;
+ }
+
+ public void setPkg(String pkg) {
+ mPkg = pkg;
+ }
+
+ public int getUid() {
+ return mUid;
+ }
+
+ public void setUid(int uid) {
+ mUid = uid;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -111,12 +133,14 @@
return Objects.equals(getNotificationChannel(), that.getNotificationChannel()) &&
Objects.equals(getGroupLabel(), that.getGroupLabel()) &&
Objects.equals(getParentChannelLabel(), that.getParentChannelLabel()) &&
- Objects.equals(getShortcutInfo(), that.getShortcutInfo());
+ Objects.equals(getShortcutInfo(), that.getShortcutInfo()) &&
+ Objects.equals(getPkg(), that.getPkg()) &&
+ getUid() == that.getUid();
}
@Override
public int hashCode() {
return Objects.hash(getNotificationChannel(), getGroupLabel(), getParentChannelLabel(),
- getShortcutInfo());
+ getShortcutInfo(), getPkg(), getUid());
}
}
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 73e17a6..55542d8 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -16,15 +16,18 @@
package android.util;
+import android.annotation.NonNull;
import android.os.Parcel;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.LongObjPredicate;
import libcore.util.EmptyArray;
import java.util.Arrays;
+import java.util.Objects;
/**
* SparseArray mapping longs to Objects. Unlike a normal array of Objects,
@@ -145,6 +148,18 @@
delete(key);
}
+ /** @hide */
+ @SuppressWarnings("unchecked")
+ public void removeIf(@NonNull LongObjPredicate<? super E> filter) {
+ Objects.requireNonNull(filter);
+ for (int i = 0; i < mSize; ++i) {
+ if (mValues[i] != DELETED && filter.test(mKeys[i], (E) mValues[i])) {
+ mValues[i] = DELETED;
+ mGarbage = true;
+ }
+ }
+ }
+
/**
* Removes the mapping at the specified index.
*
diff --git a/core/java/android/view/CutoutSpecification.java b/core/java/android/view/CutoutSpecification.java
index d21a952..850e9fc 100644
--- a/core/java/android/view/CutoutSpecification.java
+++ b/core/java/android/view/CutoutSpecification.java
@@ -406,9 +406,7 @@
}
currentIndex += RIGHT_MARKER.length();
} else if (specWithoutDp.startsWith(BOTTOM_MARKER, currentIndex)) {
- if (!mPositionFromCenterVertical) {
- parseSvgPathSpec(region, sb.toString());
- }
+ parseSvgPathSpec(region, sb.toString());
currentIndex += BOTTOM_MARKER.length();
/* prepare to parse the rest path */
@@ -416,9 +414,7 @@
mBindBottomCutout = true;
mPositionFromBottom = true;
} else if (specWithoutDp.startsWith(CENTER_VERTICAL_MARKER, currentIndex)) {
- if (!mPositionFromBottom) {
- parseSvgPathSpec(region, sb.toString());
- }
+ parseSvgPathSpec(region, sb.toString());
currentIndex += CENTER_VERTICAL_MARKER.length();
/* prepare to parse the rest path */
@@ -431,14 +427,16 @@
/* prepare to parse the rest path */
resetStatus(sb);
} else if (specWithoutDp.startsWith(BIND_LEFT_CUTOUT_MARKER, currentIndex)) {
- if (!mBindBottomCutout && !mBindRightCutout) {
- mBindLeftCutout = true;
- }
+ mBindBottomCutout = false;
+ mBindRightCutout = false;
+ mBindLeftCutout = true;
+
currentIndex += BIND_LEFT_CUTOUT_MARKER.length();
} else if (specWithoutDp.startsWith(BIND_RIGHT_CUTOUT_MARKER, currentIndex)) {
- if (!mBindBottomCutout && !mBindLeftCutout) {
- mBindRightCutout = true;
- }
+ mBindBottomCutout = false;
+ mBindLeftCutout = false;
+ mBindRightCutout = true;
+
currentIndex += BIND_RIGHT_CUTOUT_MARKER.length();
} else {
currentIndex += 1;
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index b9868a7..3047385 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -28,6 +28,7 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.hardware.display.DeviceProductInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -70,6 +71,13 @@
public DisplayAddress address;
/**
+ * Product-specific information about the display or the directly connected device on the
+ * display chain. For example, if the display is transitively connected, this field may contain
+ * product information about the intermediate device.
+ */
+ public DeviceProductInfo deviceProductInfo;
+
+ /**
* The human-readable name of the display.
*/
public String name;
@@ -297,6 +305,7 @@
&& type == other.type
&& displayId == other.displayId
&& Objects.equals(address, other.address)
+ && Objects.equals(deviceProductInfo, other.deviceProductInfo)
&& Objects.equals(uniqueId, other.uniqueId)
&& appWidth == other.appWidth
&& appHeight == other.appHeight
@@ -336,6 +345,7 @@
type = other.type;
displayId = other.displayId;
address = other.address;
+ deviceProductInfo = other.deviceProductInfo;
name = other.name;
uniqueId = other.uniqueId;
appWidth = other.appWidth;
@@ -373,6 +383,7 @@
type = source.readInt();
displayId = source.readInt();
address = source.readParcelable(null);
+ deviceProductInfo = source.readParcelable(null);
name = source.readString();
appWidth = source.readInt();
appHeight = source.readInt();
@@ -418,6 +429,7 @@
dest.writeInt(type);
dest.writeInt(displayId);
dest.writeParcelable(address, flags);
+ dest.writeParcelable(deviceProductInfo, flags);
dest.writeString(name);
dest.writeInt(appWidth);
dest.writeInt(appHeight);
@@ -645,6 +657,8 @@
if (address != null) {
sb.append(", address ").append(address);
}
+ sb.append(", deviceProductInfo ");
+ sb.append(deviceProductInfo);
sb.append(", state ");
sb.append(Display.stateToString(state));
if (ownerUid != 0 || ownerPackageName != null) {
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 360dedd..58e5b2d 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.IntDef;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -28,6 +29,8 @@
import android.os.Parcelable;
import android.os.Vibrator;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
@@ -138,6 +141,19 @@
*/
public static final int SOURCE_CLASS_JOYSTICK = 0x00000010;
+ /** @hide */
+ @IntDef(flag = true, prefix = { "SOURCE_CLASS_" }, value = {
+ SOURCE_CLASS_NONE,
+ SOURCE_CLASS_BUTTON,
+ SOURCE_CLASS_POINTER,
+ SOURCE_CLASS_POINTER,
+ SOURCE_CLASS_TRACKBALL,
+ SOURCE_CLASS_POSITION,
+ SOURCE_CLASS_JOYSTICK
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface InputSourceClass {}
+
/**
* The input source is unknown.
*/
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 cf48c52..0816e84 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -41,6 +41,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
import android.os.Build;
@@ -213,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;
@@ -1286,12 +1287,14 @@
public boolean isInternal;
public float density;
public boolean secure;
+ public DeviceProductInfo deviceProductInfo;
@Override
public String toString() {
return "DisplayInfo{isInternal=" + isInternal
+ ", density=" + density
- + ", secure=" + secure + "}";
+ + ", secure=" + secure
+ + ", deviceProductInfo=" + deviceProductInfo + "}";
}
}
@@ -2735,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 5566e0e..73707ca 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -788,9 +788,16 @@
final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
boolean redrawNeeded = false;
+ getLocationInSurface(mLocation);
+ final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
+ || mWindowSpaceTop != mLocation[1];
+ final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
+ || getHeight() != mScreenRect.height();
- if (creating || formatChanged || sizeChanged || visibleChanged || (mUseAlpha
- && alphaChanged) || windowVisibleChanged) {
+
+ if (creating || formatChanged || sizeChanged || visibleChanged ||
+ (mUseAlpha && alphaChanged) || windowVisibleChanged ||
+ positionChanged || layoutSizeChanged) {
getLocationInWindow(mLocation);
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
@@ -922,6 +929,9 @@
mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
mSurfaceHeight);
}
+ } else if ((layoutSizeChanged || positionChanged) &&
+ WindowManagerGlobal.useBLAST()) {
+ viewRoot.setUseBLASTSyncTransaction();
}
mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
if (sizeChanged && !creating) {
@@ -1058,11 +1068,6 @@
} else {
// Calculate the window position in case RT loses the window
// and we need to fallback to a UI-thread driven position update
- getLocationInSurface(mLocation);
- final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
- || mWindowSpaceTop != mLocation[1];
- final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
- || getHeight() != mScreenRect.height();
if (positionChanged || layoutSizeChanged) { // Only the position has changed
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
@@ -1540,21 +1545,6 @@
}
/**
- * @hide
- * Note: Base class method is @UnsupportedAppUsage
- */
- @Override
- public void invalidate(boolean invalidateCache) {
- super.invalidate(invalidateCache);
- if (!WindowManagerGlobal.useBLAST()) {
- return;
- }
- final ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot == null) return;
- viewRoot.setUseBLASTSyncTransaction();
- }
-
- /**
* Display the view-hierarchy embedded within a {@link SurfaceControlViewHost.SurfacePackage}
* within this SurfaceView. If this SurfaceView is above it's host Surface (see
* {@link #setZOrderOnTop} then the embedded Surface hierarchy will be able to receive
@@ -1596,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 b9be33c..11ab572 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -110,6 +110,7 @@
import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.AccessibilityIterators.WordTextSegmentIterator;
import android.view.ContextMenu.ContextMenuInfo;
+import android.view.InputDevice.InputSourceClass;
import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsets.Type;
import android.view.WindowInsetsAnimation.Bounds;
@@ -5205,6 +5206,14 @@
private int mExplicitStyle;
/**
+ * Specifies which input source classes should provide unbuffered input events to this view
+ *
+ * @see View#requestUnbufferedDispatch(int)
+ */
+ @InputSourceClass
+ int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE;
+
+ /**
* Simple constructor to use when creating a view from code.
*
* @param context The Context the view is running in, through which it can
@@ -8013,6 +8022,10 @@
mAttachInfo.mKeyDispatchState.reset(this);
}
+ if (mParent != null) {
+ mParent.onDescendantUnbufferedRequested();
+ }
+
notifyEnterOrExitForAutoFillIfNeeded(gainFocus);
}
@@ -13429,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;
@@ -15820,12 +15832,17 @@
* system not batch {@link MotionEvent}s but instead deliver them as soon as they're
* available. This method should only be called for touch events.
*
- * <p class="note">This api is not intended for most applications. Buffered dispatch
+ * <p class="note">This API is not intended for most applications. Buffered dispatch
* provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent
* streams will not improve your input latency. Side effects include: increased latency,
* jittery scrolls and inability to take advantage of system resampling. Talk to your input
* professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for
* you.</p>
+ *
+ * To receive unbuffered events for arbitrary input device source classes, use
+ * {@link #requestUnbufferedDispatch(int)},
+ *
+ * @see View#requestUnbufferedDispatch(int)
*/
public final void requestUnbufferedDispatch(MotionEvent event) {
final int action = event.getAction();
@@ -15837,6 +15854,27 @@
mAttachInfo.mUnbufferedDispatchRequested = true;
}
+ /**
+ * Request unbuffered dispatch of the given event source class to this view.
+ * This is similar to {@link View#requestUnbufferedDispatch(MotionEvent)}, but does not
+ * automatically terminate, and allows the specification of arbitrary input source classes.
+ *
+ * @param source The combined input source class to request unbuffered dispatch for. All
+ * events coming from these source classes will not be buffered. Set to
+ * {@link InputDevice#SOURCE_CLASS_NONE} in order to return to default behaviour.
+ *
+ * @see View#requestUnbufferedDispatch(MotionEvent)
+ */
+ public final void requestUnbufferedDispatch(@InputSourceClass int source) {
+ if (mUnbufferedInputSource == source) {
+ return;
+ }
+ mUnbufferedInputSource = source;
+ if (mParent != null) {
+ mParent.onDescendantUnbufferedRequested();
+ }
+ }
+
private boolean hasSize() {
return (mBottom > mTop) && (mRight > mLeft);
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0367536..b6c46be 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3692,6 +3692,31 @@
}
childrenForAccessibility.clear();
}
+ info.setAvailableExtraData(Collections.singletonList(
+ AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param info The info to which to add the extra data. Never {@code null}.
+ * @param extraDataKey A key specifying the type of extra data to add to the info. The
+ * extra data should be added to the {@link Bundle} returned by
+ * the info's {@link AccessibilityNodeInfo#getExtras} method. Never
+ * {@code null}.
+ * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be
+ * {@code null} if the service provided no arguments.
+ *
+ */
+ @Override
+ public void addExtraDataToAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info,
+ @NonNull String extraDataKey, @Nullable Bundle arguments) {
+ if (extraDataKey.equals(AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY)) {
+ final AccessibilityNodeInfo.ExtraRenderingInfo extraRenderingInfo =
+ AccessibilityNodeInfo.ExtraRenderingInfo.obtain();
+ extraRenderingInfo.setLayoutParams(getLayoutParams().width, getLayoutParams().height);
+ info.setExtraRenderingInfo(extraRenderingInfo);
+ }
}
@Override
@@ -9004,4 +9029,30 @@
getChildAt(i).encode(encoder);
}
}
+
+ /** @hide */
+ @Override
+ public final void onDescendantUnbufferedRequested() {
+ // First look at the focused child for focused events
+ int focusedChildNonPointerSource = InputDevice.SOURCE_CLASS_NONE;
+ if (mFocused != null) {
+ focusedChildNonPointerSource = mFocused.mUnbufferedInputSource
+ & (~InputDevice.SOURCE_CLASS_POINTER);
+ }
+ mUnbufferedInputSource = focusedChildNonPointerSource;
+
+ // Request unbuffered dispatch for pointer events for this view if any child requested
+ // unbuffered dispatch for pointer events. This is because we can't expect that the pointer
+ // source would dispatch to the focused view.
+ for (int i = 0; i < mChildrenCount; i++) {
+ final View child = mChildren[i];
+ if ((child.mUnbufferedInputSource & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ mUnbufferedInputSource |= InputDevice.SOURCE_CLASS_POINTER;
+ break;
+ }
+ }
+ if (mParent != null) {
+ mParent.onDescendantUnbufferedRequested();
+ }
+ }
}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index f25206d..775c15e 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -675,4 +675,18 @@
*/
default void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
}
+
+ /**
+ * Unbuffered dispatch has been requested by a child of this view parent.
+ * This method is called by the View hierarchy to signal ancestors that a View needs to
+ * request unbuffered dispatch.
+ *
+ * @see View#requestUnbufferedDispatch(int)
+ * @hide
+ */
+ default void onDescendantUnbufferedRequested() {
+ if (getParent() != null) {
+ getParent().onDescendantUnbufferedRequested();
+ }
+ }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 043e5be..204d2c8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -18,6 +18,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.InputDevice.SOURCE_CLASS_NONE;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.View.PFLAG_DRAW_ANIMATION;
@@ -116,6 +117,7 @@
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.TypedValue;
+import android.view.InputDevice.InputSourceClass;
import android.view.InsetsState.InternalInsetsType;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl.Transaction;
@@ -499,6 +501,10 @@
int mPendingInputEventCount;
boolean mProcessInputEventsScheduled;
boolean mUnbufferedInputDispatch;
+ boolean mUnbufferedInputDispatchBySource;
+ @InputSourceClass
+ int mUnbufferedInputSource = SOURCE_CLASS_NONE;
+
String mPendingInputEventQueueLengthCounterName = "pq";
InputStage mFirstInputStage;
@@ -1849,7 +1855,7 @@
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
- if (!mUnbufferedInputDispatch) {
+ if (!mUnbufferedInputDispatch && !mUnbufferedInputDispatchBySource) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
@@ -7505,6 +7511,9 @@
writer.print(mTraversalScheduled);
writer.print(innerPrefix); writer.print("mIsAmbientMode=");
writer.print(mIsAmbientMode);
+ writer.print(innerPrefix); writer.print("mUnbufferedInputSource=");
+ writer.print(Integer.toHexString(mUnbufferedInputSource));
+
if (mTraversalScheduled) {
writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
} else {
@@ -8109,6 +8118,7 @@
@Override
public void onInputEvent(InputEvent event) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
+ processUnbufferedRequest(event);
List<InputEvent> processedEvents;
try {
processedEvents =
@@ -8134,7 +8144,7 @@
@Override
public void onBatchedInputEventPending() {
- if (mUnbufferedInputDispatch) {
+ if (mUnbufferedInputDispatch || mUnbufferedInputDispatchBySource) {
super.onBatchedInputEventPending();
} else {
scheduleConsumeBatchedInput();
@@ -8151,6 +8161,17 @@
unscheduleConsumeBatchedInput();
super.dispose();
}
+
+ private void processUnbufferedRequest(InputEvent event) {
+ if (!(event instanceof MotionEvent)) {
+ return;
+ }
+ mUnbufferedInputDispatchBySource =
+ (event.getSource() & mUnbufferedInputSource) != SOURCE_CLASS_NONE;
+ if (mUnbufferedInputDispatchBySource && mConsumeBatchedInputScheduled) {
+ scheduleConsumeBatchedInputImmediately();
+ }
+ }
}
WindowInputEventReceiver mInputEventReceiver;
@@ -9601,4 +9622,9 @@
return mSurfaceControl;
}
}
+
+ @Override
+ public void onDescendantUnbufferedRequested() {
+ mUnbufferedInputSource = mView.mUnbufferedInputSource;
+ }
}
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index cf34b0b..f406be9 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -26,6 +26,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
+import android.view.SurfaceControl;
import java.util.ArrayList;
import java.util.List;
@@ -77,8 +78,28 @@
public WindowContainerTransaction scheduleFinishEnterPip(IWindowContainer container,
Rect bounds) {
Change chg = getOrCreateChange(container.asBinder());
- chg.mSchedulePipCallback = true;
chg.mPinnedBounds = new Rect(bounds);
+ chg.mChangeMask |= Change.CHANGE_PIP_CALLBACK;
+
+ return this;
+ }
+
+ /**
+ * Send a SurfaceControl transaction to the server, which the server will apply in sync with
+ * the next bounds change. As this uses deferred transaction and not BLAST it is only
+ * able to sync with a single window, and the first visible window in this hierarchy of type
+ * BASE_APPLICATION to resize will be used. If there are bound changes included in this
+ * WindowContainer transaction (from setBounds or scheduleFinishEnterPip), the SurfaceControl
+ * transaction will be synced with those bounds. If there are no changes, then
+ * the SurfaceControl transaction will be synced with the next bounds change. This means
+ * that you can call this, apply the WindowContainer transaction, and then later call
+ * dismissPip() to achieve synchronization.
+ */
+ public WindowContainerTransaction setBoundsChangeTransaction(IWindowContainer container,
+ SurfaceControl.Transaction t) {
+ Change chg = getOrCreateChange(container.asBinder());
+ chg.mBoundsChangeTransaction = t;
+ chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION;
return this;
}
@@ -174,6 +195,8 @@
*/
public static class Change implements Parcelable {
public static final int CHANGE_FOCUSABLE = 1;
+ public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1;
+ public static final int CHANGE_PIP_CALLBACK = 1 << 2;
private final Configuration mConfiguration = new Configuration();
private boolean mFocusable = true;
@@ -181,8 +204,8 @@
private @ActivityInfo.Config int mConfigSetMask = 0;
private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
- private boolean mSchedulePipCallback = false;
private Rect mPinnedBounds = null;
+ private SurfaceControl.Transaction mBoundsChangeTransaction = null;
public Change() {}
@@ -192,11 +215,14 @@
mChangeMask = in.readInt();
mConfigSetMask = in.readInt();
mWindowSetMask = in.readInt();
- mSchedulePipCallback = (in.readInt() != 0);
- if (mSchedulePipCallback ) {
+ if ((mChangeMask & Change.CHANGE_PIP_CALLBACK) != 0) {
mPinnedBounds = new Rect();
mPinnedBounds.readFromParcel(in);
}
+ if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION) != 0) {
+ mBoundsChangeTransaction =
+ SurfaceControl.Transaction.CREATOR.createFromParcel(in);
+ }
}
public Configuration getConfiguration() {
@@ -233,6 +259,10 @@
return mPinnedBounds;
}
+ public SurfaceControl.Transaction getBoundsChangeTransaction() {
+ return mBoundsChangeTransaction;
+ }
+
@Override
public String toString() {
final boolean changesBounds =
@@ -264,10 +294,12 @@
dest.writeInt(mConfigSetMask);
dest.writeInt(mWindowSetMask);
- dest.writeInt(mSchedulePipCallback ? 1 : 0);
- if (mSchedulePipCallback ) {
+ if (mPinnedBounds != null) {
mPinnedBounds.writeToParcel(dest, flags);
}
+ if (mBoundsChangeTransaction != null) {
+ mBoundsChangeTransaction.writeToParcel(dest, flags);
+ }
}
@Override
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 62f3fa4..87dcba0 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -163,6 +163,15 @@
return !PixelFormat.formatHasAlpha(attrs.format);
}
+ /** @hide */
+ protected SurfaceControl getSurfaceControl(View rootView) {
+ final State s = mStateForWindow.get(rootView.getViewRootImpl().mWindow.asBinder());
+ if (s == null) {
+ return null;
+ }
+ return s.mSurfaceControl;
+ }
+
@Override
public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs,
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index bf2de14..eb4f9db 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -50,8 +50,12 @@
import android.util.Log;
import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
+import android.util.Size;
+import android.util.TypedValue;
import android.view.TouchDelegate;
import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.util.CollectionUtils;
@@ -634,6 +638,25 @@
public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH =
"android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ /**
+ * Key used to request extra data for accessibility scanning tool's purposes.
+ * The key requests that a {@link AccessibilityNodeInfo.ExtraRenderingInfo} be added to this
+ * info. This request is made with {@link #refreshWithExtraData(String, Bundle)} without
+ * argument.
+ * <p>
+ * The data can be retrieved from the {@link ExtraRenderingInfo} returned by
+ * {@link #getExtraRenderingInfo()} using {@link ExtraRenderingInfo#getLayoutParams},
+ * {@link ExtraRenderingInfo#getTextSizeInPx()} and
+ * {@link ExtraRenderingInfo#getTextSizeUnit()}. For layout params, it is supported by both
+ * {@link TextView} and {@link ViewGroup}. For text size and unit, it is only supported by
+ * {@link TextView}.
+ *
+ * @see #refreshWithExtraData(String, Bundle)
+ */
+
+ public static final String EXTRA_DATA_RENDERING_INFO_KEY =
+ "android.view.accessibility.extra.DATA_RENDERING_INFO_KEY";
+
/** @hide */
public static final String EXTRA_DATA_REQUESTED_KEY =
"android.view.accessibility.AccessibilityNodeInfo.extra_data_requested";
@@ -804,6 +827,8 @@
private TouchDelegateInfo mTouchDelegateInfo;
+ private ExtraRenderingInfo mExtraRenderingInfo;
+
private IBinder mLeashedChild;
private IBinder mLeashedParent;
private long mLeashedParentNodeId = UNDEFINED_NODE_ID;
@@ -991,6 +1016,7 @@
* @param extraDataKey The extra data requested. Data that must be requested
* with this mechanism is generally expensive to retrieve, so should only be
* requested when needed. See
+ * {@link #EXTRA_DATA_RENDERING_INFO_KEY},
* {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
* {@link #getAvailableExtraData()}.
* @param args A bundle of arguments for the request. These depend on the particular request.
@@ -1547,6 +1573,7 @@
* {@link #refreshWithExtraData(String, Bundle)}.
*
* @return An unmodifiable list of keys corresponding to extra data that can be requested.
+ * @see #EXTRA_DATA_RENDERING_INFO_KEY
* @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
*/
public List<String> getAvailableExtraData() {
@@ -2375,6 +2402,32 @@
}
/**
+ * Gets the conformance info if the node is meant to be refreshed with extra data.
+ *
+ * @return The conformance info.
+ */
+ @Nullable
+ public ExtraRenderingInfo getExtraRenderingInfo() {
+ return mExtraRenderingInfo;
+ }
+
+ /**
+ * Sets the conformance info if the node is meant to be refreshed with extra data.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param extraRenderingInfo The conformance info.
+ * @hide
+ */
+ public void setExtraRenderingInfo(@NonNull ExtraRenderingInfo extraRenderingInfo) {
+ enforceNotSealed();
+ mExtraRenderingInfo = extraRenderingInfo;
+ }
+
+ /**
* Gets if the content of this node is invalid. For example,
* a date is not well-formed.
*
@@ -3695,6 +3748,10 @@
nonDefaultFields |= bitAt(fieldIndex);
}
fieldIndex++;
+ if (!Objects.equals(mExtraRenderingInfo, DEFAULT.mExtraRenderingInfo)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
if (mLeashedChild != DEFAULT.mLeashedChild) {
nonDefaultFields |= bitAt(fieldIndex);
}
@@ -3833,6 +3890,12 @@
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ parcel.writeValue(mExtraRenderingInfo.getLayoutParams());
+ parcel.writeFloat(mExtraRenderingInfo.getTextSizeInPx());
+ parcel.writeInt(mExtraRenderingInfo.getTextSizeUnit());
+ }
+
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
parcel.writeStrongBinder(mLeashedChild);
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
@@ -3941,6 +4004,9 @@
if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
mCollectionItemInfo = (other.mCollectionItemInfo != null)
? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
+ if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle();
+ mExtraRenderingInfo = (other.mExtraRenderingInfo != null)
+ ? ExtraRenderingInfo.obtain(other.mExtraRenderingInfo) : null;
}
private void initCopyInfos(AccessibilityNodeInfo other) {
@@ -3955,6 +4021,9 @@
mCollectionItemInfo = (cii == null) ? null
: new CollectionItemInfo(cii.mRowIndex, cii.mRowSpan, cii.mColumnIndex,
cii.mColumnSpan, cii.mHeading, cii.mSelected);
+ ExtraRenderingInfo ti = other.mExtraRenderingInfo;
+ mExtraRenderingInfo = (ti == null) ? null
+ : new ExtraRenderingInfo(ti);
}
/**
@@ -4083,6 +4152,14 @@
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle();
+ mExtraRenderingInfo = ExtraRenderingInfo.obtain();
+ mExtraRenderingInfo.mLayoutParams = (Size) parcel.readValue(null);
+ mExtraRenderingInfo.mTextSizeInPx = parcel.readFloat();
+ mExtraRenderingInfo.mTextSizeUnit = parcel.readInt();
+ }
+
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
mLeashedChild = parcel.readStrongBinder();
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
@@ -5679,6 +5756,134 @@
}
/**
+ * Class with information of a view useful to evaluate accessibility needs. Developers can
+ * refresh the node with the key {@link #EXTRA_DATA_RENDERING_INFO_KEY} to fetch the text size
+ * and unit if it is {@link TextView} and the height and the width of layout params from
+ * {@link ViewGroup} or {@link TextView}.
+ *
+ * @see #EXTRA_DATA_RENDERING_INFO_KEY
+ * @see #refreshWithExtraData(String, Bundle)
+ */
+ public static final class ExtraRenderingInfo {
+ private static final int UNDEFINED_VALUE = -1;
+ private static final int MAX_POOL_SIZE = 20;
+ private static final SynchronizedPool<ExtraRenderingInfo> sPool =
+ new SynchronizedPool<>(MAX_POOL_SIZE);
+
+ private Size mLayoutParams;
+ private float mTextSizeInPx = UNDEFINED_VALUE;
+ private int mTextSizeUnit = UNDEFINED_VALUE;
+
+ /**
+ * Obtains a pooled instance.
+ * @hide
+ */
+ @NonNull
+ public static ExtraRenderingInfo obtain() {
+ final ExtraRenderingInfo info = sPool.acquire();
+ if (info == null) {
+ return new ExtraRenderingInfo(null);
+ }
+ return info;
+ }
+
+ /** Obtains a pooled instance that is a clone of another one. */
+ private static ExtraRenderingInfo obtain(ExtraRenderingInfo other) {
+ ExtraRenderingInfo extraRenderingInfo = ExtraRenderingInfo.obtain();
+ extraRenderingInfo.mLayoutParams = other.mLayoutParams;
+ extraRenderingInfo.mTextSizeInPx = other.mTextSizeInPx;
+ extraRenderingInfo.mTextSizeUnit = other.mTextSizeUnit;
+ return extraRenderingInfo;
+ }
+
+ /**
+ * Creates a new conformance info of a view, and this new instance is initialized from
+ * the given <code>other</code>.
+ *
+ * @param other The instance to clone.
+ */
+ private ExtraRenderingInfo(@Nullable ExtraRenderingInfo other) {
+ if (other != null) {
+ mLayoutParams = other.mLayoutParams;
+ mTextSizeInPx = other.mTextSizeInPx;
+ mTextSizeUnit = other.mTextSizeUnit;
+ }
+ }
+
+ /**
+ * @return a {@link Size} stores layout height and layout width of the view,
+ * or null otherwise.
+ */
+ public @Nullable Size getLayoutParams() {
+ return mLayoutParams;
+ }
+
+ /**
+ * Sets layout width and layout height of the view.
+ *
+ * @param width The layout width.
+ * @param height The layout height.
+ * @hide
+ */
+ public void setLayoutParams(int width, int height) {
+ mLayoutParams = new Size(width, height);
+ }
+
+ /**
+ * @return the text size of a {@code TextView}, or -1 otherwise.
+ */
+ public float getTextSizeInPx() {
+ return mTextSizeInPx;
+ }
+
+ /**
+ * Sets text size of the view.
+ *
+ * @param textSizeInPx The text size in pixels.
+ * @hide
+ */
+ public void setTextSizeInPx(float textSizeInPx) {
+ mTextSizeInPx = textSizeInPx;
+ }
+
+ /**
+ * @return the text size unit which type is {@link TypedValue#TYPE_DIMENSION} of a
+ * {@code TextView}, or -1 otherwise.
+ *
+ * @see TypedValue#TYPE_DIMENSION
+ */
+ public int getTextSizeUnit() {
+ return mTextSizeUnit;
+ }
+
+ /**
+ * Sets text size unit of the view.
+ *
+ * @param textSizeUnit The text size unit.
+ * @hide
+ */
+ public void setTextSizeUnit(int textSizeUnit) {
+ mTextSizeUnit = textSizeUnit;
+ }
+
+ /**
+ * Recycles this instance.
+ *
+ * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+ */
+ void recycle() {
+ clear();
+ sPool.release(this);
+ }
+
+ private void clear() {
+ mLayoutParams = null;
+ mTextSizeInPx = UNDEFINED_VALUE;
+ mTextSizeUnit = UNDEFINED_VALUE;
+ }
+ }
+
+ /**
* @see android.os.Parcelable.Creator
*/
public static final @android.annotation.NonNull Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index 265674a..c6f42f7 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -1,3 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
+qasid@google.com
diff --git a/core/java/android/view/inline/InlinePresentationSpec.java b/core/java/android/view/inline/InlinePresentationSpec.java
index 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..13c1f67 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;
@@ -151,9 +152,6 @@
private static final String TAG = "Editor";
private static final boolean DEBUG_UNDO = false;
- // Specifies whether to allow starting a cursor drag by dragging anywhere over the text.
- @VisibleForTesting
- public static boolean FLAG_ENABLE_CURSOR_DRAG = true;
// Specifies whether to use the magnifier when pressing the insertion or selection handles.
private static final boolean FLAG_USE_MAGNIFIER = true;
@@ -387,13 +385,25 @@
private final SuggestionHelper mSuggestionHelper = new SuggestionHelper();
- // Specifies whether the cursor control feature set is enabled.
- // This can only be true if the text view is editable.
- private boolean mCursorControlEnabled;
+ private boolean mFlagCursorDragFromAnywhereEnabled;
+ private boolean mFlagInsertionHandleGesturesEnabled;
// Specifies whether the new magnifier (with fish-eye effect) is enabled.
private final boolean mNewMagnifierEnabled;
+ // Line height range in DP for the new magnifier.
+ static private final int MIN_LINE_HEIGHT_FOR_MAGNIFIER = 20;
+ static private final int MAX_LINE_HEIGHT_FOR_MAGNIFIER = 32;
+ // Line height range in pixels for the new magnifier.
+ // - If the line height is bigger than the max, magnifier should be dismissed.
+ // - If the line height is smaller than the min, magnifier should apply a bigger zoom factor
+ // to make sure the text can be seen clearly.
+ private int mMinLineHeightForMagnifier;
+ private int mMaxLineHeightForMagnifier;
+ // The zoom factor initially configured.
+ // The actual zoom value may changes based on this initial zoom value.
+ private float mInitialZoom = 1f;
+
Editor(TextView textView) {
mTextView = textView;
// Synchronize the filter list, which places the undo input filter at the end.
@@ -402,26 +412,43 @@
mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableHapticTextHandle);
- mCursorControlEnabled = AppGlobals.getIntCoreSetting(
- WidgetFlags.KEY_ENABLE_CURSOR_CONTROL , 0) != 0;
+ mFlagCursorDragFromAnywhereEnabled = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
+ WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT ? 1 : 0) != 0;
+ mFlagInsertionHandleGesturesEnabled = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES,
+ WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT ? 1 : 0) != 0;
mNewMagnifierEnabled = AppGlobals.getIntCoreSetting(
- WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, 0) != 0;
+ WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER,
+ WidgetFlags.ENABLE_NEW_MAGNIFIER_DEFAULT ? 1 : 0) != 0;
if (TextView.DEBUG_CURSOR) {
- logCursor("Editor", "Cursor control is %s.",
- mCursorControlEnabled ? "enabled" : "disabled");
+ logCursor("Editor", "Cursor drag from anywhere is %s.",
+ mFlagCursorDragFromAnywhereEnabled ? "enabled" : "disabled");
+ logCursor("Editor", "Insertion handle gestures is %s.",
+ mFlagInsertionHandleGesturesEnabled ? "enabled" : "disabled");
logCursor("Editor", "New magnifier is %s.",
mNewMagnifierEnabled ? "enabled" : "disabled");
}
}
@VisibleForTesting
- public void setCursorControlEnabled(boolean enabled) {
- mCursorControlEnabled = enabled;
+ public boolean getFlagCursorDragFromAnywhereEnabled() {
+ return mFlagCursorDragFromAnywhereEnabled;
}
@VisibleForTesting
- public boolean getCursorControlEnabled() {
- return mCursorControlEnabled;
+ public void setFlagCursorDragFromAnywhereEnabled(boolean enabled) {
+ mFlagCursorDragFromAnywhereEnabled = enabled;
+ }
+
+ @VisibleForTesting
+ public boolean getFlagInsertionHandleGesturesEnabled() {
+ return mFlagInsertionHandleGesturesEnabled;
+ }
+
+ @VisibleForTesting
+ public void setFlagInsertionHandleGesturesEnabled(boolean enabled) {
+ mFlagInsertionHandleGesturesEnabled = enabled;
}
// Lazy creates the magnifier animator.
@@ -440,12 +467,12 @@
private Magnifier.Builder createBuilderWithInlineMagnifierDefaults() {
final Magnifier.Builder params = new Magnifier.Builder(mTextView);
- // TODO: supports changing the height/width dynamically because the text height can be
- // dynamically changed.
float zoom = AppGlobals.getFloatCoreSetting(
- WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, 1.5f);
+ WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR,
+ WidgetFlags.MAGNIFIER_ZOOM_FACTOR_DEFAULT);
float aspectRatio = AppGlobals.getFloatCoreSetting(
- WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, 5.5f);
+ WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO,
+ WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT);
// Avoid invalid/unsupported values.
if (zoom < 1.2f || zoom > 1.8f) {
zoom = 1.5f;
@@ -454,13 +481,20 @@
aspectRatio = 5.5f;
}
+ mInitialZoom = zoom;
+ mMinLineHeightForMagnifier = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, MIN_LINE_HEIGHT_FOR_MAGNIFIER,
+ mTextView.getContext().getResources().getDisplayMetrics());
+ mMaxLineHeightForMagnifier = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, MAX_LINE_HEIGHT_FOR_MAGNIFIER,
+ mTextView.getContext().getResources().getDisplayMetrics());
+
final Layout layout = mTextView.getLayout();
final int line = layout.getLineForOffset(mTextView.getSelectionStart());
final int sourceHeight =
layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
- // Slightly increase the height to avoid tooLargeTextForMagnifier() returns true.
- int height = (int)(sourceHeight * zoom) + 2;
- int width = (int)(aspectRatio * height);
+ final int height = (int)(sourceHeight * zoom);
+ final int width = (int)(aspectRatio * Math.max(sourceHeight, mMinLineHeightForMagnifier));
params.setFishEyeStyle()
.setSize(width, height)
@@ -4902,6 +4936,12 @@
}
private boolean tooLargeTextForMagnifier() {
+ if (mNewMagnifierEnabled) {
+ Layout layout = mTextView.getLayout();
+ final int line = layout.getLineForOffset(getCurrentCursorOffset());
+ return layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line)
+ >= mMaxLineHeightForMagnifier;
+ }
final float magnifierContentHeight = Math.round(
mMagnifierAnimator.mMagnifier.getHeight()
/ mMagnifierAnimator.mMagnifier.getZoom());
@@ -5111,9 +5151,16 @@
int lineRight = (int) layout.getLineRight(line);
lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight);
+ final int lineHeight =
+ layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
+ float zoom = mInitialZoom;
+ if (lineHeight < mMinLineHeightForMagnifier) {
+ zoom = zoom * mMinLineHeightForMagnifier / lineHeight;
+ }
+ mMagnifierAnimator.mMagnifier.updateSourceFactors(lineHeight, zoom);
mMagnifierAnimator.mMagnifier.show(showPosInView.x, showPosInView.y);
} else {
- mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
+ mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
}
updateHandlesVisibility();
} else {
@@ -5259,11 +5306,13 @@
int deltaHeight = 0;
int opacity = 255;
- if (mCursorControlEnabled) {
+ if (mFlagInsertionHandleGesturesEnabled) {
deltaHeight = AppGlobals.getIntCoreSetting(
- WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, 25);
+ WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT,
+ WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT);
opacity = AppGlobals.getIntCoreSetting(
- WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, 50);
+ WidgetFlags.KEY_INSERTION_HANDLE_OPACITY,
+ WidgetFlags.INSERTION_HANDLE_OPACITY_DEFAULT);
// Avoid invalid/unsupported values.
if (deltaHeight < -25 || deltaHeight > 50) {
deltaHeight = 25;
@@ -5329,7 +5378,7 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mCursorControlEnabled) {
+ if (mFlagInsertionHandleGesturesEnabled) {
final int height = Math.max(
getPreferredHeight() + mDeltaHeight, mDrawable.getIntrinsicHeight());
setMeasuredDimension(getPreferredWidth(), height);
@@ -5340,7 +5389,7 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
- if (mCursorControlEnabled && FLAG_ENABLE_CURSOR_DRAG) {
+ if (mFlagInsertionHandleGesturesEnabled && mFlagCursorDragFromAnywhereEnabled) {
// Should only enable touch through when cursor drag is enabled.
// Otherwise the insertion handle view cannot be moved.
return touchThrough(ev);
@@ -6012,7 +6061,13 @@
@VisibleForTesting
public class InsertionPointCursorController implements CursorController {
private InsertionHandleView mHandle;
+ // Tracks whether the cursor is currently being dragged.
private boolean mIsDraggingCursor;
+ // During a drag, tracks whether the user's finger has adjusted to be over the handle rather
+ // than the cursor bar.
+ private boolean mIsTouchSnappedToHandleDuringDrag;
+ // During a drag, tracks the line of text where the cursor was last positioned.
+ private int mPrevLineDuringDrag;
public void onTouchEvent(MotionEvent event) {
if (hasSelectionController() && getSelectionController().isCursorBeingModified()) {
@@ -6025,7 +6080,7 @@
}
if (mIsDraggingCursor) {
performCursorDrag(event);
- } else if (FLAG_ENABLE_CURSOR_DRAG
+ } else if (mFlagCursorDragFromAnywhereEnabled
&& mTextView.getLayout() != null
&& mTextView.isFocused()
&& mTouchState.isMovedEnoughForDrag()
@@ -6043,8 +6098,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 +6112,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 +6186,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/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0182975..815cc5c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
package android.widget;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
@@ -727,6 +728,7 @@
@UnsupportedAppUsage
private Layout mLayout;
private boolean mLocalesChanged = false;
+ private int mTextSizeUnit = -1;
// True if setKeyListener() has been explicitly called
private boolean mListenerChanged = false;
@@ -3842,6 +3844,7 @@
ColorStateList mTextColorHint = null;
ColorStateList mTextColorLink = null;
int mTextSize = -1;
+ int mTextSizeUnit = -1;
LocaleList mTextLocales = null;
String mFontFamily = null;
Typeface mFontTypeface = null;
@@ -3869,6 +3872,7 @@
+ " mTextColorHint:" + mTextColorHint + "\n"
+ " mTextColorLink:" + mTextColorLink + "\n"
+ " mTextSize:" + mTextSize + "\n"
+ + " mTextSizeUnit:" + mTextSizeUnit + "\n"
+ " mTextLocales:" + mTextLocales + "\n"
+ " mFontFamily:" + mFontFamily + "\n"
+ " mFontTypeface:" + mFontTypeface + "\n"
@@ -3980,6 +3984,7 @@
case com.android.internal.R.styleable.TextAppearance_textSize:
attributes.mTextSize =
appearance.getDimensionPixelSize(attr, attributes.mTextSize);
+ attributes.mTextSizeUnit = appearance.peekValue(attr).getComplexUnit();
break;
case com.android.internal.R.styleable.TextAppearance_textLocale:
final String localeString = appearance.getString(attr);
@@ -4073,6 +4078,7 @@
}
if (attributes.mTextSize != -1) {
+ mTextSizeUnit = attributes.mTextSizeUnit;
setRawTextSize(attributes.mTextSize, true /* shouldRequestLayout */);
}
@@ -4295,6 +4301,7 @@
r = c.getResources();
}
+ mTextSizeUnit = unit;
setRawTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()),
shouldRequestLayout);
}
@@ -4315,6 +4322,17 @@
}
/**
+ * Gets the text size unit defined by the developer. It may be specified in resources or be
+ * passed as the unit argument of {@link #setTextSize(int, float)} at runtime.
+ *
+ * @return the dimension type of the text size unit originally defined.
+ * @see TypedValue#TYPE_DIMENSION
+ */
+ public int getTextSizeUnit() {
+ return mTextSizeUnit;
+ }
+
+ /**
* Gets the extent by which text should be stretched horizontally.
* This will usually be 1.0.
* @return The horizontal scale factor.
@@ -11769,8 +11787,14 @@
| AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
| AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
- info.setAvailableExtraData(
- Arrays.asList(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY));
+ info.setAvailableExtraData(Arrays.asList(
+ EXTRA_DATA_RENDERING_INFO_KEY,
+ EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
+ ));
+ } else {
+ info.setAvailableExtraData(Arrays.asList(
+ EXTRA_DATA_RENDERING_INFO_KEY
+ ));
}
if (isFocused()) {
@@ -11824,11 +11848,7 @@
@Override
public void addExtraDataToAccessibilityNodeInfo(
AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
- // The only extra data we support requires arguments.
- if (arguments == null) {
- return;
- }
- if (extraDataKey.equals(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)) {
+ if (arguments != null && extraDataKey.equals(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)) {
int positionInfoStartIndex = arguments.getInt(
EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX, -1);
int positionInfoLength = arguments.getInt(
@@ -11856,6 +11876,15 @@
}
}
info.getExtras().putParcelableArray(extraDataKey, boundingRects);
+ return;
+ }
+ if (extraDataKey.equals(AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY)) {
+ final AccessibilityNodeInfo.ExtraRenderingInfo extraRenderingInfo =
+ AccessibilityNodeInfo.ExtraRenderingInfo.obtain();
+ extraRenderingInfo.setLayoutParams(getLayoutParams().width, getLayoutParams().height);
+ extraRenderingInfo.setTextSizeInPx(getTextSize());
+ extraRenderingInfo.setTextSizeUnit(getTextSizeUnit());
+ info.setExtraRenderingInfo(extraRenderingInfo);
}
}
diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java
index 1a8e7a7..bce5497 100644
--- a/core/java/android/widget/WidgetFlags.java
+++ b/core/java/android/widget/WidgetFlags.java
@@ -17,27 +17,49 @@
package android.widget;
/**
- * Keeps the flags related to the Widget namespace in {@link DeviceConfig}.
+ * Flags in the {@link android.provider.DeviceConfig#NAMESPACE_WIDGET "widget" namespace}.
*
* @hide
*/
public final class WidgetFlags {
/**
- * Whether the cursor control feature set is enabled.
- * TODO: Makes this flag key visible to webview/chrome.
+ * Whether starting a cursor drag from anywhere in the text should be enabled.
*/
- public static final String ENABLE_CURSOR_CONTROL =
- "CursorControlFeature__enable_cursor_control";
+ public static final String ENABLE_CURSOR_DRAG_FROM_ANYWHERE =
+ "CursorControlFeature__enable_cursor_drag_from_anywhere";
/**
- * The key name used in app core settings for enable cursor control.
+ * The key used in app core settings for the flag {@link #ENABLE_CURSOR_DRAG_FROM_ANYWHERE}.
*/
- public static final String KEY_ENABLE_CURSOR_CONTROL = "widget__enable_cursor_control";
+ public static final String KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE =
+ "widget__enable_cursor_drag_from_anywhere";
+
+ /**
+ * Default value for the flag {@link #ENABLE_CURSOR_DRAG_FROM_ANYWHERE}.
+ */
+ public static final boolean ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT = true;
+
+ /**
+ * Whether additional gestures should be enabled for the insertion cursor handle (e.g.
+ * long-press or double-tap on the handle to trigger selection).
+ */
+ public static final String ENABLE_INSERTION_HANDLE_GESTURES =
+ "CursorControlFeature__enable_insertion_handle_gestures";
+
+ /**
+ * The key used in app core settings for the flag {@link #ENABLE_INSERTION_HANDLE_GESTURES}.
+ */
+ public static final String KEY_ENABLE_INSERTION_HANDLE_GESTURES =
+ "widget__enable_insertion_handle_gestures";
+
+ /**
+ * Default value for the flag {@link #ENABLE_INSERTION_HANDLE_GESTURES}.
+ */
+ public static final boolean ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT = false;
/**
* The flag of delta height applies to the insertion handle when cursor control flag is enabled.
- * The default value is 25.
*/
public static final String INSERTION_HANDLE_DELTA_HEIGHT =
"CursorControlFeature__insertion_handle_delta_height";
@@ -49,8 +71,13 @@
"widget__insertion_handle_delta_height";
/**
+ * Default value for the flag {@link #INSERTION_HANDLE_DELTA_HEIGHT}.
+ */
+ public static final int INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT = 25;
+
+ /**
* The flag of opacity applies to the insertion handle when cursor control flag is enabled.
- * The opacity value is in the range of {0..100}. The default value is 50.
+ * The opacity value is in the range of {0..100}.
*/
public static final String INSERTION_HANDLE_OPACITY =
"CursorControlFeature__insertion_handle_opacity";
@@ -62,6 +89,11 @@
"widget__insertion_handle_opacity";
/**
+ * Default value for the flag {@link #INSERTION_HANDLE_OPACITY}.
+ */
+ public static final int INSERTION_HANDLE_OPACITY_DEFAULT = 50;
+
+ /**
* The flag of enabling the new magnifier.
*/
public static final String ENABLE_NEW_MAGNIFIER = "CursorControlFeature__enable_new_magnifier";
@@ -72,8 +104,12 @@
public static final String KEY_ENABLE_NEW_MAGNIFIER = "widget__enable_new_magnifier";
/**
+ * Default value for the flag {@link #ENABLE_NEW_MAGNIFIER}.
+ */
+ public static final boolean ENABLE_NEW_MAGNIFIER_DEFAULT = false;
+
+ /**
* The flag of zoom factor applies to the new magnifier.
- * The default value is 1.5f.
*/
public static final String MAGNIFIER_ZOOM_FACTOR =
"CursorControlFeature__magnifier_zoom_factor";
@@ -84,8 +120,12 @@
public static final String KEY_MAGNIFIER_ZOOM_FACTOR = "widget__magnifier_zoom_factor";
/**
+ * Default value for the flag {@link #MAGNIFIER_ZOOM_FACTOR}.
+ */
+ public static final float MAGNIFIER_ZOOM_FACTOR_DEFAULT = 1.5f;
+
+ /**
* The flag of aspect ratio (width/height) applies to the new magnifier.
- * The default value is 5.5f.
*/
public static final String MAGNIFIER_ASPECT_RATIO =
"CursorControlFeature__magnifier_aspect_ratio";
@@ -95,6 +135,11 @@
*/
public static final String KEY_MAGNIFIER_ASPECT_RATIO = "widget__magnifier_aspect_ratio";
+ /**
+ * Default value for the flag {@link #MAGNIFIER_ASPECT_RATIO}.
+ */
+ public static final float MAGNIFIER_ASPECT_RATIO_DEFAULT = 5.5f;
+
private WidgetFlags() {
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 61d22d1..250b1ea 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1805,6 +1805,10 @@
if (!TextUtils.isEmpty(dataString)) {
return new IntentFilter(intent.getAction(), dataString);
}
+ if (intent.getType() == null) {
+ Log.e(TAG, "Failed to get target intent filter: intent data and type are null");
+ return null;
+ }
IntentFilter intentFilter = new IntentFilter(intent.getAction(), intent.getType());
List<Uri> contentUris = new ArrayList<>();
if (Intent.ACTION_SEND.equals(intent.getAction())) {
@@ -1825,7 +1829,7 @@
}
return intentFilter;
} catch (Exception e) {
- Log.e(TAG, "failed to get target intent filter", e);
+ Log.e(TAG, "Failed to get target intent filter", e);
return null;
}
}
@@ -3100,7 +3104,7 @@
final ViewGroup viewGroup = (ViewGroup) holder.itemView;
int start = getListPosition(position);
int startType = getRowType(start);
- if (viewGroup.getForeground() == null) {
+ if (viewGroup.getForeground() == null && position > 0) {
viewGroup.setForeground(
getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
}
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/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index f168215..96bfe73 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1566,6 +1566,7 @@
viewPager.setVisibility(View.VISIBLE);
tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage());
mMultiProfilePagerAdapter.setOnProfileSelectedListener(tabHost::setCurrentTab);
+ findViewById(R.id.resolver_tab_divider).setVisibility(View.VISIBLE);
}
private void resetTabsHeaderStyle(TabWidget tabWidget) {
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/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
new file mode 100644
index 0000000..f44b9fb
--- /dev/null
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -0,0 +1,30 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "com.android.internal.os.KernelCpuUidFreqTimeReaderTest"
+ },
+ {
+ "include-filter": "com.android.internal.os.KernelCpuUidActiveTimeReaderTest"
+ },
+ {
+ "include-filter": "com.android.internal.os.KernelCpuUidClusterTimeReaderTest"
+ },
+ {
+ "include-filter": "com.android.internal.os.KernelSingleUidTimeReaderTest"
+ },
+ {
+ "include-filter": "com.android.internal.os.KernelCpuUidBpfMapReaderTest"
+ }
+
+ ],
+ "file_patterns": [
+ "KernelCpuUidTimeReader\\.java",
+ "KernelCpuUidBpfMapReader\\.java",
+ "KernelSingleUidTimeReader\\.java"
+ ]
+ }
+ ]
+}
diff --git a/core/java/com/android/internal/policy/DockedDividerUtils.java b/core/java/com/android/internal/policy/DockedDividerUtils.java
index c68e506..b61b9de 100644
--- a/core/java/com/android/internal/policy/DockedDividerUtils.java
+++ b/core/java/com/android/internal/policy/DockedDividerUtils.java
@@ -16,14 +16,15 @@
package com.android.internal.policy;
-import android.graphics.Rect;
-
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
+import android.content.res.Resources;
+import android.graphics.Rect;
+
/**
* Utility functions for docked stack divider used by both window manager and System UI.
*
@@ -105,23 +106,6 @@
return start + (end - start) / 2 - dividerSize / 2;
}
- public static int getDockSideFromCreatedMode(boolean dockOnTopOrLeft,
- boolean isHorizontalDivision) {
- if (dockOnTopOrLeft) {
- if (isHorizontalDivision) {
- return DOCKED_TOP;
- } else {
- return DOCKED_LEFT;
- }
- } else {
- if (isHorizontalDivision) {
- return DOCKED_BOTTOM;
- } else {
- return DOCKED_RIGHT;
- }
- }
- }
-
public static int invertDockSide(int dockSide) {
switch (dockSide) {
case DOCKED_LEFT:
@@ -136,4 +120,21 @@
return DOCKED_INVALID;
}
}
+
+ /** Returns the inset distance from the divider window edge to the dividerview. */
+ public static int getDividerInsets(Resources res) {
+ return res.getDimensionPixelSize(com.android.internal.R.dimen.docked_stack_divider_insets);
+ }
+
+ /** Returns the size of the divider */
+ public static int getDividerSize(Resources res, int dividerInsets) {
+ final int windowWidth = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.docked_stack_divider_thickness);
+ return windowWidth - 2 * dividerInsets;
+ }
+
+ /** Returns the docked-stack side */
+ public static int getDockSide(int displayWidth, int displayHeight) {
+ return displayWidth > displayHeight ? DOCKED_LEFT : DOCKED_TOP;
+ }
}
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/util/function/LongObjPredicate.java b/core/java/com/android/internal/util/function/LongObjPredicate.java
new file mode 100644
index 0000000..9e46307
--- /dev/null
+++ b/core/java/com/android/internal/util/function/LongObjPredicate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.util.function;
+
+/**
+ * Represents a predicate (boolean-valued function) of a {@code long}-valued argument
+ * and an object-valued argument.
+ *
+ * @param <T> the type of the object-valued argument to the predicate
+ */
+@FunctionalInterface
+public interface LongObjPredicate<T> {
+ /**
+ * Evaluates this predicate on the given arguments.
+ *
+ * @param value the first input argument
+ * @param t the second input argument
+ * @return {@code true} if the input arguments match the predicate,
+ * otherwise {@code false}
+ */
+ boolean test(long value, T t);
+}
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 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_os_storage_StorageManager.cpp b/core/jni/android_os_storage_StorageManager.cpp
index aee6733..fd3e66b 100644
--- a/core/jni/android_os_storage_StorageManager.cpp
+++ b/core/jni/android_os_storage_StorageManager.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "StorageManager"
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <fcntl.h>
@@ -25,11 +26,30 @@
namespace android {
+static const char* kProcFilesystems = "/proc/filesystems";
+
+// Checks whether the passed in filesystem is listed in /proc/filesystems
+static bool IsFilesystemSupported(const std::string& fsType) {
+ std::string supported;
+ if (!android::base::ReadFileToString(kProcFilesystems, &supported)) {
+ PLOG(ERROR) << "Failed to read supported filesystems";
+ return false;
+ }
+ return supported.find(fsType + "\n") != std::string::npos;
+}
+
jboolean android_os_storage_StorageManager_setQuotaProjectId(JNIEnv* env, jobject self,
jstring path, jlong projectId) {
struct fsxattr fsx;
ScopedUtfChars utf_chars_path(env, path);
+ static bool sdcardFsSupported = IsFilesystemSupported("sdcardfs");
+ if (sdcardFsSupported) {
+ // sdcardfs doesn't support project ID quota tracking and takes care of quota
+ // in a different way.
+ return JNI_TRUE;
+ }
+
if (projectId > UINT32_MAX) {
LOG(ERROR) << "Invalid project id: " << projectId;
return JNI_FALSE;
diff --git a/core/jni/android_view_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 3f81b11..a9ef257 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -37,6 +37,7 @@
#include <stdio.h>
#include <system/graphics.h>
#include <ui/ConfigStoreTypes.h>
+#include <ui/DeviceProductInfo.h>
#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <ui/DisplayedFrameStats.h>
@@ -65,9 +66,19 @@
static struct {
jclass clazz;
jmethodID ctor;
+} gIntegerClassInfo;
+
+static jobject toInteger(JNIEnv* env, int32_t i) {
+ return env->NewObject(gIntegerClassInfo.clazz, gIntegerClassInfo.ctor, i);
+}
+
+static struct {
+ jclass clazz;
+ jmethodID ctor;
jfieldID isInternal;
jfieldID density;
jfieldID secure;
+ jfieldID deviceProductInfo;
} gDisplayInfoClassInfo;
static struct {
@@ -111,6 +122,16 @@
static struct {
jclass clazz;
+ jmethodID ctor;
+} gDeviceProductInfoClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+} gDeviceProductInfoManufactureDateClassInfo;
+
+static struct {
+ jclass clazz;
jmethodID builder;
} gGraphicBufferClassInfo;
@@ -592,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) {
@@ -773,6 +797,41 @@
}
}
+static jobject convertDeviceProductInfoToJavaObject(
+ JNIEnv* env, const std::optional<DeviceProductInfo>& info) {
+ using ModelYear = android::DeviceProductInfo::ModelYear;
+ using ManufactureYear = android::DeviceProductInfo::ManufactureYear;
+ using ManufactureWeekAndYear = android::DeviceProductInfo::ManufactureWeekAndYear;
+
+ if (!info) return nullptr;
+ jstring name = env->NewStringUTF(info->name.data());
+ jstring manufacturerPnpId = env->NewStringUTF(info->manufacturerPnpId.data());
+ jobject productId = env->NewStringUTF(info->productId.data());
+ const auto& date = info->manufactureOrModelDate;
+ jobject modelYear, manufactureDate;
+ if (const auto* model = std::get_if<ModelYear>(&date)) {
+ modelYear = toInteger(env, model->year);
+ manufactureDate = nullptr;
+ } else if (const auto* manufactureWeekAndYear = std::get_if<ManufactureWeekAndYear>(&date)) {
+ modelYear = nullptr;
+ manufactureDate = env->NewObject(gDeviceProductInfoManufactureDateClassInfo.clazz,
+ gDeviceProductInfoManufactureDateClassInfo.ctor,
+ toInteger(env, manufactureWeekAndYear->week),
+ toInteger(env, manufactureWeekAndYear->year));
+ } else if (const auto* manufactureYear = std::get_if<ManufactureYear>(&date)) {
+ modelYear = nullptr;
+ manufactureDate = env->NewObject(gDeviceProductInfoManufactureDateClassInfo.clazz,
+ gDeviceProductInfoManufactureDateClassInfo.ctor,
+ nullptr,
+ toInteger(env, manufactureYear->year));
+ } else {
+ LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate");
+ }
+
+ return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name,
+ manufacturerPnpId, productId, modelYear, manufactureDate);
+}
+
static jobject nativeGetDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
DisplayInfo info;
if (const auto token = ibinderForJavaObject(env, tokenObj);
@@ -785,6 +844,8 @@
info.connectionType == DisplayConnectionType::Internal);
env->SetFloatField(object, gDisplayInfoClassInfo.density, info.density);
env->SetBooleanField(object, gDisplayInfoClassInfo.secure, info.secure);
+ env->SetObjectField(object, gDisplayInfoClassInfo.deviceProductInfo,
+ convertDeviceProductInfoToJavaObject(env, info.deviceProductInfo));
return object;
}
@@ -1409,7 +1470,7 @@
(void*)nativeSetLayerStack },
{"nativeSetShadowRadius", "(JJF)V",
(void*)nativeSetShadowRadius },
- {"nativeSetFrameRate", "(JJF)V",
+ {"nativeSetFrameRate", "(JJFI)V",
(void*)nativeSetFrameRate },
{"nativeGetPhysicalDisplayIds", "()[J",
(void*)nativeGetPhysicalDisplayIds },
@@ -1527,12 +1588,19 @@
int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl",
sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
+ jclass integerClass = FindClassOrDie(env, "java/lang/Integer");
+ gIntegerClassInfo.clazz = MakeGlobalRefOrDie(env, integerClass);
+ gIntegerClassInfo.ctor = GetMethodIDOrDie(env, gIntegerClassInfo.clazz, "<init>", "(I)V");
+
jclass infoClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayInfo");
gDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, infoClazz);
gDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env, infoClazz, "<init>", "()V");
gDisplayInfoClassInfo.isInternal = GetFieldIDOrDie(env, infoClazz, "isInternal", "Z");
gDisplayInfoClassInfo.density = GetFieldIDOrDie(env, infoClazz, "density", "F");
gDisplayInfoClassInfo.secure = GetFieldIDOrDie(env, infoClazz, "secure", "Z");
+ gDisplayInfoClassInfo.deviceProductInfo =
+ GetFieldIDOrDie(env, infoClazz, "deviceProductInfo",
+ "Landroid/hardware/display/DeviceProductInfo;");
jclass configClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayConfig");
gDisplayConfigClassInfo.clazz = MakeGlobalRefOrDie(env, configClazz);
@@ -1573,6 +1641,25 @@
gHdrCapabilitiesClassInfo.ctor = GetMethodIDOrDie(env, hdrCapabilitiesClazz, "<init>",
"([IFFF)V");
+ jclass deviceProductInfoClazz =
+ FindClassOrDie(env, "android/hardware/display/DeviceProductInfo");
+ gDeviceProductInfoClassInfo.clazz = MakeGlobalRefOrDie(env, deviceProductInfoClazz);
+ gDeviceProductInfoClassInfo.ctor =
+ GetMethodIDOrDie(env, deviceProductInfoClazz, "<init>",
+ "(Ljava/lang/String;"
+ "Ljava/lang/String;"
+ "Ljava/lang/String;"
+ "Ljava/lang/Integer;"
+ "Landroid/hardware/display/DeviceProductInfo$ManufactureDate;)V");
+
+ jclass deviceProductInfoManufactureDateClazz =
+ FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate");
+ gDeviceProductInfoManufactureDateClassInfo.clazz =
+ MakeGlobalRefOrDie(env, deviceProductInfoManufactureDateClazz);
+ gDeviceProductInfoManufactureDateClassInfo.ctor =
+ GetMethodIDOrDie(env, deviceProductInfoManufactureDateClazz, "<init>",
+ "(Ljava/lang/Integer;Ljava/lang/Integer;)V");
+
jclass graphicsBufferClazz = FindClassOrDie(env, "android/graphics/GraphicBuffer");
gGraphicBufferClassInfo.clazz = MakeGlobalRefOrDie(env, graphicsBufferClazz);
gGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env, graphicsBufferClazz,
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/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index b0b9ce6f..08db454 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -275,6 +275,7 @@
optional float adjust_divider_amount = 25;
optional bool animating_bounds = 26;
optional float minimize_amount = 27;
+ optional bool created_by_organizer = 28;
}
/* represents ActivityRecordProto */
diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto
index 2de5b7f..bb654f0 100644
--- a/core/proto/android/service/graphicsstats.proto
+++ b/core/proto/android/service/graphicsstats.proto
@@ -33,8 +33,9 @@
message GraphicsStatsProto {
enum PipelineType {
- GL = 0;
- VULKAN = 1;
+ UNKNOWN = 0;
+ GL = 1;
+ VULKAN = 2;
}
option (android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 488698a..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"/>
@@ -4953,16 +4980,6 @@
<permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
android:protectionLevel="signature|appPredictor" />
- <!-- Feature Id for Country Detector. -->
- <feature android:featureId="CountryDetector" android:label="@string/country_detector"/>
- <!-- Feature Id for Location service. -->
- <feature android:featureId="LocationService" android:label="@string/location_service"/>
- <!-- Feature Id for Sensor Notification service. -->
- <feature android:featureId="SensorNotificationService"
- android:label="@string/sensor_notification_service"/>
- <!-- Feature Id for Twilight service. -->
- <feature android:featureId="TwilightService" android:label="@string/twilight_service"/>
-
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 24a21eb..c0de693 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -78,6 +78,14 @@
android:layout_height="wrap_content"
android:visibility="gone">
</TabWidget>
+ <View
+ android:id="@+id/resolver_tab_divider"
+ android:visibility="gone"
+ android:layout_alwaysShow="true"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/colorBackgroundFloating"
+ android:foreground="?attr/dividerVertical" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index b4e6286..4359b10 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -94,6 +94,13 @@
android:layout_height="wrap_content"
android:visibility="gone">
</TabWidget>
+ <View
+ android:id="@+id/resolver_tab_divider"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/colorBackgroundFloating"
+ android:foreground="?attr/dividerVertical" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
@@ -102,10 +109,7 @@
android:id="@+id/profile_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:divider="?attr/dividerVertical"
- android:footerDividersEnabled="false"
- android:headerDividersEnabled="false"
- android:dividerHeight="1dp"/>
+ android:minHeight="@dimen/resolver_empty_state_height" />
</FrameLayout>
</LinearLayout>
</TabHost>
diff --git a/core/res/res/layout/resolver_list_per_profile.xml b/core/res/res/layout/resolver_list_per_profile.xml
index d481eff..c4f9ed9 100644
--- a/core/res/res/layout/resolver_list_per_profile.xml
+++ b/core/res/res/layout/resolver_list_per_profile.xml
@@ -29,7 +29,6 @@
android:elevation="@dimen/resolver_elevation"
android:nestedScrollingEnabled="true"
android:scrollbarStyle="outsideOverlay"
- android:scrollIndicators="top|bottom"
android:divider="@null"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index b546738..72e8b0c 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -175,6 +175,14 @@
android:layout_height="wrap_content"
android:visibility="gone">
</TabWidget>
+ <View
+ android:id="@+id/resolver_tab_divider"
+ android:visibility="gone"
+ android:layout_alwaysShow="true"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/colorBackgroundFloating"
+ android:foreground="?attr/dividerVertical" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
@@ -183,10 +191,7 @@
android:id="@+id/profile_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:dividerHeight="1dp"
- android:divider="?attr/dividerVertical"
- android:footerDividersEnabled="false"
- android:headerDividersEnabled="false"/>
+ android:minHeight="@dimen/resolver_empty_state_height" />
</FrameLayout>
</LinearLayout>
</TabHost>
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 e7ad8eb..d513e2b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -421,14 +421,6 @@
[CHAR LIMIT=NONE] -->
<string name="location_changed_notification_text">Tap to see your location settings.</string>
- <!-- Feature Id for Country Detector. [CHAR LIMIT=NONE]-->
- <string name="country_detector">Country Detector</string>
- <!-- Feature Id for Location service. [CHAR LIMIT=NONE]-->
- <string name="location_service">Location Service</string>
- <!-- Feature Id for Sensor Notification service. [CHAR LIMIT=NONE]-->
- <string name="sensor_notification_service">Sensor Notification Service</string>
- <!-- Feature Id for Twilight service. [CHAR LIMIT=NONE]-->
- <string name="twilight_service">Twilight Service</string>
<!-- Factory reset warning dialog strings--> <skip />
<!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] -->
@@ -5372,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 b8dd418..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" />
@@ -3874,6 +3875,7 @@
<java-symbol type="id" name="resolver_empty_state_title" />
<java-symbol type="id" name="resolver_empty_state_subtitle" />
<java-symbol type="id" name="resolver_empty_state_button" />
+ <java-symbol type="id" name="resolver_tab_divider" />
<java-symbol type="string" name="resolver_cant_share_with_work_apps" />
<java-symbol type="string" name="resolver_cant_share_with_personal_apps" />
<java-symbol type="string" name="resolver_cant_share_cross_profile_explanation" />
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/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index ea0a0fd..37e8d59 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -244,6 +244,28 @@
}
@Test
+ public void testGetThermalHeadroom() throws Exception {
+ float headroom = mPm.getThermalHeadroom(0);
+ // If the device doesn't support thermal headroom, return early
+ if (Float.isNaN(headroom)) {
+ return;
+ }
+ assertTrue("Expected non-negative headroom", headroom >= 0.0f);
+ assertTrue("Expected reasonably small headroom", headroom < 10.0f);
+
+ // Call again immediately to ensure rate limiting works
+ headroom = mPm.getThermalHeadroom(0);
+ assertTrue("Expected NaN because of rate limiting", Float.isNaN(headroom));
+
+ // Sleep for a second before attempting to call again so as to not get rate limited
+ Thread.sleep(1000);
+ headroom = mPm.getThermalHeadroom(5);
+ assertFalse("Expected data to still be available", Float.isNaN(headroom));
+ assertTrue("Expected non-negative headroom", headroom >= 0.0f);
+ assertTrue("Expected reasonably small headroom", headroom < 10.0f);
+ }
+
+ @Test
public void testUserspaceRebootNotSupported_throwsUnsupportedOperationException() {
// Can't use assumption framework with AndroidTestCase :(
if (mPm.isRebootingUserspaceSupported()) {
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/util/LongSparseArrayTest.java b/core/tests/coretests/src/android/util/LongSparseArrayTest.java
new file mode 100644
index 0000000..bf3f0f5
--- /dev/null
+++ b/core/tests/coretests/src/android/util/LongSparseArrayTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.function.LongObjPredicate;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link LongSparseArray}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LongSparseArrayTest {
+ @Test
+ public void testRemoveIf() {
+ final LongSparseArray<Integer> sparseArray = new LongSparseArray();
+ for (int i = 0; i < 10; ++i) {
+ for (int j = 100; j < 110; ++j) {
+ sparseArray.put(i, j);
+ sparseArray.put(-i, j);
+ sparseArray.put(j, -i);
+ sparseArray.put(-j, -i);
+ }
+ }
+
+ final LongObjPredicate<Integer> predicate = (value, obj) -> (value < 0 && obj < 0);
+ sparseArray.removeIf(predicate);
+
+ for (int i = 0; i < sparseArray.size(); ++i) {
+ assertThat(predicate.test(sparseArray.keyAt(i), sparseArray.valueAt(i)))
+ .isFalse();
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/CutoutSpecificationTest.java b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
index 1f831bb..7872810 100644
--- a/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
+++ b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
@@ -21,10 +21,27 @@
import static org.testng.Assert.assertThrows;
import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+/**
+ * Tests for {@link CutoutSpecification} used by {@link DisplayCutout}.
+ *
+ * <p>Build/Install/Run:
+ * atest FrameworksCoreTests:CutoutSpecificationTest
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
public class CutoutSpecificationTest {
private static final String WITHOUT_BIND_CUTOUT_SPECIFICATION = "M 0,0\n"
+ "h 48\n"
@@ -69,6 +86,13 @@
+ "z\n"
+ "@right\n"
+ "@bind_right_cutout\n"
+ + "@bottom\n"
+ + "M 0,0\n"
+ + "h -24\n"
+ + "v -48\n"
+ + "h 48\n"
+ + "v 48\n"
+ + "z\n"
+ "@dp";
private static final String CORNER_CUTOUT_SPECIFICATION = "M 0,0\n"
+ "h 1\n"
@@ -141,13 +165,66 @@
}
@Test
+ public void parse_withBindMarker_shouldHaveTopBound() {
+ CutoutSpecification cutoutSpecification = mParser.parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getTopBound()).isEqualTo(new Rect(0, 0, 168, 168));
+ }
+
+ @Test
public void parse_withBindMarker_shouldHaveRightBound() {
CutoutSpecification cutoutSpecification = mParser.parse(WITH_BIND_CUTOUT_SPECIFICATION);
assertThat(cutoutSpecification.getRightBound()).isEqualTo(new Rect(912, 960, 1080, 1128));
}
@Test
- public void parse_tallCutout_shouldBeDone() {
+ public void parse_withBindMarker_shouldHaveBottomBound() {
+ CutoutSpecification cutoutSpecification = mParser.parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getBottomBound()).isEqualTo(new Rect(456, 1752, 624, 1920));
+ }
+
+ @Test
+ public void parse_withBindMarker_shouldMatchExpectedSafeInset() {
+ CutoutSpecification cutoutSpecification = mParser.parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getSafeInset()).isEqualTo(new Rect(168, 168, 168, 168));
+ }
+
+ @Test
+ public void parse_withBindMarker_tabletLikeDevice_shouldHaveLeftBound() {
+ CutoutSpecification cutoutSpecification = new CutoutSpecification.Parser(3.5f, 1920, 1080)
+ .parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getLeftBound()).isEqualTo(new Rect(0, 540, 168, 708));
+ }
+
+ @Test
+ public void parse_withBindMarker_tabletLikeDevice_shouldHaveTopBound() {
+ CutoutSpecification cutoutSpecification = new CutoutSpecification.Parser(3.5f, 1920, 1080)
+ .parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getTopBound()).isEqualTo(new Rect(0, 0, 168, 168));
+ }
+
+ @Test
+ public void parse_withBindMarker_tabletLikeDevice_shouldHaveRightBound() {
+ CutoutSpecification cutoutSpecification = new CutoutSpecification.Parser(3.5f, 1920, 1080)
+ .parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getRightBound()).isEqualTo(new Rect(1752, 540, 1920, 708));
+ }
+
+ @Test
+ public void parse_withBindMarker_tabletLikeDevice_shouldHaveBottomBound() {
+ CutoutSpecification cutoutSpecification = new CutoutSpecification.Parser(3.5f, 1920, 1080)
+ .parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getBottomBound()).isEqualTo(new Rect(876, 912, 1044, 1080));
+ }
+
+ @Test
+ public void parse_withBindMarker_tabletLikeDevice_shouldMatchExpectedSafeInset() {
+ CutoutSpecification cutoutSpecification = new CutoutSpecification.Parser(3.5f, 1920, 1080)
+ .parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getSafeInset()).isEqualTo(new Rect(168, 0, 168, 168));
+ }
+
+ @Test
+ public void parse_tallCutout_topBoundShouldMatchExpectedHeight() {
CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ "L -48, 0\n"
+ "L -44.3940446283, 36.0595537175\n"
@@ -162,7 +239,7 @@
}
@Test
- public void parse_wideCutout_shouldBeDone() {
+ public void parse_wideCutout_topBoundShouldMatchExpectedWidth() {
CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ "L -72, 0\n"
+ "L -69.9940446283, 20.0595537175\n"
@@ -177,7 +254,7 @@
}
@Test
- public void parse_narrowCutout_shouldBeDone() {
+ public void parse_narrowCutout_topBoundShouldHaveExpectedWidth() {
CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ "L -24, 0\n"
+ "L -21.9940446283, 20.0595537175\n"
@@ -192,7 +269,7 @@
}
@Test
- public void parse_doubleCutout_shouldBeDone() {
+ public void parse_doubleCutout_topBoundShouldHaveExpectedHeight() {
CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ "L -72, 0\n"
+ "L -69.9940446283, 20.0595537175\n"
@@ -217,7 +294,7 @@
}
@Test
- public void parse_cornerCutout_shouldBeDone() {
+ public void parse_cornerCutout_topBoundShouldHaveExpectedHeight() {
CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ "L -48, 0\n"
+ "C -48,48 -48,48 0,48\n"
@@ -229,7 +306,7 @@
}
@Test
- public void parse_holeCutout_shouldBeDone() {
+ public void parse_holeCutout_shouldMatchExpectedInset() {
CutoutSpecification cutoutSpecification = mParser.parse("M 20.0,20.0\n"
+ "h 136\n"
+ "v 136\n"
@@ -259,4 +336,38 @@
assertThat(cutoutSpecification.getSafeInset())
.isEqualTo(new Rect(6, 0, 8, 0));
}
+
+ @Test
+ public void parse_bottomLeftSpec_withBindLeftMarker_shouldBeLeftBound() {
+ CutoutSpecification cutoutSpecification =
+ new CutoutSpecification.Parser(2f, 400, 200)
+ .parse("@bottom"
+ + "M 0,0\n"
+ + "v -10\n"
+ + "h 10\n"
+ + "v 10\n"
+ + "z\n"
+ + "@left\n"
+ + "@bind_left_cutout");
+
+ assertThat(cutoutSpecification.getLeftBound())
+ .isEqualTo(new Rect(0, 190, 10, 200));
+ }
+
+ @Test
+ public void parse_bottomRightSpec_withBindRightMarker_shouldBeRightBound() {
+ CutoutSpecification cutoutSpecification =
+ new CutoutSpecification.Parser(2f, 400, 200)
+ .parse("@bottom"
+ + "M 0,0\n"
+ + "v -10\n"
+ + "h -10\n"
+ + "v 10\n"
+ + "z\n"
+ + "@right\n"
+ + "@bind_right_cutout");
+
+ assertThat(cutoutSpecification.getRightBound())
+ .isEqualTo(new Rect(390, 190, 400, 200));
+ }
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index ade1e0d..79e7c50 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -46,7 +46,7 @@
// The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest:
// See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo,
// and assertAccessibilityNodeInfoCleared in that class.
- private static final int NUM_MARSHALLED_PROPERTIES = 38;
+ private static final int NUM_MARSHALLED_PROPERTIES = 39;
/**
* The number of properties that are purposely not marshalled
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index a602fa3..0a094c61d 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;
@@ -44,20 +50,24 @@
import com.google.common.base.Strings;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.atomic.AtomicLong;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class EditorCursorDragTest {
+ private static final String LOG_TAG = EditorCursorDragTest.class.getSimpleName();
+
+ private static final AtomicLong sTicker = new AtomicLong(1);
+
@Rule
public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>(
TextViewActivity.class);
- private boolean mOriginalFlagValue;
private Instrumentation mInstrumentation;
private Activity mActivity;
@@ -65,13 +75,6 @@
public void before() throws Throwable {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mActivity = mActivityRule.getActivity();
- mOriginalFlagValue = Editor.FLAG_ENABLE_CURSOR_DRAG;
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
- }
-
- @After
- public void after() throws Throwable {
- Editor.FLAG_ENABLE_CURSOR_DRAG = mOriginalFlagValue;
}
@Test
@@ -119,13 +122,11 @@
onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
- // Swipe along a diagonal path. This should drag the cursor.
- onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
- onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("2")));
-
- // Swipe along a steeper diagonal path. This should still drag the cursor.
+ // Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to
+ // the handle as the touch moves downwards (and because we have some slop to avoid jumping
+ // across lines), the cursor position will end up higher than the finger position.
onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3")));
- onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("3")));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1")));
// Swipe right-down along a very steep diagonal path. This should not drag the cursor.
// Normally this would trigger a scroll, but since the full view fits on the screen there
@@ -133,12 +134,15 @@
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 +158,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 +170,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 +392,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 +411,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 +505,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/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 0c38e71..88a6f9e 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -31,8 +31,8 @@
import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
import static android.widget.espresso.TextViewActions.doubleTapHandle;
import static android.widget.espresso.TextViewActions.dragHandle;
-import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
import static android.widget.espresso.TextViewActions.longPressAndDragHandle;
+import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
import static android.widget.espresso.TextViewActions.longPressHandle;
import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
import static android.widget.espresso.TextViewAssertions.doesNotHaveStyledText;
@@ -514,29 +514,26 @@
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
}
+ private void enableFlagsForInsertionHandleGestures() {
+ final TextView textView = mActivity.findViewById(R.id.textview);
+ final Editor editor = textView.getEditorForTesting();
+ editor.setFlagCursorDragFromAnywhereEnabled(true);
+ editor.setFlagInsertionHandleGesturesEnabled(true);
+ // Note: We don't need to reset these flags explicitly at the end of each test, because a
+ // fresh TextView and Editor will be created for each test.
+ }
+
@Test
public void testInsertionHandle_touchThrough() {
- final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
-
+ enableFlagsForInsertionHandleGestures();
testInsertionHandle();
testInsertionHandle_multiLine();
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
public void testInsertionHandle_longPressToSelect() {
- // This test only makes sense when Cursor Control flag is enabled.
+ enableFlagsForInsertionHandleGestures();
final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
final String text = "hello the world";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -546,20 +543,12 @@
onHandleView(com.android.internal.R.id.insertion_handle).perform(longPressHandle(textView));
onView(withId(R.id.textview)).check(hasSelection("world"));
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
public void testInsertionHandle_longPressAndDragToSelect() {
- // This test only makes sense when Cursor Control flag is enabled.
+ enableFlagsForInsertionHandleGestures();
final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
-
final String text = "hello the world";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -569,19 +558,12 @@
onHandleView(com.android.internal.R.id.insertion_handle)
.perform(longPressAndDragHandle(textView, Handle.INSERTION, text.indexOf('t')));
onView(withId(R.id.textview)).check(hasSelection("the world"));
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
public void testInsertionHandle_doubleTapToSelect() {
- // This test only makes sense when Cursor Control flag is enabled.
+ enableFlagsForInsertionHandleGestures();
final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
final String text = "hello the world";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -591,19 +573,12 @@
onHandleView(com.android.internal.R.id.insertion_handle).perform(doubleTapHandle(textView));
onView(withId(R.id.textview)).check(hasSelection("world"));
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
public void testInsertionHandle_doubleTapAndDragToSelect() {
- // This test only makes sense when Cursor Control flag is enabled.
+ enableFlagsForInsertionHandleGestures();
final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
final String text = "hello the world";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -614,9 +589,6 @@
onHandleView(com.android.internal.R.id.insertion_handle)
.perform(doubleTapAndDragHandle(textView, Handle.INSERTION, text.indexOf('t')));
onView(withId(R.id.textview)).check(hasSelection("the world"));
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
index 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/libs/hwui/protos/graphicsstats.proto b/libs/hwui/protos/graphicsstats.proto
index dd5676c..745393c 100644
--- a/libs/hwui/protos/graphicsstats.proto
+++ b/libs/hwui/protos/graphicsstats.proto
@@ -30,8 +30,9 @@
message GraphicsStatsProto {
enum PipelineType {
- GL = 0;
- VULKAN = 1;
+ UNKNOWN = 0;
+ GL = 1;
+ VULKAN = 2;
}
// The package name of the app
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/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index c9ac765..873d7d7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -25,8 +25,11 @@
import android.app.KeyguardManager;
import android.car.Car;
import android.car.media.CarAudioManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Color;
@@ -38,6 +41,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -171,6 +175,17 @@
mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
};
+ private final BroadcastReceiver mHomeButtonPressedBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
+ return;
+ }
+
+ dismissH(Events.DISMISS_REASON_VOLUME_CONTROLLER);
+ }
+ };
+
public CarVolumeDialogImpl(Context context) {
mContext = context;
mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
@@ -204,12 +219,18 @@
@Override
public void init(int windowType, Callback callback) {
initDialog();
+
+ mContext.registerReceiverAsUser(mHomeButtonPressedBroadcastReceiver, UserHandle.CURRENT,
+ new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), /* broadcastPermission= */
+ null, /* scheduler= */ null);
}
@Override
public void destroy() {
mHandler.removeCallbacksAndMessages(/* token= */ null);
+ mContext.unregisterReceiver(mHomeButtonPressedBroadcastReceiver);
+
cleanupAudioManager();
}
diff --git a/packages/DynamicSystemInstallationService/AndroidManifest.xml b/packages/DynamicSystemInstallationService/AndroidManifest.xml
index 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..e124be6 100644
--- a/packages/DynamicSystemInstallationService/res/values/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values/strings.xml
@@ -18,6 +18,8 @@
<string name="notification_install_inprogress">Install in progress</string>
<!-- Displayed on notification: Dynamic System installation failed [CHAR LIMIT=128] -->
<string name="notification_install_failed">Install failed</string>
+ <!-- Displayed on notification: Image validation failed [CHAR LIMIT=128] -->
+ <string name="notification_image_validation_failed">Image validation failed. Abort installation.</string>
<!-- Displayed on notification: We are running in Dynamic System [CHAR LIMIT=128] -->
<string name="notification_dynsystem_in_use">Currently running a dynamic system. Restart to use the original Android version.</string>
@@ -25,10 +27,11 @@
<string name="notification_action_cancel">Cancel</string>
<!-- Action on notification: Discard installation [CHAR LIMIT=16] -->
<string name="notification_action_discard">Discard</string>
- <!-- Action on notification: Uninstall Dynamic System [CHAR LIMIT=16] -->
- <string name="notification_action_uninstall">Uninstall</string>
<!-- Action on notification: Restart to Dynamic System [CHAR LIMIT=16] -->
<string name="notification_action_reboot_to_dynsystem">Restart</string>
+ <!-- Action on notification: Restart to original Android version [CHAR LIMIT=16] -->
+ <string name="notification_action_reboot_to_origin">Restart</string>
+
<!-- Toast when installed Dynamic System is discarded [CHAR LIMIT=64] -->
<string name="toast_dynsystem_discarded">Discarded dynamic system</string>
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 9bae223..37a77be 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);
@@ -456,14 +462,19 @@
.setStyle(new Notification.BigTextStyle().bigText(msgInUse));
builder.addAction(new Notification.Action.Builder(
- null, getString(R.string.notification_action_uninstall),
+ null, getString(R.string.notification_action_reboot_to_origin),
createPendingIntent(ACTION_REBOOT_TO_NORMAL)).build());
break;
case STATUS_NOT_STARTED:
if (cause != CAUSE_NOT_SPECIFIED && cause != CAUSE_INSTALL_CANCELLED) {
- builder.setContentText(getString(R.string.notification_install_failed));
+ if (detail instanceof InstallationAsyncTask.ImageValidationException) {
+ builder.setContentText(
+ getString(R.string.notification_image_validation_failed));
+ } else {
+ builder.setContentText(getString(R.string.notification_install_failed));
+ }
} else {
// no need to notify the user if the task is not started, or cancelled.
}
@@ -525,7 +536,7 @@
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..d25e3e2 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -886,6 +886,11 @@
<!-- UI debug setting: enable gpu debug layers summary [CHAR LIMIT=50] -->
<string name="enable_gpu_debug_layers_summary">Allow loading GPU debug layers for debug apps</string>
+ <!-- UI debug setting: enable verbose vendor logging [CHAR LIMIT=30] -->
+ <string name="enable_verbose_vendor_logging">Enable verbose vendor logging</string>
+ <!-- UI debug setting: enable verbose vendor logging summary [CHAR LIMIT=100] -->
+ <string name="enable_verbose_vendor_logging_summary">Allow additional vendor logs to be included in bug reports, may contain private information</string>
+
<!-- UI debug setting: scaling factor for window animations [CHAR LIMIT=25] -->
<string name="window_animation_scale_title">Window animation scale</string>
@@ -1260,9 +1265,12 @@
<!-- The notice header of Third-party licenses. not translatable -->
<string name="notice_header" translatable="false"></string>
- <!-- Name of the this device. [CHAR LIMIT=30] -->
- <string name="media_transfer_this_device_name">This device</string>
+ <!-- Name of the phone device. [CHAR LIMIT=30] -->
+ <string name="media_transfer_this_device_name">Phone speaker</string>
<!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
<string name="profile_connect_timeout_subtext">Problem connecting. Turn device off & back on</string>
+
+ <!-- Name of the 3.5mm audio device. [CHAR LIMIT=40] -->
+ <string name="media_transfer_wired_device_name">Wired audio device</string>
</resources>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index de174b1..e066230 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -86,7 +86,9 @@
android_library {
name: "SystemUI-tests",
- manifest: "tests/AndroidManifest.xml",
+ manifest: "tests/AndroidManifest-base.xml",
+ additional_manifests: ["tests/AndroidManifest.xml"],
+
resource_dirs: [
"tests/res",
"res-product",
diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml
index 28b2d21..a5b8cfa 100644
--- a/packages/SystemUI/res/layout/qs_carrier.xml
+++ b/packages/SystemUI/res/layout/qs_carrier.xml
@@ -14,7 +14,7 @@
~ limitations under the License
-->
-<com.android.systemui.qs.QSCarrier
+<com.android.systemui.qs.carrier.QSCarrier
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linear_carrier"
android:layout_width="wrap_content"
@@ -46,4 +46,4 @@
android:singleLine="true"
android:maxEms="7"/>
-</com.android.systemui.qs.QSCarrier>
\ No newline at end of file
+</com.android.systemui.qs.carrier.QSCarrier>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_carrier_group.xml b/packages/SystemUI/res/layout/qs_carrier_group.xml
index f2b0606..fd53a8b 100644
--- a/packages/SystemUI/res/layout/qs_carrier_group.xml
+++ b/packages/SystemUI/res/layout/qs_carrier_group.xml
@@ -15,7 +15,7 @@
-->
<!-- Extends LinearLayout -->
-<com.android.systemui.qs.QSCarrierGroup
+<com.android.systemui.qs.carrier.QSCarrierGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/qs_mobile"
android:layout_width="0dp"
@@ -71,4 +71,4 @@
android:layout_weight="1"
android:visibility="gone"/>
-</com.android.systemui.qs.QSCarrierGroup>
\ No newline at end of file
+</com.android.systemui.qs.carrier.QSCarrierGroup>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 2d288ff..b1d39f5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -123,4 +123,9 @@
*/
void handleImageAsScreenshot(in Bitmap screenImage, in Rect locationInScreen,
in Insets visibleInsets, int taskId) = 21;
+
+ /**
+ * Sets the split-screen divider minimized state
+ */
+ void setSplitScreenMinimized(boolean minimized) = 22;
}
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/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index d317b7e..69bc259 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -60,6 +60,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
+import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.NotificationListener;
@@ -327,6 +328,7 @@
@Inject Lazy<DisplayImeController> mDisplayImeController;
@Inject Lazy<RecordingController> mRecordingController;
@Inject Lazy<ProtoTracer> mProtoTracer;
+ @Inject Lazy<Divider> mDivider;
@Inject
public Dependency() {
@@ -527,6 +529,7 @@
mProviders.put(AutoHideController.class, mAutoHideController::get);
mProviders.put(RecordingController.class, mRecordingController::get);
+ mProviders.put(Divider.class, mDivider::get);
sDependency = this;
}
diff --git a/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java b/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
deleted file mode 100644
index 5c0df17..0000000
--- a/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 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;
-
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.IDockedStackListener;
-import android.view.WindowManagerGlobal;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.function.Consumer;
-
-/**
- * Utility wrapper to listen for whether or not a docked stack exists, to be
- * used for things like the different overview icon in that mode.
- */
-public class DockedStackExistsListener {
-
- private static final String TAG = "DockedStackExistsListener";
-
- private static ArrayList<WeakReference<Consumer<Boolean>>> sCallbacks = new ArrayList<>();
- private static boolean mLastExists;
-
- static {
- try {
- WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
- new IDockedStackListener.Stub() {
- @Override
- public void onDividerVisibilityChanged(boolean b) throws RemoteException {
-
- }
-
- @Override
- public void onDockedStackExistsChanged(boolean exists)
- throws RemoteException {
- DockedStackExistsListener.onDockedStackExistsChanged(exists);
- }
-
- @Override
- public void onDockedStackMinimizedChanged(boolean b, long l, boolean b1)
- throws RemoteException {
-
- }
-
- @Override
- public void onAdjustedForImeChanged(boolean b, long l)
- throws RemoteException {
-
- }
-
- @Override
- public void onDockSideChanged(int i) throws RemoteException {
-
- }
- });
- } catch (RemoteException e) {
- Log.e(TAG, "Failed registering docked stack exists listener", e);
- }
- }
-
-
- private static void onDockedStackExistsChanged(boolean exists) {
- mLastExists = exists;
- synchronized (sCallbacks) {
- sCallbacks.removeIf(wf -> {
- Consumer<Boolean> l = wf.get();
- if (l != null) l.accept(exists);
- return l == null;
- });
- }
- }
-
- public static void register(Consumer<Boolean> callback) {
- callback.accept(mLastExists);
- synchronized (sCallbacks) {
- sCallbacks.add(new WeakReference<>(callback));
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index c9104dc..6ce6353 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -96,6 +96,7 @@
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
private static final boolean VERBOSE = false;
+ private static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
private DisplayManager mDisplayManager;
private boolean mIsRegistered;
@@ -454,6 +455,9 @@
private void updateColorInversion(int colorsInvertedValue) {
int tint = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK;
+ if (DEBUG_COLOR) {
+ tint = Color.RED;
+ }
ColorStateList tintList = ColorStateList.valueOf(tint);
if (mOverlays == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/TransactionPool.java b/packages/SystemUI/src/com/android/systemui/TransactionPool.java
new file mode 100644
index 0000000..801cf8a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/TransactionPool.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+import android.util.Pools;
+import android.view.SurfaceControl;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Provides a synchronized pool of {@link SurfaceControl.Transaction}s to minimize allocations.
+ */
+@Singleton
+public class TransactionPool {
+ private final Pools.SynchronizedPool<SurfaceControl.Transaction> mTransactionPool =
+ new Pools.SynchronizedPool<>(4);
+
+ @Inject
+ TransactionPool() {
+ }
+
+ /** Gets a transaction from the pool. */
+ public SurfaceControl.Transaction acquire() {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (t == null) {
+ return new SurfaceControl.Transaction();
+ }
+ return t;
+ }
+
+ /**
+ * Return a transaction to the pool. DO NOT call {@link SurfaceControl.Transaction#close()} if
+ * returning to pool.
+ */
+ public void release(SurfaceControl.Transaction t) {
+ if (!mTransactionPool.release(t)) {
+ t.close();
+ }
+ }
+}
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/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 019cb14..17aaff1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -25,10 +25,13 @@
import android.content.res.Configuration;
import android.graphics.drawable.Animatable;
import android.util.AttributeSet;
+import android.util.Pair;
import android.util.SparseArray;
+import android.view.DisplayCutout;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
+import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -42,6 +45,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.StatusBarWindowView;
public class QSDetail extends LinearLayout {
@@ -274,6 +278,32 @@
}
}
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ DisplayCutout cutout = insets.getDisplayCutout();
+
+ Pair<Integer, Integer> padding = StatusBarWindowView.cornerCutoutMargins(
+ cutout, getDisplay());
+
+ if (padding == null) {
+ mQsDetailHeader.setPaddingRelative(
+ getResources().getDimensionPixelSize(R.dimen.qs_detail_header_padding),
+ getPaddingTop(),
+ getResources().getDimensionPixelSize(R.dimen.qs_detail_header_padding),
+ getPaddingBottom()
+ );
+ } else {
+ mQsDetailHeader.setPadding(
+ padding.first,
+ getPaddingTop(),
+ padding.second,
+ getPaddingBottom()
+ );
+ }
+
+ return super.onApplyWindowInsets(insets);
+ }
+
private void handleToggleStateChanged(boolean state, boolean toggleEnabled) {
mSwitchState = state;
if (mAnimatingOpen) {
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/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 8cd70cf..d422dd7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -60,6 +60,7 @@
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.qs.QSDetail.Callback;
+import com.android.systemui.qs.carrier.QSCarrierGroup;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
@@ -435,23 +436,22 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ // Handle padding of SystemIconsView
DisplayCutout cutout = insets.getDisplayCutout();
-
- // Handle padding of QuickStatusBarHeader
Pair<Integer, Integer> cornerCutoutPadding = StatusBarWindowView.cornerCutoutMargins(
cutout, getDisplay());
Pair<Integer, Integer> padding =
StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
cutout, cornerCutoutPadding, mRoundedCornerPadding);
- setPadding(padding.first, 0, padding.second, getPaddingBottom());
-
- // Handle padding of SystemIconsView
final int waterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
- mSystemIconsView.setPaddingRelative(
- getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start),
- waterfallTopInset,
- getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end),
- 0);
+ int statusBarPaddingLeft = isLayoutRtl()
+ ? getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end)
+ : getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start);
+ int statusBarPaddingRight = isLayoutRtl()
+ ? getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start)
+ : getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end);
+ mSystemIconsView.setPadding(padding.first + statusBarPaddingLeft, waterfallTopInset,
+ padding.second + statusBarPaddingRight, 0);
return super.onApplyWindowInsets(insets);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 867677a..d899acb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs;
import com.android.systemui.R;
+import com.android.systemui.qs.carrier.QSCarrierGroupController;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt b/packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt
new file mode 100644
index 0000000..663f3f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.carrier
+
+/**
+ * Represents the state of cell signal for a particular slot.
+ *
+ * To be used between [QSCarrierGroupController] and [QSCarrier].
+ */
+data class CellSignalState(
+ @JvmField val visible: Boolean = false,
+ @JvmField val mobileSignalIconId: Int = 0,
+ @JvmField val contentDescription: String? = null,
+ @JvmField val typeContentDescription: String? = null,
+ @JvmField val roaming: Boolean = false
+) {
+ /**
+ * Changes the visibility of this state by returning a copy with the visibility changed.
+ *
+ * If the visibility would not change, the same state is returned.
+ *
+ * @param visible the new visibility state
+ * @return `this` if `this.visible == visible`. Else, a new copy with the visibility changed.
+ */
+ fun changeVisibility(visible: Boolean): CellSignalState {
+ if (this.visible == visible) return this
+ else return copy(visible = visible)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
rename to packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
index 5a9c360..ad275f1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.qs;
+package com.android.systemui.qs.carrier;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -29,6 +29,7 @@
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
+import com.android.systemui.qs.QuickStatusBarHeader;
import java.util.Objects;
@@ -41,7 +42,7 @@
private DualToneHandler mDualToneHandler;
private ColorStateList mColorForegroundStateList;
private float mColorForegroundIntensity;
- private QSCarrierGroupController.CellSignalState mLastSignalState;
+ private CellSignalState mLastSignalState;
public QSCarrier(Context context) {
super(context);
@@ -76,8 +77,13 @@
mColorForegroundIntensity = QuickStatusBarHeader.getColorIntensity(colorForeground);
}
- public void updateState(QSCarrierGroupController.CellSignalState state) {
- if (Objects.equals(state, mLastSignalState)) return;
+ /**
+ * Update the state of this view
+ * @param state the current state of the signal for this view
+ * @return true if the state was actually changed
+ */
+ public boolean updateState(CellSignalState state) {
+ if (Objects.equals(state, mLastSignalState)) return false;
mLastSignalState = state;
mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
if (state.visible) {
@@ -103,6 +109,7 @@
}
mMobileSignal.setContentDescription(contentDescription);
}
+ return true;
}
private boolean hasValidTypeContentDescription(String typeContentDescription) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
rename to packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.java
index 346c75d..d03563f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.qs;
+package com.android.systemui.qs.carrier;
import android.content.Context;
import android.util.AttributeSet;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java
rename to packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index eb5b4cc..f9b1473 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.qs;
+package com.android.systemui.qs.carrier;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
@@ -29,7 +29,6 @@
import android.view.View;
import android.widget.TextView;
-import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.keyguard.CarrierTextController;
@@ -38,7 +37,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.NetworkController;
-import java.util.Objects;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -82,11 +80,13 @@
Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
return;
}
- mInfos[slotIndex].visible = statusIcon.visible;
- mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
- mInfos[slotIndex].contentDescription = statusIcon.contentDescription;
- mInfos[slotIndex].typeContentDescription = typeContentDescription.toString();
- mInfos[slotIndex].roaming = roaming;
+ mInfos[slotIndex] = new CellSignalState(
+ statusIcon.visible,
+ statusIcon.icon,
+ statusIcon.contentDescription,
+ typeContentDescription.toString(),
+ roaming
+ );
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
}
@@ -94,7 +94,7 @@
public void setNoSims(boolean hasNoSims, boolean simDetected) {
if (hasNoSims) {
for (int i = 0; i < SIM_SLOTS; i++) {
- mInfos[i].visible = false;
+ mInfos[i] = mInfos[i].changeVisibility(false);
}
}
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
@@ -236,7 +236,7 @@
+ info.subscriptionIds[i]);
continue;
}
- mInfos[slot].visible = true;
+ mInfos[slot] = mInfos[slot].changeVisibility(true);
slotSeen[slot] = true;
mCarrierGroups[slot].setCarrierText(
info.listOfCarriers[i].toString().trim());
@@ -244,7 +244,7 @@
}
for (int i = 0; i < SIM_SLOTS; i++) {
if (!slotSeen[i]) {
- mInfos[i].visible = false;
+ mInfos[i] = mInfos[i].changeVisibility(false);
mCarrierGroups[i].setVisibility(View.GONE);
}
}
@@ -255,7 +255,7 @@
// No sims or airplane mode (but not WFC). Do not show QSCarrierGroup, instead just show
// info.carrierText in a different view.
for (int i = 0; i < SIM_SLOTS; i++) {
- mInfos[i].visible = false;
+ mInfos[i] = mInfos[i].changeVisibility(false);
mCarrierGroups[i].setCarrierText("");
mCarrierGroups[i].setVisibility(View.GONE);
}
@@ -295,35 +295,6 @@
}
}
- static final class CellSignalState {
- boolean visible;
- int mobileSignalIconId;
- String contentDescription;
- String typeContentDescription;
- boolean roaming;
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) return true;
- if (!(obj instanceof CellSignalState)) return false;
- CellSignalState other = (CellSignalState) obj;
- return this.visible == other.visible
- && this.mobileSignalIconId == other.mobileSignalIconId
- && Objects.equals(this.contentDescription, other.contentDescription)
- && Objects.equals(this.typeContentDescription, other.typeContentDescription)
- && this.roaming == other.roaming;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(visible,
- mobileSignalIconId,
- contentDescription,
- typeContentDescription,
- roaming);
- }
- }
-
public static class Builder {
private QSCarrierGroup mView;
private final ActivityStarter mActivityStarter;
@@ -343,7 +314,7 @@
mCarrierTextControllerBuilder = carrierTextControllerBuilder;
}
- Builder setQSCarrierGroup(QSCarrierGroup view) {
+ public Builder setQSCarrierGroup(QSCarrierGroup view) {
mView = view;
return this;
}
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/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index ad49364..34cad51 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -380,6 +380,14 @@
taskId, mHandler, null);
}
+ @Override
+ public void setSplitScreenMinimized(boolean minimized) {
+ Divider divider = mDividerOptional.get();
+ if (divider != null) {
+ divider.setMinimized(minimized);
+ }
+ }
+
private boolean verifyCaller(String reason) {
final int callerId = Binder.getCallingUserHandle().getIdentifier();
if (callerId != mCurrentBoundedUserId) {
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/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 5ae0954..4f20492 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -22,10 +22,8 @@
import android.content.Context;
import android.content.res.Configuration;
import android.os.RemoteException;
-import android.util.Log;
import android.view.IWindowManager;
import android.view.KeyEvent;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.policy.DividerSnapAlgorithm;
@@ -94,29 +92,24 @@
}
private void handleDockKey(long shortcutCode) {
- try {
- int dockSide = mWindowManagerService.getDockedStackSide();
- if (dockSide == WindowManager.DOCKED_INVALID) {
- // Split the screen
- mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
- ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
- : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
- } else {
- // If there is already a docked window, we respond by resizing the docking pane.
- DividerView dividerView = mDivider.getView();
- DividerSnapAlgorithm snapAlgorithm = dividerView.getSnapAlgorithm();
- int dividerPosition = dividerView.getCurrentPosition();
- DividerSnapAlgorithm.SnapTarget currentTarget =
- snapAlgorithm.calculateNonDismissingSnapTarget(dividerPosition);
- DividerSnapAlgorithm.SnapTarget target = (shortcutCode == SC_DOCK_LEFT)
- ? snapAlgorithm.getPreviousTarget(currentTarget)
- : snapAlgorithm.getNextTarget(currentTarget);
- dividerView.startDragging(true /* animate */, false /* touching */);
- dividerView.stopDragging(target.position, 0f, false /* avoidDismissStart */,
- true /* logMetrics */);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "handleDockKey() failed.");
+ if (mDivider == null || !mDivider.inSplitMode()) {
+ // Split the screen
+ mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
+ ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+ : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
+ } else {
+ // If there is already a docked window, we respond by resizing the docking pane.
+ DividerView dividerView = mDivider.getView();
+ DividerSnapAlgorithm snapAlgorithm = dividerView.getSnapAlgorithm();
+ int dividerPosition = dividerView.getCurrentPosition();
+ DividerSnapAlgorithm.SnapTarget currentTarget =
+ snapAlgorithm.calculateNonDismissingSnapTarget(dividerPosition);
+ DividerSnapAlgorithm.SnapTarget target = (shortcutCode == SC_DOCK_LEFT)
+ ? snapAlgorithm.getPreviousTarget(currentTarget)
+ : snapAlgorithm.getNextTarget(currentTarget);
+ dividerView.startDragging(true /* animate */, false /* touching */);
+ dividerView.stopDragging(target.position, 0f, false /* avoidDismissStart */,
+ true /* logMetrics */);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 90cc0e57..56cdff4 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -17,69 +17,284 @@
package com.android.systemui.stackdivider;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.Display.DEFAULT_DISPLAY;
+import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Handler;
import android.os.RemoteException;
+import android.provider.Settings;
import android.util.Log;
-import android.view.IDockedStackListener;
+import android.util.Slog;
+import android.view.IWindowContainer;
import android.view.LayoutInflater;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.view.View;
-import android.view.WindowManagerGlobal;
+import android.view.WindowContainerTransaction;
+import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
+import com.android.systemui.TransactionPool;
import com.android.systemui.recents.Recents;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.wm.DisplayChangeController;
+import com.android.systemui.wm.DisplayController;
+import com.android.systemui.wm.DisplayImeController;
+import com.android.systemui.wm.DisplayLayout;
+import com.android.systemui.wm.SystemWindows;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.Optional;
+import java.util.function.Consumer;
+
+import javax.inject.Singleton;
import dagger.Lazy;
/**
* Controls the docked stack divider.
*/
-public class Divider extends SystemUI implements DividerView.DividerCallbacks {
+@Singleton
+public class Divider extends SystemUI implements DividerView.DividerCallbacks,
+ DisplayController.OnDisplaysChangedListener {
private static final String TAG = "Divider";
+
+ static final boolean DEBUG = true;
+
+ static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+
private final Optional<Lazy<Recents>> mRecentsOptionalLazy;
private DividerWindowManager mWindowManager;
private DividerView mView;
private final DividerState mDividerState = new DividerState();
- private DockDividerVisibilityListener mDockDividerVisibilityListener;
private boolean mVisible = false;
private boolean mMinimized = false;
private boolean mAdjustedForIme = false;
private boolean mHomeStackResizable = false;
private ForcedResizableInfoActivityController mForcedResizableController;
+ private SystemWindows mSystemWindows;
+ final SurfaceSession mSurfaceSession = new SurfaceSession();
+ private DisplayController mDisplayController;
+ private DisplayImeController mImeController;
+ final TransactionPool mTransactionPool;
- public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy) {
+ // Keeps track of real-time split geometry including snap positions and ime adjustments
+ private SplitDisplayLayout mSplitLayout;
+
+ // Transient: this contains the layout calculated for a new rotation requested by WM. This is
+ // kept around so that we can wait for a matching configuration change and then use the exact
+ // layout that we sent back to WM.
+ private SplitDisplayLayout mRotateSplitLayout;
+
+ private Handler mHandler;
+ private KeyguardStateController mKeyguardStateController;
+
+ private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
+ new ArrayList<>();
+
+ private SplitScreenTaskOrganizer mSplits = new SplitScreenTaskOrganizer(this);
+
+ private DisplayChangeController.OnDisplayChangingListener mRotationController =
+ (display, fromRotation, toRotation, t) -> {
+ DisplayLayout displayLayout =
+ new DisplayLayout(mDisplayController.getDisplayLayout(display));
+ SplitDisplayLayout sdl = new SplitDisplayLayout(mContext, displayLayout, mSplits);
+ sdl.rotateTo(toRotation);
+ mRotateSplitLayout = sdl;
+ int position = mMinimized ? mView.mSnapTargetBeforeMinimized.position
+ : mView.getCurrentPosition();
+ DividerSnapAlgorithm snap = sdl.getSnapAlgorithm();
+ final DividerSnapAlgorithm.SnapTarget target =
+ snap.calculateNonDismissingSnapTarget(position);
+ sdl.resizeSplits(target.position, t);
+
+ if (inSplitMode()) {
+ WindowManagerProxy.applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
+ }
+ };
+
+ private IWindowContainer mLastImeTarget = null;
+ private boolean mShouldAdjustForIme = false;
+
+ private DisplayImeController.ImePositionProcessor mImePositionProcessor =
+ new DisplayImeController.ImePositionProcessor() {
+ private int mStartTop = 0;
+ private int mFinalTop = 0;
+ @Override
+ public void onImeStartPositioning(int displayId, int imeTop, int finalImeTop,
+ boolean showing, SurfaceControl.Transaction t) {
+ mStartTop = imeTop;
+ mFinalTop = finalImeTop;
+ if (showing) {
+ try {
+ mLastImeTarget = ActivityTaskManager.getTaskOrganizerController()
+ .getImeTarget(displayId);
+ mShouldAdjustForIme = mLastImeTarget != null
+ && !mSplitLayout.mDisplayLayout.isLandscape()
+ && (mLastImeTarget.asBinder()
+ == mSplits.mSecondary.token.asBinder());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to get IME target", e);
+ }
+ }
+ if (!mShouldAdjustForIme) {
+ setAdjustedForIme(false);
+ return;
+ }
+ mView.setAdjustedForIme(showing, showing
+ ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
+ : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
+ // Reposition the server's secondary split position so that it evaluates
+ // insets properly.
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (showing) {
+ mSplitLayout.updateAdjustedBounds(finalImeTop, imeTop, finalImeTop);
+ wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
+ } else {
+ wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
+ }
+ try {
+ ActivityTaskManager.getTaskOrganizerController()
+ .applyContainerTransaction(wct, null /* organizer */);
+ } catch (RemoteException e) {
+ }
+ setAdjustedForIme(showing);
+ }
+
+ @Override
+ public void onImePositionChanged(int displayId, int imeTop,
+ SurfaceControl.Transaction t) {
+ if (!mShouldAdjustForIme) {
+ return;
+ }
+ mSplitLayout.updateAdjustedBounds(imeTop, mStartTop, mFinalTop);
+ mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
+ mSplitLayout.mAdjustedSecondary);
+ final boolean showing = mFinalTop < mStartTop;
+ final float progress = ((float) (imeTop - mStartTop)) / (mFinalTop - mStartTop);
+ final float fraction = showing ? progress : 1.f - progress;
+ mView.setResizeDimLayer(t, true /* primary */, fraction * 0.3f);
+ }
+
+ @Override
+ public void onImeEndPositioning(int displayId, int imeTop,
+ boolean showing, SurfaceControl.Transaction t) {
+ if (!mShouldAdjustForIme) {
+ return;
+ }
+ mSplitLayout.updateAdjustedBounds(imeTop, mStartTop, mFinalTop);
+ mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
+ mSplitLayout.mAdjustedSecondary);
+ mView.setResizeDimLayer(t, true /* primary */, showing ? 0.3f : 0.f);
+ }
+ };
+
+ public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
+ DisplayController displayController, SystemWindows systemWindows,
+ DisplayImeController imeController, Handler handler,
+ KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
super(context);
+ mDisplayController = displayController;
+ mSystemWindows = systemWindows;
+ mImeController = imeController;
+ mHandler = handler;
+ mKeyguardStateController = keyguardStateController;
mRecentsOptionalLazy = recentsOptionalLazy;
+ mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
+ mTransactionPool = transactionPool;
}
@Override
public void start() {
- mWindowManager = new DividerWindowManager(mContext);
- update(mContext.getResources().getConfiguration());
- mDockDividerVisibilityListener = new DockDividerVisibilityListener();
- try {
- WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
- mDockDividerVisibilityListener);
- } catch (Exception e) {
- Log.e(TAG, "Failed to register docked stack listener", e);
- }
- mForcedResizableController = new ForcedResizableInfoActivityController(mContext);
+ mWindowManager = new DividerWindowManager(mSystemWindows);
+ mDisplayController.addDisplayWindowListener(this);
+ // Hide the divider when keyguard is showing. Even though keyguard/statusbar is above
+ // everything, it is actually transparent except for notifications, so we still need to
+ // hide any surfaces that are below it.
+ // TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
+ mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
+ @Override
+ public void onUnlockedChanged() {
+
+ }
+
+ @Override
+ public void onKeyguardShowingChanged() {
+ if (!inSplitMode() || mView == null) {
+ return;
+ }
+ mView.setHidden(mKeyguardStateController.isShowing());
+ }
+
+ @Override
+ public void onKeyguardFadingAwayChanged() {
+
+ }
+ });
+ // Don't initialize the divider or anything until we get the default display.
}
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
+ public void onDisplayAdded(int displayId) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+ mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
+ mDisplayController.getDisplayLayout(displayId), mSplits);
+ mImeController.addPositionProcessor(mImePositionProcessor);
+ mDisplayController.addDisplayChangingController(mRotationController);
+ try {
+ mSplits.init(ActivityTaskManager.getTaskOrganizerController(), mSurfaceSession);
+ // Set starting tile bounds based on middle target
+ final WindowContainerTransaction tct = new WindowContainerTransaction();
+ int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
+ mSplitLayout.resizeSplits(midPos, tct);
+ ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(tct,
+ null /* organizer */);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to register docked stack listener", e);
+ }
+ update(mDisplayController.getDisplayContext(displayId).getResources().getConfiguration());
+ }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+ mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
+ mDisplayController.getDisplayLayout(displayId), mSplits);
+ if (mRotateSplitLayout == null) {
+ int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
+ final WindowContainerTransaction tct = new WindowContainerTransaction();
+ mSplitLayout.resizeSplits(midPos, tct);
+ try {
+ ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(tct,
+ null /* organizer */);
+ } catch (RemoteException e) {
+ }
+ } else if (mRotateSplitLayout != null
+ && mSplitLayout.mDisplayLayout.rotation()
+ == mRotateSplitLayout.mDisplayLayout.rotation()) {
+ mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary);
+ mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
+ mRotateSplitLayout = null;
+ }
update(newConfig);
}
+ Handler getHandler() {
+ return mHandler;
+ }
+
public DividerView getView() {
return mView;
}
@@ -92,18 +307,25 @@
return mHomeStackResizable;
}
+ /** {@code true} if this is visible */
+ public boolean inSplitMode() {
+ return mView != null && mView.getVisibility() == View.VISIBLE;
+ }
+
private void addDivider(Configuration configuration) {
+ Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
mView = (DividerView)
- LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
- mView.injectDependencies(mWindowManager, mDividerState, this);
+ LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
+ DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
+ mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout);
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
- final int size = mContext.getResources().getDimensionPixelSize(
+ final int size = dctx.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
- final int width = landscape ? size : MATCH_PARENT;
- final int height = landscape ? MATCH_PARENT : size;
- mWindowManager.add(mView, width, height);
+ final int width = landscape ? size : displayLayout.width();
+ final int height = landscape ? displayLayout.height() : size;
+ mWindowManager.add(mView, width, height, mContext.getDisplayId());
}
private void removeDivider() {
@@ -116,65 +338,86 @@
private void update(Configuration configuration) {
removeDivider();
addDivider(configuration);
- if (mMinimized) {
+ if (mMinimized && mView != null) {
mView.setMinimizedDockStack(true, mHomeStackResizable);
updateTouchable();
}
}
- private void updateVisibility(final boolean visible) {
- mView.post(new Runnable() {
- @Override
- public void run() {
- if (mVisible != visible) {
- mVisible = visible;
- mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ void updateVisibility(final boolean visible) {
+ if (mVisible != visible) {
+ mVisible = visible;
+ mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- // Update state because animations won't finish.
- mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
- }
+ if (visible) {
+ mView.enterSplitMode(mHomeStackResizable);
+ // Update state because animations won't finish.
+ mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
+ } else {
+ mView.exitSplitMode();
+ // un-minimize so that next entry triggers minimize anim.
+ mView.setMinimizedDockStack(false /* minimized */, mHomeStackResizable);
}
- });
+ // Notify existence listeners
+ synchronized (mDockedStackExistsListeners) {
+ mDockedStackExistsListeners.removeIf(wf -> {
+ Consumer<Boolean> l = wf.get();
+ if (l != null) l.accept(visible);
+ return l == null;
+ });
+ }
+ }
+ }
+
+ private void setHomeStackResizable(boolean resizable) {
+ if (mHomeStackResizable == resizable) {
+ return;
+ }
+ mHomeStackResizable = resizable;
+ if (!inSplitMode()) {
+ return;
+ }
+ WindowManagerProxy.applyHomeTasksMinimized(mSplitLayout, mSplits.mSecondary.token);
}
private void updateMinimizedDockedStack(final boolean minimized, final long animDuration,
final boolean isHomeStackResizable) {
- mView.post(new Runnable() {
- @Override
- public void run() {
- mHomeStackResizable = isHomeStackResizable;
- if (mMinimized != minimized) {
- mMinimized = minimized;
- updateTouchable();
- if (animDuration > 0) {
- mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable);
- } else {
- mView.setMinimizedDockStack(minimized, isHomeStackResizable);
- }
- }
+ setHomeStackResizable(isHomeStackResizable);
+ if (animDuration > 0) {
+ mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable);
+ } else {
+ mView.setMinimizedDockStack(minimized, isHomeStackResizable);
+ }
+ updateTouchable();
+ }
+
+ /** Switch to minimized state if appropriate */
+ public void setMinimized(final boolean minimized) {
+ mHandler.post(() -> {
+ if (!inSplitMode()) {
+ return;
}
+ if (mMinimized == minimized) {
+ return;
+ }
+ mMinimized = minimized;
+ mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
+ updateTouchable();
});
}
- private void notifyDockedStackExistsChanged(final boolean exists) {
- mView.post(new Runnable() {
- @Override
- public void run() {
- mForcedResizableController.notifyDockedStackExistsChanged(exists);
- }
- });
+ void setAdjustedForIme(boolean adjustedForIme) {
+ if (mAdjustedForIme == adjustedForIme) {
+ return;
+ }
+ mAdjustedForIme = adjustedForIme;
+ updateTouchable();
}
private void updateTouchable() {
mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme);
}
- public void onRecentsActivityStarting() {
- if (mView != null) {
- mView.onRecentsActivityStarting();
- }
- }
-
/**
* Workaround for b/62528361, at the time recents has drawn, it may happen before a
* configuration change to the Divider, and internally, the event will be posted to the
@@ -206,6 +449,9 @@
}
public void onAppTransitionFinished() {
+ if (mView == null) {
+ return;
+ }
mForcedResizableController.onAppTransitionFinished();
}
@@ -231,46 +477,66 @@
pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme);
}
- class DockDividerVisibilityListener extends IDockedStackListener.Stub {
+ long getAnimDuration() {
+ float transitionScale = Settings.Global.getFloat(mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE,
+ mContext.getResources().getFloat(
+ com.android.internal.R.dimen
+ .config_appTransitionAnimationDurationScaleDefault));
+ final long transitionDuration = DEFAULT_APP_TRANSITION_DURATION;
+ return (long) (transitionDuration * transitionScale);
+ }
- @Override
- public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
- updateVisibility(visible);
+ /** Register a listener that gets called whenever the existence of the divider changes */
+ public void registerInSplitScreenListener(Consumer<Boolean> listener) {
+ listener.accept(inSplitMode());
+ synchronized (mDockedStackExistsListeners) {
+ mDockedStackExistsListeners.add(new WeakReference<>(listener));
}
+ }
- @Override
- public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
- notifyDockedStackExistsChanged(exists);
+ void startEnterSplit() {
+ // Set resizable directly here because applyEnterSplit already resizes home stack.
+ mHomeStackResizable = WindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
+ }
+
+ void ensureMinimizedSplit() {
+ final boolean wasMinimized = mMinimized;
+ mMinimized = true;
+ setHomeStackResizable(mSplits.mSecondary.isResizable());
+ if (!inSplitMode()) {
+ // Wasn't in split-mode yet, so enter now.
+ if (DEBUG) {
+ Log.d(TAG, " entering split mode with minimized=true");
+ }
+ updateVisibility(true /* visible */);
+ } else if (!wasMinimized) {
+ if (DEBUG) {
+ Log.d(TAG, " in split mode, but minimizing ");
+ }
+ // Was already in split-mode, update just minimized state.
+ updateMinimizedDockedStack(mMinimized, getAnimDuration(),
+ mHomeStackResizable);
}
+ }
- @Override
- public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
- boolean isHomeStackResizable) throws RemoteException {
- mHomeStackResizable = isHomeStackResizable;
- updateMinimizedDockedStack(minimized, animDuration, isHomeStackResizable);
+ void ensureNormalSplit() {
+ if (!inSplitMode()) {
+ // Wasn't in split-mode, so enter now.
+ if (DEBUG) {
+ Log.d(TAG, " enter split mode unminimized ");
+ }
+ mMinimized = false;
+ updateVisibility(true /* visible */);
}
-
- @Override
- public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
- throws RemoteException {
- mView.post(() -> {
- if (mAdjustedForIme != adjustedForIme) {
- mAdjustedForIme = adjustedForIme;
- updateTouchable();
- if (!mMinimized) {
- if (animDuration > 0) {
- mView.setAdjustedForIme(adjustedForIme, animDuration);
- } else {
- mView.setAdjustedForIme(adjustedForIme);
- }
- }
- }
- });
- }
-
- @Override
- public void onDockSideChanged(final int newDockSide) throws RemoteException {
- mView.post(() -> mView.notifyDockSideChanged(newDockSide));
+ if (mMinimized) {
+ // Was in minimized state, so leave that.
+ if (DEBUG) {
+ Log.d(TAG, " in split mode already, but unminimizing ");
+ }
+ mMinimized = false;
+ updateMinimizedDockedStack(mMinimized, getAnimDuration(),
+ mHomeStackResizable);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
index 49f4d5e..3b7f315 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
@@ -17,8 +17,15 @@
package com.android.systemui.stackdivider;
import android.content.Context;
+import android.os.Handler;
+import com.android.systemui.TransactionPool;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.recents.Recents;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.wm.DisplayController;
+import com.android.systemui.wm.DisplayImeController;
+import com.android.systemui.wm.SystemWindows;
import java.util.Optional;
@@ -35,7 +42,11 @@
public class DividerModule {
@Singleton
@Provides
- static Divider provideDivider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy) {
- return new Divider(context, recentsOptionalLazy);
+ static Divider provideDivider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
+ DisplayController displayController, SystemWindows systemWindows,
+ DisplayImeController imeController, @Main Handler handler,
+ KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
+ return new Divider(context, recentsOptionalLazy, displayController, systemWindows,
+ imeController, handler, keyguardStateController, transactionPool);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 9fe6e84..375d9bb 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -16,12 +16,8 @@
package com.android.systemui.stackdivider;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
-import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
@@ -40,10 +36,11 @@
import android.util.AttributeSet;
import android.view.Choreographer;
import android.view.Display;
-import android.view.DisplayInfo;
import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.PointerIcon;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnTouchListener;
@@ -75,6 +72,7 @@
*/
public class DividerView extends FrameLayout implements OnTouchListener,
OnComputeInternalInsetsListener {
+ private static final String TAG = "DividerView";
public interface DividerCallbacks {
void onDraggingStart();
@@ -123,14 +121,11 @@
private int mTouchSlop;
private boolean mBackgroundLifted;
private boolean mIsInMinimizeInteraction;
- private SnapTarget mSnapTargetBeforeMinimized;
+ SnapTarget mSnapTargetBeforeMinimized;
private int mDividerInsets;
private final Display mDefaultDisplay;
- private int mDisplayWidth;
- private int mDisplayHeight;
- private int mDisplayRotation;
- private int mDividerWindowWidth;
+
private int mDividerSize;
private int mTouchElevation;
private int mLongPressEntraceAnimDuration;
@@ -147,8 +142,7 @@
private DividerWindowManager mWindowManager;
private VelocityTracker mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
- private DividerSnapAlgorithm mSnapAlgorithm;
- private DividerSnapAlgorithm mMinimizedSnapAlgorithm;
+ private SplitDisplayLayout mSplitLayout;
private DividerCallbacks mCallback;
private final Rect mStableInsets = new Rect();
@@ -163,6 +157,10 @@
private DividerState mState;
private final SurfaceFlingerVsyncChoreographer mSfChoreographer;
+ private SplitScreenTaskOrganizer mTiles;
+ boolean mFirstLayout = true;
+ int mDividerPositionX;
+ int mDividerPositionY;
// The view is removed or in the process of been removed from the system.
private boolean mRemoved;
@@ -172,7 +170,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_RESIZE_STACK:
- resizeStack(msg.arg1, msg.arg2, (SnapTarget) msg.obj);
+ resizeStackSurfaces(msg.arg1, msg.arg2, (SnapTarget) msg.obj);
break;
default:
super.handleMessage(msg);
@@ -228,16 +226,17 @@
public boolean performAccessibilityAction(View host, int action, Bundle args) {
int currentPosition = getCurrentPosition();
SnapTarget nextTarget = null;
+ DividerSnapAlgorithm snapAlgorithm = mSplitLayout.getSnapAlgorithm();
if (action == R.id.action_move_tl_full) {
- nextTarget = mSnapAlgorithm.getDismissEndTarget();
+ nextTarget = snapAlgorithm.getDismissEndTarget();
} else if (action == R.id.action_move_tl_70) {
- nextTarget = mSnapAlgorithm.getLastSplitTarget();
+ nextTarget = snapAlgorithm.getLastSplitTarget();
} else if (action == R.id.action_move_tl_50) {
- nextTarget = mSnapAlgorithm.getMiddleTarget();
+ nextTarget = snapAlgorithm.getMiddleTarget();
} else if (action == R.id.action_move_tl_30) {
- nextTarget = mSnapAlgorithm.getFirstSplitTarget();
+ nextTarget = snapAlgorithm.getFirstSplitTarget();
} else if (action == R.id.action_move_rb_full) {
- nextTarget = mSnapAlgorithm.getDismissStartTarget();
+ nextTarget = snapAlgorithm.getDismissStartTarget();
}
if (nextTarget != null) {
startDragging(true /* animate */, false /* touching */);
@@ -284,11 +283,11 @@
mBackground = findViewById(R.id.docked_divider_background);
mMinimizedShadow = findViewById(R.id.minimized_dock_shadow);
mHandle.setOnTouchListener(this);
- mDividerWindowWidth = getResources().getDimensionPixelSize(
+ final int dividerWindowWidth = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
mDividerInsets = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_insets);
- mDividerSize = mDividerWindowWidth - 2 * mDividerInsets;
+ mDividerSize = dividerWindowWidth - 2 * mDividerInsets;
mTouchElevation = getResources().getDimensionPixelSize(
R.dimen.docked_stack_divider_lift_elevation);
mLongPressEntraceAnimDuration = getResources().getInteger(
@@ -296,7 +295,6 @@
mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.3f);
- updateDisplayInfo();
boolean landscape = getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE;
mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(),
@@ -314,6 +312,7 @@
&& !mIsInMinimizeInteraction) {
saveSnapTargetBeforeMinimized(mSnapTargetBeforeMinimized);
}
+ mFirstLayout = true;
}
void onDividerRemoved() {
@@ -341,17 +340,17 @@
|| mStableInsets.bottom != insets.getStableInsetBottom()) {
mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
insets.getStableInsetRight(), insets.getStableInsetBottom());
- if (mSnapAlgorithm != null || mMinimizedSnapAlgorithm != null) {
- mSnapAlgorithm = null;
- mMinimizedSnapAlgorithm = null;
- initializeSnapAlgorithm();
- }
}
return super.onApplyWindowInsets(insets);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mFirstLayout) {
+ // Wait for first layout so that the ViewRootImpl surface has been created.
+ initializeSurfaceState();
+ mFirstLayout = false;
+ }
super.onLayout(changed, left, top, right, bottom);
int minimizeLeft = 0;
int minimizeTop = 0;
@@ -372,19 +371,16 @@
}
public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState,
- DividerCallbacks callback) {
+ DividerCallbacks callback, SplitScreenTaskOrganizer tiles, SplitDisplayLayout sdl) {
mWindowManager = windowManager;
mState = dividerState;
mCallback = callback;
-
- // Set the previous position ratio before minimized state after attaching this divider
- if (mStableInsets.isEmpty()) {
- WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
- }
+ mTiles = tiles;
+ mSplitLayout = sdl;
if (mState.mRatioPositionBeforeMinimized == 0) {
// Set the middle target as the initial state
- mSnapTargetBeforeMinimized = mSnapAlgorithm.getMiddleTarget();
+ mSnapTargetBeforeMinimized = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
} else {
repositionSnapTargetBeforeMinimized();
}
@@ -411,18 +407,35 @@
return mOtherTaskRect;
}
+ private boolean inSplitMode() {
+ return getVisibility() == VISIBLE;
+ }
+
+ /** Unlike setVisible, this directly hides the surface without changing view visibility. */
+ void setHidden(boolean hidden) {
+ post(() -> {
+ final SurfaceControl sc = getWindowSurfaceControl();
+ if (sc == null) {
+ return;
+ }
+ Transaction t = mTiles.getTransaction();
+ if (hidden) {
+ t.hide(sc);
+ } else {
+ t.show(sc);
+ }
+ t.apply();
+ mTiles.releaseTransaction(t);
+ });
+ }
+
public boolean startDragging(boolean animate, boolean touching) {
cancelFlingAnimation();
if (touching) {
mHandle.setTouching(true, animate);
}
- mDockSide = mWindowManagerProxy.getDockSide();
+ mDockSide = mSplitLayout.getPrimarySplitSide();
- // Update snap algorithm if rotation has occurred
- if (mDisplayRotation != mDefaultDisplay.getRotation()) {
- updateDisplayInfo();
- }
- initializeSnapAlgorithm();
mWindowManagerProxy.setResizing(true);
if (touching) {
mWindowManager.setSlippery(false);
@@ -431,7 +444,7 @@
if (mCallback != null) {
mCallback.onDraggingStart();
}
- return mDockSide != WindowManager.DOCKED_INVALID;
+ return inSplitMode();
}
public void stopDragging(int position, float velocity, boolean avoidDismissStart,
@@ -467,38 +480,22 @@
}
private void updateDockSide() {
- mDockSide = mWindowManagerProxy.getDockSide();
+ mDockSide = mSplitLayout.getPrimarySplitSide();
mMinimizedShadow.setDockSide(mDockSide);
}
- private void initializeSnapAlgorithm() {
- if (mSnapAlgorithm == null) {
- mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
- mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets, mDockSide);
- if (mSnapTargetBeforeMinimized != null && mSnapTargetBeforeMinimized.isMiddleTarget) {
- mSnapTargetBeforeMinimized = mSnapAlgorithm.getMiddleTarget();
- }
- }
- if (mMinimizedSnapAlgorithm == null) {
- mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
- mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(),
- mStableInsets, mDockSide, mDockedStackMinimized && mHomeStackResizable);
- }
- }
-
public DividerSnapAlgorithm getSnapAlgorithm() {
- initializeSnapAlgorithm();
- return mDockedStackMinimized && mHomeStackResizable ? mMinimizedSnapAlgorithm :
- mSnapAlgorithm;
+ return mDockedStackMinimized
+ && mHomeStackResizable ? mSplitLayout.getMinimizedSnapAlgorithm()
+ : mSplitLayout.getSnapAlgorithm();
}
public int getCurrentPosition() {
- getLocationOnScreen(mTempInt2);
- if (isHorizontalDivision()) {
- return mTempInt2[1] + mDividerInsets;
- } else {
- return mTempInt2[0] + mDividerInsets;
- }
+ return isHorizontalDivision() ? mDividerPositionY : mDividerPositionX;
+ }
+
+ public boolean isMinimized() {
+ return mDockedStackMinimized;
}
@Override
@@ -557,25 +554,25 @@
}
private void logResizeEvent(SnapTarget snapTarget) {
- if (snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
+ if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissStartTarget()) {
MetricsLogger.action(
mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideTopLeft(mDockSide)
? LOG_VALUE_UNDOCK_MAX_OTHER
: LOG_VALUE_UNDOCK_MAX_DOCKED);
- } else if (snapTarget == mSnapAlgorithm.getDismissEndTarget()) {
+ } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissEndTarget()) {
MetricsLogger.action(
mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideBottomRight(mDockSide)
? LOG_VALUE_UNDOCK_MAX_OTHER
: LOG_VALUE_UNDOCK_MAX_DOCKED);
- } else if (snapTarget == mSnapAlgorithm.getMiddleTarget()) {
+ } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getMiddleTarget()) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
LOG_VALUE_RESIZE_50_50);
- } else if (snapTarget == mSnapAlgorithm.getFirstSplitTarget()) {
+ } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getFirstSplitTarget()) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
dockSideTopLeft(mDockSide)
? LOG_VALUE_RESIZE_DOCKED_SMALLER
: LOG_VALUE_RESIZE_DOCKED_LARGER);
- } else if (snapTarget == mSnapAlgorithm.getLastSplitTarget()) {
+ } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getLastSplitTarget()) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
dockSideTopLeft(mDockSide)
? LOG_VALUE_RESIZE_DOCKED_LARGER
@@ -625,12 +622,16 @@
: snapTarget.taskPosition,
snapTarget));
Runnable endAction = () -> {
- commitSnapFlags(snapTarget);
+ boolean dismissed = commitSnapFlags(snapTarget);
mWindowManagerProxy.setResizing(false);
updateDockSide();
mCurrentAnimator = null;
mEntranceAnimationRunning = false;
mExitAnimationRunning = false;
+ if (!dismissed) {
+ WindowManagerProxy.applyResizeSplits((mIsInMinimizeInteraction
+ ? mSnapTargetBeforeMinimized : snapTarget).position, mSplitLayout);
+ }
if (mCallback != null) {
mCallback.onDraggingEnd();
}
@@ -642,12 +643,13 @@
// position isn't negative.
final SnapTarget saveTarget;
if (snapTarget.position < 0) {
- saveTarget = mSnapAlgorithm.getMiddleTarget();
+ saveTarget = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
} else {
saveTarget = snapTarget;
}
- if (saveTarget.position != mSnapAlgorithm.getDismissEndTarget().position
- && saveTarget.position != mSnapAlgorithm.getDismissStartTarget().position) {
+ final DividerSnapAlgorithm snapAlgo = mSplitLayout.getSnapAlgorithm();
+ if (saveTarget.position != snapAlgo.getDismissEndTarget().position
+ && saveTarget.position != snapAlgo.getDismissStartTarget().position) {
saveSnapTargetBeforeMinimized(saveTarget);
}
}
@@ -701,11 +703,11 @@
}
}
- private void commitSnapFlags(SnapTarget target) {
+ private boolean commitSnapFlags(SnapTarget target) {
if (target.flag == SnapTarget.FLAG_NONE) {
- return;
+ return false;
}
- boolean dismissOrMaximize;
+ final boolean dismissOrMaximize;
if (target.flag == SnapTarget.FLAG_DISMISS_START) {
dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT
|| mDockSide == WindowManager.DOCKED_TOP;
@@ -713,12 +715,13 @@
dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
|| mDockSide == WindowManager.DOCKED_BOTTOM;
}
- if (dismissOrMaximize) {
- mWindowManagerProxy.dismissDockedStack();
- } else {
- mWindowManagerProxy.maximizeDockedStack();
- }
- mWindowManagerProxy.setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
+ mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, dismissOrMaximize);
+ Transaction t = mTiles.getTransaction();
+ setResizeDimLayer(t, true /* primary */, 0f);
+ setResizeDimLayer(t, false /* primary */, 0f);
+ t.apply();
+ mTiles.releaseTransaction(t);
+ return true;
}
private void liftBackground() {
@@ -765,6 +768,28 @@
mBackgroundLifted = false;
}
+ private void initializeSurfaceState() {
+ int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
+ // Recalculate the split-layout's internal tile bounds
+ mSplitLayout.resizeSplits(midPos);
+ Transaction t = mTiles.getTransaction();
+ if (mDockedStackMinimized) {
+ int position = mSplitLayout.getMinimizedSnapAlgorithm().getMiddleTarget().position;
+ calculateBoundsForPosition(position, mDockSide, mDockedRect);
+ calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
+ mOtherRect);
+ mDividerPositionX = mDividerPositionY = position;
+ resizeSplitSurfaces(t, mDockedRect, mSplitLayout.mPrimary,
+ mOtherRect, mSplitLayout.mSecondary);
+ } else {
+ resizeSplitSurfaces(t, mSplitLayout.mPrimary, null,
+ mSplitLayout.mSecondary, null);
+ }
+ setResizeDimLayer(t, true /* primary */, 0.f /* alpha */);
+ setResizeDimLayer(t, false /* secondary */, 0.f /* alpha */);
+ t.apply();
+ mTiles.releaseTransaction(t);
+ }
public void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable) {
mHomeStackResizable = isHomeStackResizable;
@@ -789,15 +814,11 @@
mDockedStackMinimized = minimized;
} else if (mDockedStackMinimized != minimized) {
mDockedStackMinimized = minimized;
- if (mDisplayRotation != mDefaultDisplay.getRotation()) {
+ if (mSplitLayout.mDisplayLayout.rotation() != mDefaultDisplay.getRotation()) {
// Splitscreen to minimize is about to starts after rotating landscape to seascape,
// update insets, display info and snap algorithm targets
WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
repositionSnapTargetBeforeMinimized();
- updateDisplayInfo();
- } else {
- mMinimizedSnapAlgorithm = null;
- initializeSnapAlgorithm();
}
if (mIsInMinimizeInteraction != minimized || mCurrentAnimator != null) {
cancelFlingAnimation();
@@ -805,15 +826,64 @@
// Relayout to recalculate the divider shadow when minimizing
requestLayout();
mIsInMinimizeInteraction = true;
- resizeStack(mMinimizedSnapAlgorithm.getMiddleTarget());
+ resizeStackSurfaces(mSplitLayout.getMinimizedSnapAlgorithm().getMiddleTarget());
} else {
- resizeStack(mSnapTargetBeforeMinimized);
+ resizeStackSurfaces(mSnapTargetBeforeMinimized);
mIsInMinimizeInteraction = false;
}
}
}
}
+ void enterSplitMode(boolean isHomeStackResizable) {
+ post(() -> {
+ final SurfaceControl sc = getWindowSurfaceControl();
+ if (sc == null) {
+ return;
+ }
+ Transaction t = mTiles.getTransaction();
+ t.show(sc).apply();
+ mTiles.releaseTransaction(t);
+ });
+ if (isHomeStackResizable) {
+ SnapTarget miniMid = mSplitLayout.getMinimizedSnapAlgorithm().getMiddleTarget();
+ if (mDockedStackMinimized) {
+ mDividerPositionY = mDividerPositionX = miniMid.position;
+ }
+ }
+ }
+
+ /**
+ * Tries to grab a surface control from ViewRootImpl. If this isn't available for some reason
+ * (ie. the window isn't ready yet), it will get the surfacecontrol that the WindowlessWM has
+ * assigned to it.
+ */
+ private SurfaceControl getWindowSurfaceControl() {
+ if (getViewRootImpl() == null) {
+ return null;
+ }
+ SurfaceControl out = getViewRootImpl().getSurfaceControl();
+ if (out != null && out.isValid()) {
+ return out;
+ }
+ return mWindowManager.mSystemWindows.getViewSurface(this);
+ }
+
+ void exitSplitMode() {
+ // Reset tile bounds
+ post(() -> {
+ final SurfaceControl sc = getWindowSurfaceControl();
+ if (sc == null) {
+ return;
+ }
+ Transaction t = mTiles.getTransaction();
+ t.hide(sc).apply();
+ mTiles.releaseTransaction(t);
+ });
+ int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
+ WindowManagerProxy.applyResizeSplits(midPos, mSplitLayout);
+ }
+
public void setMinimizedDockStack(boolean minimized, long animDuration,
boolean isHomeStackResizable) {
mHomeStackResizable = isHomeStackResizable;
@@ -844,14 +914,12 @@
mDockedStackMinimized = minimized;
} else if (mDockedStackMinimized != minimized) {
mIsInMinimizeInteraction = true;
- mMinimizedSnapAlgorithm = null;
mDockedStackMinimized = minimized;
- initializeSnapAlgorithm();
stopDragging(minimized
? mSnapTargetBeforeMinimized.position
: getCurrentPosition(),
minimized
- ? mMinimizedSnapAlgorithm.getMiddleTarget()
+ ? mSplitLayout.getMinimizedSnapAlgorithm().getMiddleTarget()
: mSnapTargetBeforeMinimized,
animDuration, Interpolators.FAST_OUT_SLOW_IN, 0);
setAdjustedForIme(false, animDuration);
@@ -865,18 +933,6 @@
.start();
}
- public void setAdjustedForIme(boolean adjustedForIme) {
- updateDockSide();
- mHandle.setAlpha(adjustedForIme ? 0f : 1f);
- if (!adjustedForIme) {
- resetBackground();
- } else if (mDockSide == WindowManager.DOCKED_TOP) {
- mBackground.setPivotY(0);
- mBackground.setScaleY(ADJUSTED_FOR_IME_SCALE);
- }
- mAdjustedForIme = adjustedForIme;
- }
-
public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
updateDockSide();
mHandle.animate()
@@ -902,7 +958,8 @@
private void saveSnapTargetBeforeMinimized(SnapTarget target) {
mSnapTargetBeforeMinimized = target;
mState.mRatioPositionBeforeMinimized = (float) target.position /
- (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth);
+ (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
+ : mSplitLayout.mDisplayLayout.width());
}
private void resetBackground() {
@@ -916,51 +973,17 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- updateDisplayInfo();
- }
-
- public void notifyDockSideChanged(int newDockSide) {
- int oldDockSide = mDockSide;
- mDockSide = newDockSide;
- mMinimizedShadow.setDockSide(mDockSide);
- requestLayout();
-
- // Update the snap position to the new docked side with correct insets
- WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
- mMinimizedSnapAlgorithm = null;
- initializeSnapAlgorithm();
-
- if (oldDockSide == DOCKED_LEFT && mDockSide == DOCKED_RIGHT
- || oldDockSide == DOCKED_RIGHT && mDockSide == DOCKED_LEFT) {
- repositionSnapTargetBeforeMinimized();
- }
-
- // Landscape to seascape rotation requires minimized to resize docked app correctly
- if (mHomeStackResizable && mDockedStackMinimized) {
- resizeStack(mMinimizedSnapAlgorithm.getMiddleTarget());
- }
}
private void repositionSnapTargetBeforeMinimized() {
int position = (int) (mState.mRatioPositionBeforeMinimized *
- (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth));
- mSnapAlgorithm = null;
- initializeSnapAlgorithm();
+ (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
+ : mSplitLayout.mDisplayLayout.width()));
// Set the snap target before minimized but do not save until divider is attached and not
// minimized because it does not know its minimized state yet.
- mSnapTargetBeforeMinimized = mSnapAlgorithm.calculateNonDismissingSnapTarget(position);
- }
-
- private void updateDisplayInfo() {
- mDisplayRotation = mDefaultDisplay.getRotation();
- final DisplayInfo info = new DisplayInfo();
- mDefaultDisplay.getDisplayInfo(info);
- mDisplayWidth = info.logicalWidth;
- mDisplayHeight = info.logicalHeight;
- mSnapAlgorithm = null;
- mMinimizedSnapAlgorithm = null;
- initializeSnapAlgorithm();
+ mSnapTargetBeforeMinimized =
+ mSplitLayout.getSnapAlgorithm().calculateNonDismissingSnapTarget(position);
}
private int calculatePosition(int touchX, int touchY) {
@@ -994,8 +1017,9 @@
}
public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
- DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect, mDisplayWidth,
- mDisplayHeight, mDividerSize);
+ DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect,
+ mSplitLayout.mDisplayLayout.width(), mSplitLayout.mDisplayLayout.height(),
+ mDividerSize);
}
public void resizeStackDelayed(int position, int taskPosition, SnapTarget taskSnapTarget) {
@@ -1005,16 +1029,60 @@
mSfChoreographer.scheduleAtSfVsync(mHandler, message);
}
- private void resizeStack(SnapTarget taskSnapTarget) {
- resizeStack(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget);
+ private void resizeStackSurfaces(SnapTarget taskSnapTarget) {
+ resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget);
}
- public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
+ void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect otherRect) {
+ resizeSplitSurfaces(t, dockedRect, null, otherRect, null);
+ }
+
+ private void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect dockedTaskRect,
+ Rect otherRect, Rect otherTaskRect) {
+ dockedTaskRect = dockedTaskRect == null ? dockedRect : dockedTaskRect;
+ otherTaskRect = otherTaskRect == null ? otherRect : otherTaskRect;
+
+ mDividerPositionX = dockedRect.right;
+ mDividerPositionY = dockedRect.bottom;
+
+ t.setPosition(mTiles.mPrimarySurface, dockedTaskRect.left, dockedTaskRect.top);
+ Rect crop = new Rect(dockedRect);
+ crop.offsetTo(-Math.min(dockedTaskRect.left - dockedRect.left, 0),
+ -Math.min(dockedTaskRect.top - dockedRect.top, 0));
+ t.setWindowCrop(mTiles.mPrimarySurface, crop);
+ t.setPosition(mTiles.mSecondarySurface, otherTaskRect.left, otherTaskRect.top);
+ crop.set(otherRect);
+ crop.offsetTo(-(otherTaskRect.left - otherRect.left),
+ -(otherTaskRect.top - otherRect.top));
+ t.setWindowCrop(mTiles.mSecondarySurface, crop);
+ final SurfaceControl dividerCtrl = getWindowSurfaceControl();
+ if (dividerCtrl != null) {
+ if (isHorizontalDivision()) {
+ t.setPosition(dividerCtrl, 0, mDividerPositionY - mDividerInsets);
+ } else {
+ t.setPosition(dividerCtrl, mDividerPositionX - mDividerInsets, 0);
+ }
+ }
+ }
+
+ void setResizeDimLayer(Transaction t, boolean primary, float alpha) {
+ SurfaceControl dim = primary ? mTiles.mPrimaryDim : mTiles.mSecondaryDim;
+ if (alpha <= 0.f) {
+ t.hide(dim);
+ } else {
+ t.setAlpha(dim, alpha);
+ t.show(dim);
+ }
+ }
+
+ void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget) {
if (mRemoved) {
// This divider view has been removed so shouldn't have any additional influence.
return;
}
calculateBoundsForPosition(position, mDockSide, mDockedRect);
+ calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
+ mOtherRect);
if (mDockedRect.equals(mLastResizeRect) && !mEntranceAnimationRunning) {
return;
@@ -1025,6 +1093,7 @@
mBackground.invalidate();
}
+ Transaction t = mTiles.getTransaction();
mLastResizeRect.set(mDockedRect);
if (mHomeStackResizable && mIsInMinimizeInteraction) {
calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
@@ -1037,8 +1106,10 @@
mDockedTaskRect.offset(Math.max(position, mStableInsets.left - mDividerSize)
- mDockedTaskRect.left + mDividerSize, 0);
}
- mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect,
- mOtherTaskRect, null);
+ resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect,
+ mOtherTaskRect);
+ t.apply();
+ mTiles.releaseTransaction(t);
return;
}
@@ -1052,8 +1123,7 @@
}
calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
mOtherTaskRect);
- mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
- mOtherTaskRect, null);
+ resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
} else if (mExitAnimationRunning && taskPosition != TASK_POSITION_SAME) {
calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
mDockedInsetRect.set(mDockedTaskRect);
@@ -1066,8 +1136,7 @@
if (mDockSide == DOCKED_RIGHT) {
mDockedTaskRect.offset(position - mStableInsets.left + mDividerSize, 0);
}
- mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
- mOtherTaskRect, mOtherInsetRect);
+ resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
} else if (taskPosition != TASK_POSITION_SAME) {
calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
mOtherRect);
@@ -1078,7 +1147,8 @@
restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
- mTmpRect.set(0, 0, mDisplayWidth, mDisplayHeight);
+ mTmpRect.set(0, 0, mSplitLayout.mDisplayLayout.width(),
+ mSplitLayout.mDisplayLayout.height());
alignTopLeft(mDockedRect, mDockedTaskRect);
alignTopLeft(mOtherRect, mOtherTaskRect);
mDockedInsetRect.set(mDockedTaskRect);
@@ -1094,15 +1164,15 @@
taskPositionDocked);
applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
taskPositionOther);
- mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
- mOtherTaskRect, mOtherInsetRect);
+ resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
} else {
- mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
+ resizeSplitSurfaces(t, mDockedRect, null, mOtherRect, null);
}
SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
float dimFraction = getDimFraction(position, closestDismissTarget);
- mWindowManagerProxy.setResizeDimLayer(dimFraction != 0f,
- getWindowingModeForDismissTarget(closestDismissTarget), dimFraction);
+ setResizeDimLayer(t, isDismissTargetPrimary(closestDismissTarget), dimFraction);
+ t.apply();
+ mTiles.releaseTransaction(t);
}
private void applyExitAnimationParallax(Rect taskRect, int position) {
@@ -1156,10 +1226,12 @@
private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
SnapTarget snapTarget) {
if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
- return Math.max(mSnapAlgorithm.getFirstSplitTarget().position, mStartPosition);
+ return Math.max(mSplitLayout.getSnapAlgorithm().getFirstSplitTarget().position,
+ mStartPosition);
} else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
&& dockSideBottomRight(dockSide)) {
- return Math.min(mSnapAlgorithm.getLastSplitTarget().position, mStartPosition);
+ return Math.min(mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position,
+ mStartPosition);
} else {
return taskPosition;
}
@@ -1171,19 +1243,19 @@
private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
int position, int taskPosition) {
float fraction = Math.min(1, Math.max(0,
- mSnapAlgorithm.calculateDismissingFraction(position)));
+ mSplitLayout.getSnapAlgorithm().calculateDismissingFraction(position)));
SnapTarget dismissTarget = null;
SnapTarget splitTarget = null;
int start = 0;
- if (position <= mSnapAlgorithm.getLastSplitTarget().position
+ if (position <= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
&& dockSideTopLeft(dockSide)) {
- dismissTarget = mSnapAlgorithm.getDismissStartTarget();
- splitTarget = mSnapAlgorithm.getFirstSplitTarget();
+ dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
+ splitTarget = mSplitLayout.getSnapAlgorithm().getFirstSplitTarget();
start = taskPosition;
- } else if (position >= mSnapAlgorithm.getLastSplitTarget().position
+ } else if (position >= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
&& dockSideBottomRight(dockSide)) {
- dismissTarget = mSnapAlgorithm.getDismissEndTarget();
- splitTarget = mSnapAlgorithm.getLastSplitTarget();
+ dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissEndTarget();
+ splitTarget = mSplitLayout.getSnapAlgorithm().getLastSplitTarget();
start = splitTarget.position;
}
if (dismissTarget != null && fraction > 0f
@@ -1236,14 +1308,10 @@
}
}
- private int getWindowingModeForDismissTarget(SnapTarget dismissTarget) {
- if ((dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
+ private boolean isDismissTargetPrimary(SnapTarget dismissTarget) {
+ return (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
|| (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
- && dockSideBottomRight(mDockSide))) {
- return WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
- } else {
- return WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- }
+ && dockSideBottomRight(mDockSide));
}
/**
@@ -1297,7 +1365,7 @@
}
void onDockedFirstAnimationFrame() {
- saveSnapTargetBeforeMinimized(mSnapAlgorithm.getMiddleTarget());
+ saveSnapTargetBeforeMinimized(mSplitLayout.getSnapAlgorithm().getMiddleTarget());
}
void onDockedTopTask() {
@@ -1307,8 +1375,9 @@
updateDockSide();
mEntranceAnimationRunning = true;
- resizeStack(calculatePositionForInsetBounds(), mSnapAlgorithm.getMiddleTarget().position,
- mSnapAlgorithm.getMiddleTarget());
+ resizeStackSurfaces(calculatePositionForInsetBounds(),
+ mSplitLayout.getSnapAlgorithm().getMiddleTarget().position,
+ mSplitLayout.getSnapAlgorithm().getMiddleTarget());
}
void onRecentsDrawn() {
@@ -1337,13 +1406,12 @@
}
void onUndockingTask() {
- int dockSide = mWindowManagerProxy.getDockSide();
- if (dockSide != WindowManager.DOCKED_INVALID && (mHomeStackResizable
- || !mDockedStackMinimized)) {
+ int dockSide = mSplitLayout.getPrimarySplitSide();
+ if (inSplitMode() && (mHomeStackResizable || !mDockedStackMinimized)) {
startDragging(false /* animate */, false /* touching */);
SnapTarget target = dockSideTopLeft(dockSide)
- ? mSnapAlgorithm.getDismissEndTarget()
- : mSnapAlgorithm.getDismissStartTarget();
+ ? mSplitLayout.getSnapAlgorithm().getDismissEndTarget()
+ : mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
// Don't start immediately - give a little bit time to settle the drag resize change.
mExitAnimationRunning = true;
@@ -1354,8 +1422,7 @@
}
private int calculatePositionForInsetBounds() {
- mTmpRect.set(0, 0, mDisplayWidth, mDisplayHeight);
- mTmpRect.inset(mStableInsets);
+ mSplitLayout.mDisplayLayout.getStableBounds(mTmpRect);
return DockedDividerUtils.calculatePositionForBounds(mTmpRect, mDockSide, mDividerSize);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 2486d653..3020a25 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -26,12 +26,13 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.view.View;
import android.view.WindowManager;
+import com.android.systemui.wm.SystemWindows;
+
/**
* Manages the window parameters of the docked stack divider.
*/
@@ -39,15 +40,16 @@
private static final String WINDOW_TITLE = "DockedStackDivider";
- private final WindowManager mWindowManager;
+ final SystemWindows mSystemWindows;
private WindowManager.LayoutParams mLp;
private View mView;
- public DividerWindowManager(Context ctx) {
- mWindowManager = ctx.getSystemService(WindowManager.class);
+ public DividerWindowManager(SystemWindows systemWindows) {
+ mSystemWindows = systemWindows;
}
- public void add(View view, int width, int height) {
+ /** Add a divider view */
+ public void add(View view, int width, int height, int displayId) {
mLp = new WindowManager.LayoutParams(
width, height, TYPE_DOCK_DIVIDER,
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
@@ -60,13 +62,13 @@
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- mWindowManager.addView(view, mLp);
+ mSystemWindows.addView(view, mLp, displayId, TYPE_DOCK_DIVIDER);
mView = view;
}
public void remove() {
if (mView != null) {
- mWindowManager.removeView(mView);
+ mSystemWindows.removeView(mView);
}
mView = null;
}
@@ -81,7 +83,7 @@
changed = true;
}
if (changed) {
- mWindowManager.updateViewLayout(mView, mLp);
+ mSystemWindows.updateViewLayout(mView, mLp);
}
}
@@ -95,7 +97,7 @@
changed = true;
}
if (changed) {
- mWindowManager.updateViewLayout(mView, mLp);
+ mSystemWindows.updateViewLayout(mView, mLp);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index c6ac309..db7996e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -31,6 +31,8 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import java.util.function.Consumer;
+
/**
* Controller that decides when to show the {@link ForcedResizableInfoActivity}.
*/
@@ -52,6 +54,12 @@
}
};
+ private final Consumer<Boolean> mDockedStackExistsListener = exists -> {
+ if (!exists) {
+ mPackagesShownInSession.clear();
+ }
+ };
+
/** Record of force resized task that's pending to be handled. */
private class PendingTaskRecord {
int taskId;
@@ -67,7 +75,7 @@
}
}
- public ForcedResizableInfoActivityController(Context context) {
+ public ForcedResizableInfoActivityController(Context context, Divider divider) {
mContext = context;
ActivityManagerWrapper.getInstance().registerTaskStackListener(
new TaskStackChangeListener() {
@@ -87,12 +95,7 @@
activityLaunchOnSecondaryDisplayFailed();
}
});
- }
-
- public void notifyDockedStackExistsChanged(boolean exists) {
- if (!exists) {
- mPackagesShownInSession.clear();
- }
+ divider.registerInSplitScreenListener(mDockedStackExistsListener);
}
public void onAppTransitionFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java
new file mode 100644
index 0000000..b19f560
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java
@@ -0,0 +1,310 @@
+/*
+ * 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.stackdivider;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.util.TypedValue;
+import android.view.WindowContainerTransaction;
+
+import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.internal.policy.DockedDividerUtils;
+import com.android.systemui.wm.DisplayLayout;
+
+/**
+ * Handles split-screen related internal display layout. In general, this represents the
+ * WM-facing understanding of the splits.
+ */
+public class SplitDisplayLayout {
+ /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
+ * restrict IME adjustment so that a min portion of top stack remains visible.*/
+ private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
+
+ private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
+
+ SplitScreenTaskOrganizer mTiles;
+ DisplayLayout mDisplayLayout;
+ Context mContext;
+
+ // Lazy stuff
+ boolean mResourcesValid = false;
+ int mDividerSize;
+ int mDividerSizeInactive;
+ private DividerSnapAlgorithm mSnapAlgorithm = null;
+ private DividerSnapAlgorithm mMinimizedSnapAlgorithm = null;
+ Rect mPrimary = null;
+ Rect mSecondary = null;
+ Rect mAdjustedPrimary = null;
+ Rect mAdjustedSecondary = null;
+
+ public SplitDisplayLayout(Context ctx, DisplayLayout dl, SplitScreenTaskOrganizer taskTiles) {
+ mTiles = taskTiles;
+ mDisplayLayout = dl;
+ mContext = ctx;
+ }
+
+ void rotateTo(int newRotation) {
+ mDisplayLayout.rotateTo(mContext.getResources(), newRotation);
+ final Configuration config = new Configuration();
+ config.unset();
+ config.orientation = mDisplayLayout.getOrientation();
+ Rect tmpRect = new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height());
+ tmpRect.inset(mDisplayLayout.nonDecorInsets());
+ config.windowConfiguration.setAppBounds(tmpRect);
+ tmpRect.set(0, 0, mDisplayLayout.width(), mDisplayLayout.height());
+ tmpRect.inset(mDisplayLayout.stableInsets());
+ config.screenWidthDp = (int) (tmpRect.width() / mDisplayLayout.density());
+ config.screenHeightDp = (int) (tmpRect.height() / mDisplayLayout.density());
+ mContext = mContext.createConfigurationContext(config);
+ mSnapAlgorithm = null;
+ mMinimizedSnapAlgorithm = null;
+ mResourcesValid = false;
+ }
+
+ private void updateResources() {
+ if (mResourcesValid) {
+ return;
+ }
+ mResourcesValid = true;
+ Resources res = mContext.getResources();
+ mDividerSize = DockedDividerUtils.getDividerSize(res,
+ DockedDividerUtils.getDividerInsets(res));
+ mDividerSizeInactive = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, DIVIDER_WIDTH_INACTIVE_DP, res.getDisplayMetrics());
+ }
+
+ int getPrimarySplitSide() {
+ return mDisplayLayout.isLandscape() ? DOCKED_LEFT : DOCKED_TOP;
+ }
+
+ boolean isMinimized() {
+ return mTiles.mSecondary.topActivityType == ACTIVITY_TYPE_HOME
+ || mTiles.mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS;
+ }
+
+ DividerSnapAlgorithm getSnapAlgorithm() {
+ if (mSnapAlgorithm == null) {
+ updateResources();
+ boolean isHorizontalDivision = !mDisplayLayout.isLandscape();
+ mSnapAlgorithm = new DividerSnapAlgorithm(mContext.getResources(),
+ mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize,
+ isHorizontalDivision, mDisplayLayout.stableInsets(), getPrimarySplitSide());
+ }
+ return mSnapAlgorithm;
+ }
+
+ DividerSnapAlgorithm getMinimizedSnapAlgorithm() {
+ if (mMinimizedSnapAlgorithm == null) {
+ updateResources();
+ boolean isHorizontalDivision = !mDisplayLayout.isLandscape();
+ mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(mContext.getResources(),
+ mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize,
+ isHorizontalDivision, mDisplayLayout.stableInsets(), getPrimarySplitSide(),
+ true /* isMinimized */);
+ }
+ return mMinimizedSnapAlgorithm;
+ }
+
+ void resizeSplits(int position) {
+ mPrimary = mPrimary == null ? new Rect() : mPrimary;
+ mSecondary = mSecondary == null ? new Rect() : mSecondary;
+ calcSplitBounds(position, mPrimary, mSecondary);
+ }
+
+ void resizeSplits(int position, WindowContainerTransaction t) {
+ resizeSplits(position);
+ t.setBounds(mTiles.mPrimary.token, mPrimary);
+ t.setBounds(mTiles.mSecondary.token, mSecondary);
+
+ t.setSmallestScreenWidthDp(mTiles.mPrimary.token,
+ getSmallestWidthDpForBounds(mContext, mDisplayLayout, mPrimary));
+ t.setSmallestScreenWidthDp(mTiles.mSecondary.token,
+ getSmallestWidthDpForBounds(mContext, mDisplayLayout, mSecondary));
+ }
+
+ void calcSplitBounds(int position, @NonNull Rect outPrimary, @NonNull Rect outSecondary) {
+ int dockSide = getPrimarySplitSide();
+ DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outPrimary,
+ mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize);
+
+ DockedDividerUtils.calculateBoundsForPosition(position,
+ DockedDividerUtils.invertDockSide(dockSide), outSecondary, mDisplayLayout.width(),
+ mDisplayLayout.height(), mDividerSize);
+ }
+
+ Rect calcMinimizedHomeStackBounds() {
+ DividerSnapAlgorithm.SnapTarget miniMid = getMinimizedSnapAlgorithm().getMiddleTarget();
+ Rect homeBounds = new Rect();
+ DockedDividerUtils.calculateBoundsForPosition(miniMid.position,
+ DockedDividerUtils.invertDockSide(getPrimarySplitSide()), homeBounds,
+ mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize);
+ return homeBounds;
+ }
+
+ /**
+ * Updates the adjustment depending on it's current state.
+ */
+ void updateAdjustedBounds(int currImeTop, int startTop, int finalTop) {
+ updateAdjustedBounds(mDisplayLayout, currImeTop, startTop, finalTop, mDividerSize,
+ mDividerSizeInactive, mPrimary, mSecondary);
+ }
+
+ /**
+ * Updates the adjustment depending on it's current state.
+ */
+ private void updateAdjustedBounds(DisplayLayout dl, int currImeTop, int startTop, int finalTop,
+ int dividerWidth, int dividerWidthInactive, Rect primaryBounds, Rect secondaryBounds) {
+ adjustForIME(dl, currImeTop, startTop, finalTop, dividerWidth, dividerWidthInactive,
+ primaryBounds, secondaryBounds);
+ }
+
+ /** Assumes top/bottom split. Splits are not adjusted for left/right splits. */
+ private void adjustForIME(DisplayLayout dl, int currImeTop, int startTop, int finalTop,
+ int dividerWidth, int dividerWidthInactive, Rect primaryBounds, Rect secondaryBounds) {
+ if (mAdjustedPrimary == null) {
+ mAdjustedPrimary = new Rect();
+ mAdjustedSecondary = new Rect();
+ }
+
+ final Rect displayStableRect = new Rect();
+ dl.getStableBounds(displayStableRect);
+
+ final boolean showing = finalTop < startTop;
+ final float progress = ((float) (currImeTop - startTop)) / (finalTop - startTop);
+ final float dividerSquish = showing ? progress : 1.f - progress;
+ final int currDividerWidth =
+ (int) (dividerWidthInactive * dividerSquish + dividerWidth * (1.f - dividerSquish));
+
+ final int minTopStackBottom = displayStableRect.top
+ + (int) ((mPrimary.bottom - displayStableRect.top) * ADJUSTED_STACK_FRACTION_MIN);
+ final int minImeTop = minTopStackBottom + currDividerWidth;
+
+ // Calculate an offset which shifts the stacks up by the height of the IME, but still
+ // leaves at least 30% of the top stack visible.
+ final int yOffset = Math.max(0, dl.height() - Math.max(currImeTop, minImeTop));
+
+ // TOP
+ // Reduce the offset by an additional small amount to squish the divider bar.
+ mAdjustedPrimary.set(primaryBounds);
+ mAdjustedPrimary.offset(0, -yOffset + (dividerWidth - currDividerWidth));
+
+ // BOTTOM
+ mAdjustedSecondary.set(secondaryBounds);
+ mAdjustedSecondary.offset(0, -yOffset);
+ }
+
+ static int getSmallestWidthDpForBounds(@NonNull Context context, DisplayLayout dl,
+ Rect bounds) {
+ int dividerSize = DockedDividerUtils.getDividerSize(context.getResources(),
+ DockedDividerUtils.getDividerInsets(context.getResources()));
+
+ int minWidth = Integer.MAX_VALUE;
+
+ // Go through all screen orientations and find the orientation in which the task has the
+ // smallest width.
+ Rect tmpRect = new Rect();
+ Rect rotatedDisplayRect = new Rect();
+ Rect displayRect = new Rect(0, 0, dl.width(), dl.height());
+
+ DisplayLayout tmpDL = new DisplayLayout();
+ for (int rotation = 0; rotation < 4; rotation++) {
+ tmpDL.set(dl);
+ tmpDL.rotateTo(context.getResources(), rotation);
+ DividerSnapAlgorithm snap = initSnapAlgorithmForRotation(context, tmpDL, dividerSize);
+
+ tmpRect.set(bounds);
+ DisplayLayout.rotateBounds(tmpRect, displayRect, rotation - dl.rotation());
+ rotatedDisplayRect.set(0, 0, tmpDL.width(), tmpDL.height());
+ final int dockSide = getPrimarySplitSide(tmpRect, rotatedDisplayRect,
+ tmpDL.getOrientation());
+ final int position = DockedDividerUtils.calculatePositionForBounds(tmpRect, dockSide,
+ dividerSize);
+
+ final int snappedPosition =
+ snap.calculateNonDismissingSnapTarget(position).position;
+ DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, tmpRect,
+ tmpDL.width(), tmpDL.height(), dividerSize);
+ Rect insettedDisplay = new Rect(rotatedDisplayRect);
+ insettedDisplay.inset(tmpDL.stableInsets());
+ tmpRect.intersect(insettedDisplay);
+ minWidth = Math.min(tmpRect.width(), minWidth);
+ }
+ return (int) (minWidth / dl.density());
+ }
+
+ static DividerSnapAlgorithm initSnapAlgorithmForRotation(Context context, DisplayLayout dl,
+ int dividerSize) {
+ final Configuration config = new Configuration();
+ config.unset();
+ config.orientation = dl.getOrientation();
+ Rect tmpRect = new Rect(0, 0, dl.width(), dl.height());
+ tmpRect.inset(dl.nonDecorInsets());
+ config.windowConfiguration.setAppBounds(tmpRect);
+ tmpRect.set(0, 0, dl.width(), dl.height());
+ tmpRect.inset(dl.stableInsets());
+ config.screenWidthDp = (int) (tmpRect.width() / dl.density());
+ config.screenHeightDp = (int) (tmpRect.height() / dl.density());
+ final Context rotationContext = context.createConfigurationContext(config);
+ return new DividerSnapAlgorithm(
+ rotationContext.getResources(), dl.width(), dl.height(), dividerSize,
+ config.orientation == ORIENTATION_PORTRAIT, dl.stableInsets());
+ }
+
+ /**
+ * Get the current primary-split side. Determined by its location of {@param bounds} within
+ * {@param displayRect} but if both are the same, it will try to dock to each side and determine
+ * if allowed in its respected {@param orientation}.
+ *
+ * @param bounds bounds of the primary split task to get which side is docked
+ * @param displayRect bounds of the display that contains the primary split task
+ * @param orientation the origination of device
+ * @return current primary-split side
+ */
+ static int getPrimarySplitSide(Rect bounds, Rect displayRect, int orientation) {
+ if (orientation == ORIENTATION_PORTRAIT) {
+ // Portrait mode, docked either at the top or the bottom.
+ final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
+ if (diff < 0) {
+ return DOCKED_BOTTOM;
+ } else {
+ // Top is default
+ return DOCKED_TOP;
+ }
+ } else if (orientation == ORIENTATION_LANDSCAPE) {
+ // Landscape mode, docked either on the left or on the right.
+ final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
+ if (diff < 0) {
+ return DOCKED_RIGHT;
+ }
+ return DOCKED_LEFT;
+ }
+ return DOCKED_INVALID;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
new file mode 100644
index 0000000..5cc8799
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -0,0 +1,159 @@
+/*
+ * 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.stackdivider;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ITaskOrganizerController;
+import android.app.WindowConfiguration;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Display;
+import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub {
+ private static final String TAG = "SplitScreenTaskOrganizer";
+ private static final boolean DEBUG = Divider.DEBUG;
+
+ RunningTaskInfo mPrimary;
+ RunningTaskInfo mSecondary;
+ SurfaceControl mPrimarySurface;
+ SurfaceControl mSecondarySurface;
+ SurfaceControl mPrimaryDim;
+ SurfaceControl mSecondaryDim;
+ final Divider mDivider;
+
+ SplitScreenTaskOrganizer(Divider divider) {
+ mDivider = divider;
+ }
+
+ void init(ITaskOrganizerController organizerController, SurfaceSession session)
+ throws RemoteException {
+ organizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ organizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mPrimary = organizerController.createRootTask(Display.DEFAULT_DISPLAY,
+ WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ mSecondary = organizerController.createRootTask(Display.DEFAULT_DISPLAY,
+ WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mPrimarySurface = mPrimary.token.getLeash();
+ mSecondarySurface = mSecondary.token.getLeash();
+
+ // Initialize dim surfaces:
+ mPrimaryDim = new SurfaceControl.Builder(session).setParent(mPrimarySurface)
+ .setColorLayer().setName("Primary Divider Dim").build();
+ mSecondaryDim = new SurfaceControl.Builder(session).setParent(mSecondarySurface)
+ .setColorLayer().setName("Secondary Divider Dim").build();
+ SurfaceControl.Transaction t = getTransaction();
+ t.setLayer(mPrimaryDim, Integer.MAX_VALUE);
+ t.setColor(mPrimaryDim, new float[]{0f, 0f, 0f});
+ t.setLayer(mSecondaryDim, Integer.MAX_VALUE);
+ t.setColor(mSecondaryDim, new float[]{0f, 0f, 0f});
+ t.apply();
+ releaseTransaction(t);
+ }
+
+ SurfaceControl.Transaction getTransaction() {
+ return mDivider.mTransactionPool.acquire();
+ }
+
+ void releaseTransaction(SurfaceControl.Transaction t) {
+ mDivider.mTransactionPool.release(t);
+ }
+
+ @Override
+ public void taskAppeared(RunningTaskInfo taskInfo) {
+ }
+
+ @Override
+ public void taskVanished(IWindowContainer container) {
+ }
+
+ @Override
+ public void transactionReady(int id, SurfaceControl.Transaction t) {
+ }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ if (taskInfo.displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+ mDivider.getHandler().post(() -> handleTaskInfoChanged(taskInfo));
+ }
+
+ /**
+ * This is effectively a finite state machine which moves between the various split-screen
+ * presentations based on the contents of the split regions.
+ */
+ private void handleTaskInfoChanged(RunningTaskInfo info) {
+ final boolean primaryWasEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
+ final boolean secondaryWasEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
+ if (info.token.asBinder() == mPrimary.token.asBinder()) {
+ mPrimary = info;
+ } else if (info.token.asBinder() == mSecondary.token.asBinder()) {
+ mSecondary = info;
+ }
+ final boolean primaryIsEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
+ final boolean secondaryIsEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
+ if (DEBUG) {
+ Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary);
+ }
+ if (primaryIsEmpty || secondaryIsEmpty) {
+ // At-least one of the splits is empty which means we are currently transitioning
+ // into or out-of split-screen mode.
+ if (DEBUG) {
+ Log.d(TAG, " at-least one split empty " + mPrimary.topActivityType
+ + " " + mSecondary.topActivityType);
+ }
+ if (mDivider.inSplitMode()) {
+ // Was in split-mode, which means we are leaving split, so continue that.
+ // This happens when the stack in the primary-split is dismissed.
+ if (DEBUG) {
+ Log.d(TAG, " was in split, so this means leave it "
+ + mPrimary.topActivityType + " " + mSecondary.topActivityType);
+ }
+ WindowManagerProxy.applyDismissSplit(this, true /* dismissOrMaximize */);
+ mDivider.updateVisibility(false /* visible */);
+ } else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
+ // Wasn't in split-mode (both were empty), but now that the primary split is
+ // populated, we should fully enter split by moving everything else into secondary.
+ // This just tells window-manager to reparent things, the UI will respond
+ // when it gets new task info for the secondary split.
+ if (DEBUG) {
+ Log.d(TAG, " was not in split, but primary is populated, so enter it");
+ }
+ mDivider.startEnterSplit();
+ }
+ } else if (mSecondary.topActivityType == ACTIVITY_TYPE_HOME
+ || mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS) {
+ // Both splits are populated but the secondary split has a home/recents stack on top,
+ // so enter minimized mode.
+ mDivider.ensureMinimizedSplit();
+ } else {
+ // Both splits are populated by normal activities, so make sure we aren't minimized.
+ mDivider.ensureNormalSplit();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 228aab5..7685733 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -16,16 +16,25 @@
package com.android.systemui.stackdivider;
-import static android.view.WindowManager.DOCKED_INVALID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.Display.DEFAULT_DISPLAY;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
+import android.view.Display;
+import android.view.IWindowContainer;
+import android.view.WindowContainerTransaction;
import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -35,88 +44,20 @@
public class WindowManagerProxy {
private static final String TAG = "WindowManagerProxy";
+ private static final int[] HOME_AND_RECENTS = {ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_RECENTS};
private static final WindowManagerProxy sInstance = new WindowManagerProxy();
@GuardedBy("mDockedRect")
private final Rect mDockedRect = new Rect();
- private final Rect mTempDockedTaskRect = new Rect();
- private final Rect mTempDockedInsetRect = new Rect();
- private final Rect mTempOtherTaskRect = new Rect();
- private final Rect mTempOtherInsetRect = new Rect();
private final Rect mTmpRect1 = new Rect();
- private final Rect mTmpRect2 = new Rect();
- private final Rect mTmpRect3 = new Rect();
- private final Rect mTmpRect4 = new Rect();
- private final Rect mTmpRect5 = new Rect();
@GuardedBy("mDockedRect")
private final Rect mTouchableRegion = new Rect();
- private boolean mDimLayerVisible;
- private int mDimLayerTargetWindowingMode;
- private float mDimLayerAlpha;
-
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
- private final Runnable mResizeRunnable = new Runnable() {
- @Override
- public void run() {
- synchronized (mDockedRect) {
- mTmpRect1.set(mDockedRect);
- mTmpRect2.set(mTempDockedTaskRect);
- mTmpRect3.set(mTempDockedInsetRect);
- mTmpRect4.set(mTempOtherTaskRect);
- mTmpRect5.set(mTempOtherInsetRect);
- }
- try {
- ActivityTaskManager.getService()
- .resizeDockedStack(mTmpRect1,
- mTmpRect2.isEmpty() ? null : mTmpRect2,
- mTmpRect3.isEmpty() ? null : mTmpRect3,
- mTmpRect4.isEmpty() ? null : mTmpRect4,
- mTmpRect5.isEmpty() ? null : mTmpRect5);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to resize stack: " + e);
- }
- }
- };
-
- private final Runnable mDismissRunnable = new Runnable() {
- @Override
- public void run() {
- try {
- ActivityTaskManager.getService().dismissSplitScreenMode(false /* onTop */);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to remove stack: " + e);
- }
- }
- };
-
- private final Runnable mMaximizeRunnable = new Runnable() {
- @Override
- public void run() {
- try {
- ActivityTaskManager.getService().dismissSplitScreenMode(true /* onTop */);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to resize stack: " + e);
- }
- }
- };
-
- private final Runnable mDimLayerRunnable = new Runnable() {
- @Override
- public void run() {
- try {
- WindowManagerGlobal.getWindowManagerService().setResizeDimLayer(mDimLayerVisible,
- mDimLayerTargetWindowingMode, mDimLayerAlpha);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to resize stack: " + e);
- }
- }
- };
-
private final Runnable mSetTouchableRegionRunnable = new Runnable() {
@Override
public void run() {
@@ -139,40 +80,9 @@
return sInstance;
}
- public void resizeDockedStack(Rect docked, Rect tempDockedTaskRect, Rect tempDockedInsetRect,
- Rect tempOtherTaskRect, Rect tempOtherInsetRect) {
- synchronized (mDockedRect) {
- mDockedRect.set(docked);
- if (tempDockedTaskRect != null) {
- mTempDockedTaskRect.set(tempDockedTaskRect);
- } else {
- mTempDockedTaskRect.setEmpty();
- }
- if (tempDockedInsetRect != null) {
- mTempDockedInsetRect.set(tempDockedInsetRect);
- } else {
- mTempDockedInsetRect.setEmpty();
- }
- if (tempOtherTaskRect != null) {
- mTempOtherTaskRect.set(tempOtherTaskRect);
- } else {
- mTempOtherTaskRect.setEmpty();
- }
- if (tempOtherInsetRect != null) {
- mTempOtherInsetRect.set(tempOtherInsetRect);
- } else {
- mTempOtherInsetRect.setEmpty();
- }
- }
- mExecutor.execute(mResizeRunnable);
- }
-
- public void dismissDockedStack() {
- mExecutor.execute(mDismissRunnable);
- }
-
- public void maximizeDockedStack() {
- mExecutor.execute(mMaximizeRunnable);
+ void dismissOrMaximizeDocked(
+ final SplitScreenTaskOrganizer tiles, final boolean dismissOrMaximize) {
+ mExecutor.execute(() -> applyDismissSplit(tiles, dismissOrMaximize));
}
public void setResizing(final boolean resizing) {
@@ -188,26 +98,204 @@
});
}
- public int getDockSide() {
- try {
- return WindowManagerGlobal.getWindowManagerService().getDockedStackSide();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to get dock side: " + e);
- }
- return DOCKED_INVALID;
- }
-
- public void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
- mDimLayerVisible = visible;
- mDimLayerTargetWindowingMode = targetWindowingMode;
- mDimLayerAlpha = alpha;
- mExecutor.execute(mDimLayerRunnable);
- }
-
+ /** Sets a touch region */
public void setTouchRegion(Rect region) {
synchronized (mDockedRect) {
mTouchableRegion.set(region);
}
mExecutor.execute(mSetTouchableRegionRunnable);
}
+
+ static void applyResizeSplits(int position, SplitDisplayLayout splitLayout) {
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ splitLayout.resizeSplits(position, t);
+ try {
+ ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(t,
+ null /* organizer */);
+ } catch (RemoteException e) {
+ }
+ }
+
+ private static boolean getHomeAndRecentsTasks(List<IWindowContainer> out,
+ IWindowContainer parent) {
+ boolean resizable = false;
+ try {
+ List<ActivityManager.RunningTaskInfo> rootTasks = parent == null
+ ? ActivityTaskManager.getTaskOrganizerController().getRootTasks(
+ Display.DEFAULT_DISPLAY, HOME_AND_RECENTS)
+ : ActivityTaskManager.getTaskOrganizerController().getChildTasks(parent,
+ HOME_AND_RECENTS);
+ for (int i = 0, n = rootTasks.size(); i < n; ++i) {
+ final ActivityManager.RunningTaskInfo ti = rootTasks.get(i);
+ out.add(ti.token);
+ if (ti.topActivityType == ACTIVITY_TYPE_HOME) {
+ resizable = ti.isResizable();
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ return resizable;
+ }
+
+ static void applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent) {
+ applyHomeTasksMinimized(layout, parent, null /* transaction */);
+ }
+
+ /**
+ * Assign a fixed override-bounds to home tasks that reflect their geometry while the primary
+ * split is minimized. This actually "sticks out" of the secondary split area, but when in
+ * minimized mode, the secondary split gets a 'negative' crop to expose it.
+ */
+ static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent,
+ WindowContainerTransaction t) {
+ // Resize the home/recents stacks to the larger minimized-state size
+ final Rect homeBounds;
+ final ArrayList<IWindowContainer> homeStacks = new ArrayList<>();
+ boolean isHomeResizable = getHomeAndRecentsTasks(homeStacks, parent);
+ if (isHomeResizable) {
+ homeBounds = layout.calcMinimizedHomeStackBounds();
+ } else {
+ homeBounds = new Rect(0, 0, layout.mDisplayLayout.width(),
+ layout.mDisplayLayout.height());
+ }
+ WindowContainerTransaction wct = t != null ? t : new WindowContainerTransaction();
+ for (int i = homeStacks.size() - 1; i >= 0; --i) {
+ wct.setBounds(homeStacks.get(i), homeBounds);
+ }
+ if (t != null) {
+ return isHomeResizable;
+ }
+ try {
+ ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
+ null /* organizer */);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to resize home stacks ", e);
+ }
+ return isHomeResizable;
+ }
+
+ /**
+ * Finishes entering split-screen by reparenting all FULLSCREEN tasks into the secondary split.
+ * This assumes there is already something in the primary split since that is usually what
+ * triggers a call to this. In the same transaction, this overrides the home task bounds via
+ * {@link #applyHomeTasksMinimized}.
+ *
+ * @return whether the home stack is resizable
+ */
+ static boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) {
+ try {
+ // Set launchtile first so that any stack created after
+ // getAllStackInfos and before reparent (even if unlikely) are placed
+ // correctly.
+ ActivityTaskManager.getTaskOrganizerController().setLaunchRoot(
+ DEFAULT_DISPLAY, tiles.mSecondary.token);
+ List<ActivityManager.RunningTaskInfo> rootTasks =
+ ActivityTaskManager.getTaskOrganizerController().getRootTasks(DEFAULT_DISPLAY,
+ null /* activityTypes */);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (rootTasks.isEmpty()) {
+ return false;
+ }
+ for (int i = rootTasks.size() - 1; i >= 0; --i) {
+ if (rootTasks.get(i).configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_FULLSCREEN) {
+ continue;
+ }
+ wct.reparent(rootTasks.get(i).token, tiles.mSecondary.token,
+ true /* onTop */);
+ }
+ boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct);
+ ActivityTaskManager.getTaskOrganizerController()
+ .applyContainerTransaction(wct, null /* organizer */);
+ return isHomeResizable;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error moving fullscreen tasks to secondary split: " + e);
+ }
+ return false;
+ }
+
+ private static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
+ final int atype = ti.configuration.windowConfiguration.getActivityType();
+ return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
+ }
+
+ /**
+ * Reparents all tile members back to their display and resets home task override bounds.
+ * @param dismissOrMaximize When {@code true} this resolves the split by closing the primary
+ * split (thus resulting in the top of the secondary split becoming
+ * fullscreen. {@code false} resolves the other way.
+ */
+ static void applyDismissSplit(SplitScreenTaskOrganizer tiles, boolean dismissOrMaximize) {
+ try {
+ // Set launch root first so that any task created after getChildContainers and
+ // before reparent (pretty unlikely) are put into fullscreen.
+ ActivityTaskManager.getTaskOrganizerController().setLaunchRoot(Display.DEFAULT_DISPLAY,
+ null);
+ // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
+ // plus specific APIs to clean this up.
+ List<ActivityManager.RunningTaskInfo> primaryChildren =
+ ActivityTaskManager.getTaskOrganizerController().getChildTasks(
+ tiles.mPrimary.token, null /* activityTypes */);
+ List<ActivityManager.RunningTaskInfo> secondaryChildren =
+ ActivityTaskManager.getTaskOrganizerController().getChildTasks(
+ tiles.mSecondary.token, null /* activityTypes */);
+ // In some cases (eg. non-resizable is launched), system-server will leave split-screen.
+ // as a result, the above will not capture any tasks; yet, we need to clean-up the
+ // home task bounds.
+ List<ActivityManager.RunningTaskInfo> freeHomeAndRecents =
+ ActivityTaskManager.getTaskOrganizerController().getRootTasks(
+ Display.DEFAULT_DISPLAY, HOME_AND_RECENTS);
+ if (primaryChildren.isEmpty() && secondaryChildren.isEmpty()
+ && freeHomeAndRecents.isEmpty()) {
+ return;
+ }
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (dismissOrMaximize) {
+ // Dismissing, so move all primary split tasks first
+ for (int i = primaryChildren.size() - 1; i >= 0; --i) {
+ wct.reparent(primaryChildren.get(i).token, null /* parent */,
+ true /* onTop */);
+ }
+ // Don't need to worry about home tasks because they are already in the "proper"
+ // order within the secondary split.
+ for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
+ wct.reparent(ti.token, null /* parent */, true /* onTop */);
+ if (isHomeOrRecentTask(ti)) {
+ wct.setBounds(ti.token, null);
+ }
+ }
+ } else {
+ // Maximize, so move non-home secondary split first
+ for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
+ if (isHomeOrRecentTask(secondaryChildren.get(i))) {
+ continue;
+ }
+ wct.reparent(secondaryChildren.get(i).token, null /* parent */,
+ true /* onTop */);
+ }
+ // Find and place home tasks in-between. This simulates the fact that there was
+ // nothing behind the primary split's tasks.
+ for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
+ if (isHomeOrRecentTask(ti)) {
+ wct.reparent(ti.token, null /* parent */, true /* onTop */);
+ // reset bounds too
+ wct.setBounds(ti.token, null);
+ }
+ }
+ for (int i = primaryChildren.size() - 1; i >= 0; --i) {
+ wct.reparent(primaryChildren.get(i).token, null /* parent */,
+ true /* onTop */);
+ }
+ }
+ for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) {
+ wct.setBounds(freeHomeAndRecents.get(i).token, null);
+ }
+ ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
+ null /* organizer */);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to remove stack: " + 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/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 93f5805..55a20fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -51,10 +51,10 @@
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.Dependency;
-import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.NotificationChannels;
@@ -80,11 +80,13 @@
private final CommandQueue mCommandQueue;
private boolean mDockedStackExists;
private KeyguardStateController mKeyguardStateController;
+ private final Divider mDivider;
@Inject
public InstantAppNotifier(Context context, CommandQueue commandQueue,
- @UiBackground Executor uiBgExecutor) {
+ @UiBackground Executor uiBgExecutor, Divider divider) {
super(context);
+ mDivider = divider;
mCommandQueue = commandQueue;
mUiBgExecutor = uiBgExecutor;
}
@@ -103,7 +105,7 @@
mCommandQueue.addCallback(this);
mKeyguardStateController.addCallback(this);
- DockedStackExistsListener.register(
+ mDivider.registerInSplitScreenListener(
exists -> {
mDockedStackExists = exists;
updateForegroundInstantApps();
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/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 2981252..e612c07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -33,6 +33,7 @@
import com.android.systemui.statusbar.phone.NotificationGroupManager
import com.android.systemui.statusbar.policy.HeadsUpManager
import dagger.Lazy
+import java.util.Comparator
import java.util.Objects
import javax.inject.Inject
@@ -73,6 +74,9 @@
val aIsPeople = a.isPeopleNotification()
val bIsPeople = b.isPeopleNotification()
+ val aIsImportantPeople = a.isImportantPeopleNotification()
+ val bIsImportantPeople = b.isImportantPeopleNotification()
+
val aMedia = isImportantMedia(a)
val bMedia = isImportantMedia(b)
@@ -87,6 +91,8 @@
when {
usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1
+ usePeopleFiltering && aIsImportantPeople != bIsImportantPeople ->
+ if (aIsImportantPeople) -1 else 1
aHeadsUp != bHeadsUp -> if (aHeadsUp) -1 else 1
// Provide consistent ranking with headsUpManager
aHeadsUp -> headsUpManager.compare(a, b)
@@ -192,6 +198,9 @@
private fun NotificationEntry.isPeopleNotification() =
peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)
+ private fun NotificationEntry.isImportantPeopleNotification() =
+ peopleNotificationIdentifier.isImportantPeopleNotification(sbn, ranking)
+
private fun NotificationEntry.isHighPriority() =
highPriorityProvider.isHighPriority(this)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index 4672de0..e15fa2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -23,6 +23,7 @@
interface PeopleNotificationIdentifier {
fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean
+ fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean
}
@Singleton
@@ -32,4 +33,7 @@
override fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) =
ranking.isConversation || personExtractor.isPersonNotification(sbn)
+
+ override fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) =
+ isPeopleNotification(sbn, ranking) && ranking.channel.isImportantConversation
}
\ No newline at end of file
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 55173182..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
@@ -1197,6 +1198,9 @@
if (mMenuRow != null && mMenuRow.getMenuView() != null) {
mMenuRow.onConfigurationChanged();
}
+ if (mImageResolver != null) {
+ mImageResolver.updateMaxImageSizes();
+ }
}
public void onUiModeChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 248e5fe..60eda06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -22,6 +22,7 @@
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
+import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -112,7 +113,8 @@
boolean mSkipPost = false;
@Retention(SOURCE)
- @IntDef({ACTION_BUBBLE, ACTION_HOME, ACTION_FAVORITE, ACTION_SNOOZE, ACTION_MUTE})
+ @IntDef({ACTION_BUBBLE, ACTION_HOME, ACTION_FAVORITE, ACTION_SNOOZE, ACTION_MUTE,
+ ACTION_UNBUBBLE, ACTION_SETTINGS})
private @interface Action {}
static final int ACTION_BUBBLE = 0;
static final int ACTION_HOME = 1;
@@ -128,8 +130,6 @@
mBubbleController.onUserDemotedBubbleFromNotification(mEntry);
} else {
mBubbleController.onUserCreatedBubbleFromNotification(mEntry);
- Settings.Global.putInt(
- mContext.getContentResolver(), Settings.Global.NOTIFICATION_BUBBLES, 1);
}
closeControls(v, true);
};
@@ -225,7 +225,9 @@
mShortcutInfo = shortcuts.get(0);
}
- mIsBubbleable = mEntry.getBubbleMetadata() != null;
+ mIsBubbleable = mEntry.getBubbleMetadata() != null
+ && Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.NOTIFICATION_BUBBLES, 0) == 1;
mStartedAsBubble = mEntry.isBubble();
createConversationChannelIfNeeded();
@@ -382,6 +384,11 @@
((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
}
+ private boolean bubbleImportantConversations() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ BUBBLE_IMPORTANT_CONVERSATIONS, 1) == 1;
+ }
+
private void bindDelegate() {
TextView delegateView = findViewById(R.id.delegate_name);
@@ -579,6 +586,10 @@
case ACTION_FAVORITE:
mChannelToUpdate.setImportantConversation(
!mChannelToUpdate.isImportantConversation());
+ if (mChannelToUpdate.isImportantConversation()
+ && bubbleImportantConversations()) {
+ mChannelToUpdate.setAllowBubbles(true);
+ }
break;
case ACTION_MUTE:
if (mChannelToUpdate.getImportance() == IMPORTANCE_UNSPECIFIED
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index fa4bc2a..52f7c2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -19,12 +19,17 @@
import android.app.ActivityManager;
import android.app.Notification;
import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.ImageResolver;
import com.android.internal.widget.LocalImageResolver;
import com.android.internal.widget.MessagingMessage;
@@ -36,6 +41,10 @@
/**
* Custom resolver with built-in image cache for image messages.
+ *
+ * If the URL points to a bitmap that's larger than the maximum width or height, the bitmap
+ * will be resized down to that maximum size before being cached. See {@link #getMaxImageWidth()},
+ * {@link #getMaxImageHeight()}, and {@link #resolveImage(Uri)} for the downscaling implementation.
*/
public class NotificationInlineImageResolver implements ImageResolver {
private static final String TAG = NotificationInlineImageResolver.class.getSimpleName();
@@ -44,6 +53,13 @@
private final ImageCache mImageCache;
private Set<Uri> mWantedUriSet;
+ // max allowed bitmap width, in pixels
+ @VisibleForTesting
+ protected int mMaxImageWidth;
+ // max allowed bitmap height, in pixels
+ @VisibleForTesting
+ protected int mMaxImageHeight;
+
/**
* Constructor.
* @param context Context.
@@ -56,6 +72,8 @@
if (mImageCache != null) {
mImageCache.setImageResolver(this);
}
+
+ updateMaxImageSizes();
}
/**
@@ -66,14 +84,49 @@
return mImageCache != null && !ActivityManager.isLowRamDeviceStatic();
}
+ private boolean isLowRam() {
+ return ActivityManager.isLowRamDeviceStatic();
+ }
+
/**
- * To resolve image from specified uri directly.
+ * Update the maximum width and height allowed for bitmaps, ex. after a configuration change.
+ */
+ public void updateMaxImageSizes() {
+ mMaxImageWidth = getMaxImageWidth();
+ mMaxImageHeight = getMaxImageHeight();
+ }
+
+ @VisibleForTesting
+ protected int getMaxImageWidth() {
+ return mContext.getResources().getDimensionPixelSize(isLowRam()
+ ? R.dimen.notification_custom_view_max_image_width_low_ram
+ : R.dimen.notification_custom_view_max_image_width);
+ }
+
+ @VisibleForTesting
+ protected int getMaxImageHeight() {
+ return mContext.getResources().getDimensionPixelSize(isLowRam()
+ ? R.dimen.notification_custom_view_max_image_height_low_ram
+ : R.dimen.notification_custom_view_max_image_height);
+ }
+
+ @VisibleForTesting
+ protected BitmapDrawable resolveImageInternal(Uri uri) throws IOException {
+ return (BitmapDrawable) LocalImageResolver.resolveImage(uri, mContext);
+ }
+
+ /**
+ * To resolve image from specified uri directly. If the resulting image is larger than the
+ * maximum allowed size, scale it down.
* @param uri Uri of the image.
* @return Drawable of the image.
* @throws IOException Throws if failed at resolving the image.
*/
Drawable resolveImage(Uri uri) throws IOException {
- return LocalImageResolver.resolveImage(uri, mContext);
+ BitmapDrawable image = resolveImageInternal(uri);
+ Bitmap bitmap = image.getBitmap();
+ image.setBitmap(Icon.scaleDownIfNecessary(bitmap, mMaxImageWidth, mMaxImageHeight));
+ return image;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index d790cbc..84aecd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -63,7 +63,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
-import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.assist.AssistHandleViewController;
@@ -75,6 +74,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.policy.DeadZone;
@@ -869,7 +869,8 @@
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
- DockedStackExistsListener.register(mDockedListener);
+ Divider divider = Dependency.get(Divider.class);
+ divider.registerInSplitScreenListener(mDockedListener);
updateOrientationViews();
reloadNavIcons();
}
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/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index d8d96c1..0d3b09a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -163,7 +163,6 @@
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
-import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
@@ -1412,8 +1411,11 @@
if (!mRecentsOptional.isPresent()) {
return false;
}
- int dockSide = WindowManagerProxy.getInstance().getDockSide();
- if (dockSide == WindowManager.DOCKED_INVALID) {
+ Divider divider = null;
+ if (mDividerOptional.isPresent()) {
+ divider = mDividerOptional.get();
+ }
+ if (divider == null || !divider.inSplitMode()) {
final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
if (navbarPos == NAV_BAR_POS_INVALID) {
return false;
@@ -1423,16 +1425,13 @@
: SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
return mRecentsOptional.get().splitPrimaryTask(createMode, null, metricsDockAction);
} else {
- if (mDividerOptional.isPresent()) {
- Divider divider = mDividerOptional.get();
- if (divider.isMinimized() && !divider.isHomeStackResizable()) {
- // Undocking from the minimized state is not supported
- return false;
- } else {
- divider.onUndockingTask();
- if (metricsUndockAction != -1) {
- mMetricsLogger.action(metricsUndockAction);
- }
+ if (divider.isMinimized() && !divider.isHomeStackResizable()) {
+ // Undocking from the minimized state is not supported
+ return false;
+ } else {
+ divider.onUndockingTask();
+ if (metricsUndockAction != -1) {
+ mMetricsLogger.action(metricsUndockAction);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index f6e1681..cebcf76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -15,24 +15,18 @@
*/
package com.android.systemui.statusbar.policy;
-import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
-import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
-
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.net.NetworkCapabilities;
import android.os.Handler;
import android.os.Looper;
-import android.os.Message;
import android.provider.Settings.Global;
-import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation;
import android.telephony.CdmaEriInformation;
import android.telephony.CellSignalStrength;
import android.telephony.CellSignalStrengthCdma;
-import android.telephony.DataSpecificRegistrationInfo;
-import android.telephony.NetworkRegistrationInfo;
+import android.telephony.DisplayInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -60,16 +54,10 @@
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public class MobileSignalController extends SignalController<
MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> {
-
- // The message to display Nr5G icon gracfully by CarrierConfig timeout
- private static final int MSG_DISPLAY_GRACE = 1;
-
private final TelephonyManager mPhone;
private final SubscriptionDefaults mDefaults;
private final String mNetworkNameDefault;
@@ -86,19 +74,15 @@
// Since some pieces of the phone state are interdependent we store it locally,
// this could potentially become part of MobileState for simplification/complication
// of code.
- private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- private boolean mCA = false;
- private boolean mCAPlus = false;
private int mDataState = TelephonyManager.DATA_DISCONNECTED;
+ private DisplayInfo mDisplayInfo = new DisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ DisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
private ServiceState mServiceState;
private SignalStrength mSignalStrength;
private MobileIconGroup mDefaultIcons;
private Config mConfig;
- private final Handler mDisplayGraceHandler;
@VisibleForTesting
boolean mInflateSignalStrengths = false;
- @VisibleForTesting
- boolean mIsShowingIconGracefully = false;
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
@@ -136,16 +120,6 @@
updateTelephony();
}
};
-
- mDisplayGraceHandler = new Handler(receiverLooper) {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MSG_DISPLAY_GRACE) {
- mIsShowingIconGracefully = false;
- updateTelephony();
- }
- }
- };
}
public void setConfiguration(Config config) {
@@ -190,7 +164,8 @@
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY
| PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE
- | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+ | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE
+ | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED);
mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
true, mObserver);
mContext.getContentResolver().registerContentObserver(Global.getUriFor(
@@ -268,52 +243,60 @@
mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_LTE),
TelephonyIcons.FOUR_G);
if (mConfig.hideLtePlus) {
- mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
- TelephonyIcons.FOUR_G);
+ mNetworkToIconLookup.put(toDisplayIconKey(
+ DisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA), TelephonyIcons.FOUR_G);
} else {
- mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
- TelephonyIcons.FOUR_G_PLUS);
+ mNetworkToIconLookup.put(toDisplayIconKey(
+ DisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA), TelephonyIcons.FOUR_G_PLUS);
}
} else {
mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_LTE),
TelephonyIcons.LTE);
if (mConfig.hideLtePlus) {
- mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
- TelephonyIcons.LTE);
+ mNetworkToIconLookup.put(toDisplayIconKey(
+ DisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA), TelephonyIcons.LTE);
} else {
- mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
- TelephonyIcons.LTE_PLUS);
+ mNetworkToIconLookup.put(toDisplayIconKey(
+ DisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA), TelephonyIcons.LTE_PLUS);
}
}
- mNetworkToIconLookup.put(toIconKeyCAPlus(TelephonyManager.NETWORK_TYPE_LTE),
- TelephonyIcons.LTE_CA_5G_E);
mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_IWLAN),
TelephonyIcons.WFC);
+ mNetworkToIconLookup.put(toDisplayIconKey(
+ DisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO), TelephonyIcons.LTE_CA_5G_E);
+ mNetworkToIconLookup.put(toDisplayIconKey(
+ DisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA), TelephonyIcons.NR_5G);
+ mNetworkToIconLookup.put(toDisplayIconKey(
+ DisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE), TelephonyIcons.NR_5G_PLUS);
}
private String getIconKey() {
- if (mCA) {
- return toIconKeyCA(mDataNetType);
- } else if (mCAPlus) {
- return toIconKeyCAPlus(mDataNetType);
+ if (mDisplayInfo.getOverrideNetworkType() == DisplayInfo.OVERRIDE_NETWORK_TYPE_NONE) {
+ return toIconKey(mDisplayInfo.getNetworkType());
} else {
- return toIconKey(mDataNetType);
+ return toDisplayIconKey(mDisplayInfo.getOverrideNetworkType());
}
}
- // Some specific carriers have 5GE network which is special CA network.
- private String toIconKeyCAPlus(@Annotation.NetworkType int networkType) {
- return toIconKeyCA(networkType) + "_Plus";
- }
-
- private String toIconKeyCA(@Annotation.NetworkType int networkType) {
- return toIconKey(networkType) + "_CA";
- }
-
private String toIconKey(@Annotation.NetworkType int networkType) {
return Integer.toString(networkType);
}
+ private String toDisplayIconKey(@Annotation.OverrideNetworkType int displayNetworkType) {
+ switch (displayNetworkType) {
+ case DisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA:
+ return toIconKey(TelephonyManager.NETWORK_TYPE_LTE) + "_CA";
+ case DisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO:
+ return toIconKey(TelephonyManager.NETWORK_TYPE_LTE) + "_CA_Plus";
+ case DisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA:
+ return "5G";
+ case DisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE:
+ return "5G_Plus";
+ default:
+ return "unsupported";
+ }
+ }
+
private void updateInflateSignalStrength() {
mInflateSignalStrengths = SignalStrengthUtil.shouldInflateSignalStrength(mContext,
mSubscriptionInfo.getSubscriptionId());
@@ -465,26 +448,6 @@
}
}
- private boolean isCarrierSpecificDataIcon() {
- if (mConfig.patternOfCarrierSpecificDataIcon == null
- || mConfig.patternOfCarrierSpecificDataIcon.length() == 0) {
- return false;
- }
-
- Pattern stringPattern = Pattern.compile(mConfig.patternOfCarrierSpecificDataIcon);
- String[] operatorNames = new String[]{mServiceState.getOperatorAlphaLongRaw(),
- mServiceState.getOperatorAlphaShortRaw()};
- for (String opName : operatorNames) {
- if (!TextUtils.isEmpty(opName)) {
- Matcher matcher = stringPattern.matcher(opName);
- if (matcher.find()) {
- return true;
- }
- }
- }
- return false;
- }
-
/**
* Updates the network's name based on incoming spn and plmn.
*/
@@ -538,18 +501,18 @@
}
/**
- * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
- * mDataState, and mSimState. It should be called any time one of these is updated.
+ * Updates the current state based on mServiceState, mSignalStrength, mDataState,
+ * mDisplayInfo, and mSimState. It should be called any time one of these is updated.
* This will call listeners if necessary.
*/
private final void updateTelephony() {
if (DEBUG) {
Log.d(mTag, "updateTelephonySignalStrength: hasService=" +
- Utils.isInService(mServiceState) + " ss=" + mSignalStrength);
+ Utils.isInService(mServiceState) + " ss=" + mSignalStrength
+ + " displayInfo=" + mDisplayInfo);
}
checkDefaultData();
- mCurrentState.connected = Utils.isInService(mServiceState)
- && mSignalStrength != null;
+ mCurrentState.connected = Utils.isInService(mServiceState) && mSignalStrength != null;
if (mCurrentState.connected) {
if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
mCurrentState.level = getCdmaLevel();
@@ -558,17 +521,8 @@
}
}
- // When the device is camped on a 5G Non-Standalone network, the data network type is still
- // LTE. In this case, we first check which 5G icon should be shown.
- MobileIconGroup nr5GIconGroup = getNr5GIconGroup();
- if (mConfig.nrIconDisplayGracePeriodMs > 0) {
- nr5GIconGroup = adjustNr5GIconGroupByDisplayGraceTime(nr5GIconGroup);
- }
-
String iconKey = getIconKey();
- if (nr5GIconGroup != null) {
- mCurrentState.iconGroup = nr5GIconGroup;
- } else if (mNetworkToIconLookup.get(iconKey) != null) {
+ if (mNetworkToIconLookup.get(iconKey) != null) {
mCurrentState.iconGroup = mNetworkToIconLookup.get(iconKey);
} else {
mCurrentState.iconGroup = mDefaultIcons;
@@ -580,8 +534,7 @@
if (isCarrierNetworkChangeActive()) {
mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
} else if (isDataDisabled() && !mConfig.alwaysShowDataRatIcon) {
- if (mSubscriptionInfo.getSubscriptionId()
- != mDefaults.getDefaultDataSubId()) {
+ if (mSubscriptionInfo.getSubscriptionId() != mDefaults.getDefaultDataSubId()) {
mCurrentState.iconGroup = TelephonyIcons.NOT_DEFAULT_DATA;
} else {
mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
@@ -623,91 +576,6 @@
notifyListenersIfNecessary();
}
- private int getNrState(ServiceState serviceState) {
- NetworkRegistrationInfo nri = serviceState.getNetworkRegistrationInfo(
- NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
- if (nri != null) {
- return nri.getNrState();
- }
- return NetworkRegistrationInfo.NR_STATE_NONE;
- }
-
- private MobileIconGroup getNr5GIconGroup() {
- if (mServiceState == null) return null;
-
- int nrState = getNrState(mServiceState);
- if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
- // Check if the NR 5G is using millimeter wave and the icon is config.
- if (mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE) {
- if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED_MMWAVE)) {
- return mConfig.nr5GIconMap.get(Config.NR_CONNECTED_MMWAVE);
- }
- }
-
- // If NR 5G is not using millimeter wave or there is no icon for millimeter wave, we
- // check the normal 5G icon.
- if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED)) {
- return mConfig.nr5GIconMap.get(Config.NR_CONNECTED);
- }
- } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
- if (mCurrentState.activityDormant) {
- if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED_RRC_IDLE)) {
- return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED_RRC_IDLE);
- }
- } else {
- if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED_RRC_CON)) {
- return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED_RRC_CON);
- }
- }
- } else if (nrState == NetworkRegistrationInfo.NR_STATE_RESTRICTED) {
- if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) {
- return mConfig.nr5GIconMap.get(Config.NR_RESTRICTED);
- }
- }
-
- return null;
- }
-
- /**
- * The function to adjust MobileIconGroup depend on CarrierConfig's time
- * nextIconGroup == null imply next state could be 2G/3G/4G/4G+
- * nextIconGroup != null imply next state will be 5G/5G+
- * Flag : mIsShowingIconGracefully
- * ---------------------------------------------------------------------------------
- * | Last state | Current state | Flag | Action |
- * ---------------------------------------------------------------------------------
- * | 5G/5G+ | 2G/3G/4G/4G+ | true | return previous IconGroup |
- * | 5G/5G+ | 5G/5G+ | true | Bypass |
- * | 2G/3G/4G/4G+ | 5G/5G+ | true | Bypass |
- * | 2G/3G/4G/4G+ | 2G/3G/4G/4G+ | true | Bypass |
- * | SS.connected | SS.disconnect | T|F | Reset timer |
- * |NETWORK_TYPE_LTE|!NETWORK_TYPE_LTE| T|F | Reset timer |
- * | 5G/5G+ | 2G/3G/4G/4G+ | false| Bypass |
- * | 5G/5G+ | 5G/5G+ | false| Bypass |
- * | 2G/3G/4G/4G+ | 5G/5G+ | false| SendMessageDelay(time), flag->true |
- * | 2G/3G/4G/4G+ | 2G/3G/4G/4G+ | false| Bypass |
- * ---------------------------------------------------------------------------------
- */
- private MobileIconGroup adjustNr5GIconGroupByDisplayGraceTime(
- MobileIconGroup candidateIconGroup) {
- if (mIsShowingIconGracefully && candidateIconGroup == null) {
- candidateIconGroup = (MobileIconGroup) mCurrentState.iconGroup;
- } else if (!mIsShowingIconGracefully && candidateIconGroup != null
- && mLastState.iconGroup != candidateIconGroup) {
- mDisplayGraceHandler.sendMessageDelayed(
- mDisplayGraceHandler.obtainMessage(MSG_DISPLAY_GRACE),
- mConfig.nrIconDisplayGracePeriodMs);
- mIsShowingIconGracefully = true;
- } else if (!mCurrentState.connected || mDataState == TelephonyManager.DATA_DISCONNECTED
- || candidateIconGroup == null) {
- mDisplayGraceHandler.removeMessages(MSG_DISPLAY_GRACE);
- mIsShowingIconGracefully = false;
- candidateIconGroup = null;
- }
-
- return candidateIconGroup;
- }
-
boolean isDataDisabled() {
return !mPhone.isDataConnectionEnabled();
}
@@ -718,8 +586,6 @@
|| activity == TelephonyManager.DATA_ACTIVITY_IN;
mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
|| activity == TelephonyManager.DATA_ACTIVITY_OUT;
- mCurrentState.activityDormant = activity == TelephonyManager.DATA_ACTIVITY_DORMANT;
-
notifyListenersIfNecessary();
}
@@ -729,13 +595,10 @@
pw.println(" mSubscription=" + mSubscriptionInfo + ",");
pw.println(" mServiceState=" + mServiceState + ",");
pw.println(" mSignalStrength=" + mSignalStrength + ",");
+ pw.println(" mDisplayInfo=" + mDisplayInfo + ",");
pw.println(" mDataState=" + mDataState + ",");
- pw.println(" mDataNetType=" + mDataNetType + ",");
- pw.println(" mCA=" + mCA + ",");
- pw.println(" mCAPlus=" + mCAPlus + ",");
pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
- pw.println(" mIsShowingIconGracefully=" + mIsShowingIconGracefully + ",");
}
class MobilePhoneStateListener extends PhoneStateListener {
@@ -760,14 +623,8 @@
+ " dataState=" + state.getDataRegistrationState());
}
mServiceState = state;
- if (mServiceState != null) {
- NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo(
- DOMAIN_PS, TRANSPORT_TYPE_WWAN);
- if (regInfo != null) {
- updateDataNetType(regInfo.getAccessNetworkTechnology());
- }
- }
- updateTelephony();
+ // onDisplayInfoChanged is invoked directly after onServiceStateChanged, so not calling
+ // updateTelephony() to prevent icon flickering in case of overrides.
}
@Override
@@ -777,35 +634,12 @@
+ " type=" + networkType);
}
mDataState = state;
- updateDataNetType(networkType);
+ if (networkType != mDisplayInfo.getNetworkType()) {
+ mDisplayInfo = new DisplayInfo(networkType, DisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
+ }
updateTelephony();
}
- private void updateDataNetType(int networkType) {
- mDataNetType = networkType;
- mCA = false;
- mCAPlus = false;
- if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE) {
- if (isCarrierSpecificDataIcon()) {
- mCAPlus = true;
- } else if (mServiceState != null && isUsingCarrierAggregation(mServiceState)) {
- mCA = true;
- }
- }
- }
-
- private boolean isUsingCarrierAggregation(ServiceState serviceState) {
- NetworkRegistrationInfo nri = serviceState.getNetworkRegistrationInfo(
- NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
- if (nri != null) {
- DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
- if (dsri != null) {
- return dsri.isUsingCarrierAggregation();
- }
- }
- return false;
- }
-
@Override
public void onDataActivity(int direction) {
if (DEBUG) {
@@ -820,7 +654,6 @@
Log.d(mTag, "onCarrierNetworkChange: active=" + active);
}
mCurrentState.carrierNetworkChangeMode = active;
-
updateTelephony();
}
@@ -830,7 +663,16 @@
updateDataSim();
updateTelephony();
}
- };
+
+ @Override
+ public void onDisplayInfoChanged(DisplayInfo displayInfo) {
+ if (DEBUG) {
+ Log.d(mTag, "onDisplayInfoChanged: displayInfo=" + displayInfo);
+ }
+ mDisplayInfo = displayInfo;
+ updateTelephony();
+ }
+ }
static class MobileIconGroup extends SignalController.IconGroup {
final int mDataContentDescription; // mContentDescriptionDataType
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 4f382e7..9003de1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -49,7 +49,6 @@
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.util.Log;
import android.util.MathUtils;
import android.util.SparseArray;
@@ -64,7 +63,6 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -72,10 +70,8 @@
import java.util.BitSet;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -846,12 +842,6 @@
pw.println(emergencyToString(mEmergencySource));
pw.println(" - config ------");
- pw.print(" patternOfCarrierSpecificDataIcon=");
- pw.println(mConfig.patternOfCarrierSpecificDataIcon);
- pw.print(" nr5GIconMap=");
- pw.println(mConfig.nr5GIconMap.toString());
- pw.print(" nrIconDisplayGracePeriodMs=");
- pw.println(mConfig.nrIconDisplayGracePeriodMs);
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.dump(pw);
@@ -1132,14 +1122,6 @@
@VisibleForTesting
static class Config {
- static final int NR_CONNECTED_MMWAVE = 1;
- static final int NR_CONNECTED = 2;
- static final int NR_NOT_RESTRICTED_RRC_IDLE = 3;
- static final int NR_NOT_RESTRICTED_RRC_CON = 4;
- static final int NR_RESTRICTED = 5;
-
- Map<Integer, MobileIconGroup> nr5GIconMap = new HashMap<>();
-
boolean showAtLeast3G = false;
boolean show4gFor3g = false;
boolean alwaysShowCdmaRssi = false;
@@ -1148,22 +1130,6 @@
boolean hspaDataDistinguishable;
boolean inflateSignalStrengths = false;
boolean alwaysShowDataRatIcon = false;
- public String patternOfCarrierSpecificDataIcon = "";
- public long nrIconDisplayGracePeriodMs;
-
- /**
- * Mapping from NR 5G status string to an integer. The NR 5G status string should match
- * those in carrier config.
- */
- private static final Map<String, Integer> NR_STATUS_STRING_TO_INDEX;
- static {
- NR_STATUS_STRING_TO_INDEX = new HashMap<>(5);
- NR_STATUS_STRING_TO_INDEX.put("connected_mmwave", NR_CONNECTED_MMWAVE);
- NR_STATUS_STRING_TO_INDEX.put("connected", NR_CONNECTED);
- NR_STATUS_STRING_TO_INDEX.put("not_restricted_rrc_idle", NR_NOT_RESTRICTED_RRC_IDLE);
- NR_STATUS_STRING_TO_INDEX.put("not_restricted_rrc_con", NR_NOT_RESTRICTED_RRC_CON);
- NR_STATUS_STRING_TO_INDEX.put("restricted", NR_RESTRICTED);
- }
static Config readConfig(Context context) {
Config config = new Config();
@@ -1192,64 +1158,9 @@
CarrierConfigManager.KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL);
config.hideLtePlus = b.getBoolean(
CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL);
- config.patternOfCarrierSpecificDataIcon = b.getString(
- CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING);
- String nr5GIconConfiguration =
- b.getString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING);
- if (!TextUtils.isEmpty(nr5GIconConfiguration)) {
- String[] nr5GIconConfigPairs = nr5GIconConfiguration.trim().split(",");
- for (String pair : nr5GIconConfigPairs) {
- add5GIconMapping(pair, config);
- }
- }
- setDisplayGraceTime(
- b.getInt(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT),
- config);
}
return config;
}
-
- /**
- * Add a mapping from NR 5G status to the 5G icon. All the icon resources come from
- * {@link TelephonyIcons}.
- *
- * @param keyValuePair the NR 5G status and icon name separated by a colon.
- * @param config container that used to store the parsed configs.
- */
- @VisibleForTesting
- static void add5GIconMapping(String keyValuePair, Config config) {
- String[] kv = (keyValuePair.trim().toLowerCase()).split(":");
-
- if (kv.length != 2) {
- if (DEBUG) Log.e(TAG, "Invalid 5G icon configuration, config = " + keyValuePair);
- return;
- }
-
- String key = kv[0], value = kv[1];
-
- // There is no icon config for the specific 5G status.
- if (value.equals("none")) return;
-
- if (NR_STATUS_STRING_TO_INDEX.containsKey(key)
- && TelephonyIcons.ICON_NAME_TO_ICON.containsKey(value)) {
- config.nr5GIconMap.put(
- NR_STATUS_STRING_TO_INDEX.get(key),
- TelephonyIcons.ICON_NAME_TO_ICON.get(value));
- }
- }
-
- /**
- * Set display gracefully period time(MS) depend on carrierConfig KEY
- * KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, and this function will convert to ms.
- * {@link CarrierConfigManager}.
- *
- * @param time showing 5G icon gracefully in the period of the time(SECOND)
- * @param config container that used to store the parsed configs.
- */
- @VisibleForTesting
- static void setDisplayGraceTime(int time, Config config) {
- config.nrIconDisplayGracePeriodMs = time * DateUtils.SECOND_IN_MILLIS;
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index 749b56c..3a45691 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -261,7 +261,6 @@
boolean enabled;
boolean activityIn;
boolean activityOut;
- public boolean activityDormant;
int level;
IconGroup iconGroup;
int inetCondition;
@@ -278,7 +277,6 @@
inetCondition = state.inetCondition;
activityIn = state.activityIn;
activityOut = state.activityOut;
- activityDormant = state.activityDormant;
rssi = state.rssi;
time = state.time;
}
@@ -302,7 +300,6 @@
.append("iconGroup=").append(iconGroup).append(',')
.append("activityIn=").append(activityIn).append(',')
.append("activityOut=").append(activityOut).append(',')
- .append("activityDormant=").append(activityDormant).append(',')
.append("rssi=").append(rssi).append(',')
.append("lastModified=").append(sSDF.format(time));
}
@@ -320,7 +317,6 @@
&& other.iconGroup == iconGroup
&& other.activityIn == activityIn
&& other.activityOut == activityOut
- && other.activityDormant == activityDormant
&& other.rssi == rssi;
}
}
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/src/com/android/systemui/wm/DisplayController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayController.java
index bc24ad0..c66f07dd 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayController.java
@@ -101,6 +101,11 @@
return;
}
Display display = getDisplay(displayId);
+ if (display == null) {
+ Slog.w(TAG, "Skipping Display Configuration change on invalid"
+ + " display. It may have been removed.");
+ return;
+ }
Context perDisplayContext = mContext;
if (displayId != Display.DEFAULT_DISPLAY) {
perDisplayContext = mContext.createDisplayContext(display);
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 7dad05d..1b62cbf 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -34,6 +34,7 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.systemui.TransactionPool;
import com.android.systemui.dagger.qualifiers.Main;
import java.util.ArrayList;
@@ -48,8 +49,8 @@
public class DisplayImeController implements DisplayController.OnDisplaysChangedListener {
private static final String TAG = "DisplayImeController";
- static final int ANIMATION_DURATION_SHOW_MS = 275;
- static final int ANIMATION_DURATION_HIDE_MS = 340;
+ public static final int ANIMATION_DURATION_SHOW_MS = 275;
+ public static final int ANIMATION_DURATION_HIDE_MS = 340;
static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
private static final int DIRECTION_NONE = 0;
private static final int DIRECTION_SHOW = 1;
@@ -57,6 +58,7 @@
SystemWindows mSystemWindows;
final Handler mHandler;
+ final TransactionPool mTransactionPool;
final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
@@ -64,9 +66,10 @@
@Inject
public DisplayImeController(SystemWindows syswin, DisplayController displayController,
- @Main Handler mainHandler) {
+ @Main Handler mainHandler, TransactionPool transactionPool) {
mHandler = mainHandler;
mSystemWindows = syswin;
+ mTransactionPool = transactionPool;
displayController.addDisplayWindowListener(this);
}
@@ -255,18 +258,18 @@
show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
mAnimation.addUpdateListener(animation -> {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
float value = (float) animation.getAnimatedValue();
t.setPosition(mImeSourceControl.getLeash(), x, value);
dispatchPositionChanged(mDisplayId, imeTop(imeSource, value), t);
t.apply();
- t.close();
+ mTransactionPool.release(t);
});
mAnimation.setInterpolator(INTERPOLATOR);
mAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setPosition(mImeSourceControl.getLeash(), x, startY);
dispatchStartPositioning(mDisplayId, imeTop(imeSource, startY),
imeTop(imeSource, endY), mAnimationDirection == DIRECTION_SHOW,
@@ -275,11 +278,11 @@
t.show(mImeSourceControl.getLeash());
}
t.apply();
- t.close();
+ mTransactionPool.release(t);
}
@Override
public void onAnimationEnd(Animator animation) {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setPosition(mImeSourceControl.getLeash(), x, endY);
dispatchEndPositioning(mDisplayId, imeTop(imeSource, endY),
mAnimationDirection == DIRECTION_SHOW, t);
@@ -287,7 +290,7 @@
t.hide(mImeSourceControl.getLeash());
}
t.apply();
- t.close();
+ mTransactionPool.release(t);
mAnimationDirection = DIRECTION_NONE;
mAnimation = null;
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
index 64b0b66..4652abf 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
@@ -35,6 +35,7 @@
import android.graphics.Rect;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.util.DisplayMetrics;
import android.util.RotationUtils;
import android.util.Size;
import android.view.Display;
@@ -191,6 +192,11 @@
return mDensityDpi;
}
+ /** Get the density scale for the display. */
+ public float density() {
+ return mDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ }
+
/** Get whether this layout is landscape. */
public boolean isLandscape() {
return mWidth > mHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
index 044a2a6..23df991 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -162,6 +162,23 @@
return pd.getWindow(windowType);
}
+ /**
+ * Gets the SurfaceControl associated with a root view. This is the same surface that backs the
+ * ViewRootImpl.
+ */
+ public SurfaceControl getViewSurface(View rootView) {
+ for (int i = 0; i < mPerDisplay.size(); ++i) {
+ for (int iWm = 0; iWm < mPerDisplay.valueAt(i).mWwms.size(); ++iWm) {
+ SurfaceControl out =
+ mPerDisplay.valueAt(i).mWwms.get(iWm).getSurfaceControlForWindow(rootView);
+ if (out != null) {
+ return out;
+ }
+ }
+ }
+ return null;
+ }
+
private class PerDisplay {
final int mDisplayId;
private final SparseArray<SysUiWindowManager> mWwms = new SparseArray<>();
@@ -256,6 +273,10 @@
void updateConfiguration(Configuration configuration) {
setConfiguration(configuration);
}
+
+ SurfaceControl getSurfaceControlForWindow(View rootView) {
+ return getSurfaceControl(rootView);
+ }
}
class ContainerWindow extends IWindow.Stub {
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index e5f56d4..38da21e 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -46,6 +46,9 @@
# UI it doesn't own. This is necessary to allow screenshots to be taken
LOCAL_CERTIFICATE := platform
+LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := AndroidManifest-base.xml
+
# Provide jack a list of classes to exclude from code coverage.
# This is needed because the SystemUITests compile SystemUI source directly, rather than using
# LOCAL_INSTRUMENTATION_FOR := SystemUI.
diff --git a/packages/SystemUI/tests/AndroidManifest-base.xml b/packages/SystemUI/tests/AndroidManifest-base.xml
new file mode 100644
index 0000000..f08d3d2
--- /dev/null
+++ b/packages/SystemUI/tests/AndroidManifest-base.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:sharedUserId="android.uid.system"
+ package="com.android.systemui.tests" />
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index c51624b..12c7048 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:sharedUserId="android.uid.system"
- package="com.android.systemui.tests">
+ package="com.android.systemui" >
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
@@ -55,11 +55,6 @@
<application android:debuggable="true" android:largeHeap="true">
<uses-library android:name="android.test.runner" />
- <activity android:name="com.android.systemui.screenshot.ScreenshotStubActivity" />
-
- <service
- android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService"
- android:process=":killable" />
<receiver android:name="com.android.systemui.SliceBroadcastRelayHandlerTest$Receiver">
<intent-filter>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 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/carrier/CellSignalStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/CellSignalStateTest.kt
new file mode 100644
index 0000000..75be74b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/CellSignalStateTest.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.carrier
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertNotSame
+import org.junit.Assert.assertSame
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class CellSignalStateTest : SysuiTestCase() {
+
+ @Test
+ fun testChangeVisibility_sameObject() {
+ val c = CellSignalState()
+
+ val other = c.changeVisibility(c.visible)
+
+ assertSame(c, other)
+ }
+
+ @Test
+ fun testChangeVisibility_otherObject() {
+ val c = CellSignalState()
+
+ val other = c.changeVisibility(!c.visible)
+
+ assertNotSame(c, other)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index 715087d..fa02231 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.qs;
+package com.android.systemui.qs.carrier;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
new file mode 100644
index 0000000..022dc84
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.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 com.android.systemui.qs.carrier;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class QSCarrierTest extends SysuiTestCase {
+
+ private QSCarrier mQSCarrier;
+ private TestableLooper mTestableLooper;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestableLooper = TestableLooper.get(this);
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ mTestableLooper.runWithLooper(() ->
+ mQSCarrier = (QSCarrier) inflater.inflate(R.layout.qs_carrier, null));
+ }
+
+ @Test
+ public void testUpdateState_first() {
+ CellSignalState c = new CellSignalState(true, 0, "", "", false);
+
+ assertTrue(mQSCarrier.updateState(c));
+ }
+
+ @Test
+ public void testUpdateState_same() {
+ CellSignalState c = new CellSignalState(true, 0, "", "", false);
+
+ assertTrue(mQSCarrier.updateState(c));
+ assertFalse(mQSCarrier.updateState(c));
+ }
+
+ @Test
+ public void testUpdateState_changed() {
+ CellSignalState c = new CellSignalState(true, 0, "", "", false);
+
+ assertTrue(mQSCarrier.updateState(c));
+
+ CellSignalState other = c.changeVisibility(false);
+
+ assertTrue(mQSCarrier.updateState(other));
+ }
+}
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/screenshot/ScreenshotStubActivity.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java
deleted file mode 100644
index 0b871e4..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.screenshot;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-import com.android.systemui.tests.R;
-
-/**
- * A stub activity used in {@link ScreenshotTest}.
- */
-public class ScreenshotStubActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- }
-}
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 c6b496d..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)
)
@@ -145,6 +148,50 @@
}
@Test
+ fun testSort_importantPeople() {
+ whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
+ val aN = Notification.Builder(mContext, "test")
+ .setStyle(Notification.MessagingStyle(""))
+ .build()
+ val a = NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(aN)
+ .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 b = NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .setPkg("pkg2")
+ .setOpPkg("pkg2")
+ .setTag("tag")
+ .setNotification(bN)
+ .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),
+ rankingManager.updateRanking(null, listOf(a, b), "test"))
+ }
+
+ @Test
fun testSort_properlySetsAlertingBucket() {
val notif = Notification.Builder(mContext, "test") .build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 27b263f..138ea39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -21,6 +21,8 @@
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
+import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
+import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@@ -55,6 +57,7 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
+import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -449,6 +452,7 @@
@Test
public void testBindNotification_bubbleActionVisibleWhenCanBubble() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, 1);
mNotificationInfo.bindNotification(
mShortcutManager,
mLauncherApps,
@@ -469,7 +473,8 @@
}
@Test
- public void testBindNotification_bubbleActionVisibleWhenCannotBubble() {
+ public void testBindNotification_bubbleAction_noBubbleMetadata() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, 1);
mNotificationInfo.bindNotification(
mShortcutManager,
mLauncherApps,
@@ -490,6 +495,28 @@
}
@Test
+ public void testBindNotification_bubbleActionGloballyOff() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, 0);
+ mNotificationInfo.bindNotification(
+ mShortcutManager,
+ mLauncherApps,
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mBubbleEntry,
+ null,
+ null,
+ null,
+ mIconFactory,
+ true);
+
+ View bubbleView = mNotificationInfo.findViewById(R.id.bubble);
+ assertEquals(View.GONE, bubbleView.getVisibility());
+ }
+
+ @Test
public void testAddToHome() throws Exception {
when(mShortcutManager.isRequestPinShortcutSupported()).thenReturn(true);
@@ -550,6 +577,7 @@
@Test
public void testBubble_promotesBubble() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, 1);
mNotificationChannel.setAllowBubbles(false);
mConversationChannel.setAllowBubbles(false);
@@ -584,6 +612,7 @@
@Test
public void testBubble_demotesBubble() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, 1);
mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE;
mNotificationInfo.bindNotification(
@@ -617,6 +646,7 @@
@Test
public void testBubble_noChannelChange() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, 1);
mNotificationInfo.bindNotification(
mShortcutManager,
mLauncherApps,
@@ -645,7 +675,11 @@
}
@Test
- public void testFavorite_favorite() throws Exception {
+ public void testFavorite_favorite_noBubble() throws Exception {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ BUBBLE_IMPORTANT_CONVERSATIONS, 0);
+ mNotificationChannel.setAllowBubbles(false);
+ mConversationChannel.setAllowBubbles(false);
mNotificationInfo.bindNotification(
mShortcutManager,
mLauncherApps,
@@ -673,6 +707,44 @@
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), anyInt(), captor.capture());
assertTrue(captor.getValue().isImportantConversation());
+ assertFalse(captor.getValue().canBubble());
+ verify(mBubbleController, never()).onUserCreatedBubbleFromNotification(mEntry);
+ }
+
+ @Test
+ public void testFavorite_favorite_bubble() throws Exception {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ BUBBLE_IMPORTANT_CONVERSATIONS, 1);
+ mNotificationChannel.setAllowBubbles(false);
+ mConversationChannel.setAllowBubbles(false);
+ mNotificationInfo.bindNotification(
+ mShortcutManager,
+ mLauncherApps,
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ null,
+ null,
+ null,
+ mIconFactory,
+ true);
+
+ ImageButton fave = mNotificationInfo.findViewById(R.id.fave);
+ assertEquals(mContext.getString(R.string.notification_conversation_unfavorite),
+ fave.getContentDescription().toString());
+
+ fave.performClick();
+ mTestableLooper.processAllMessages();
+
+ ArgumentCaptor<NotificationChannel> captor =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), anyInt(), captor.capture());
+ assertTrue(captor.getValue().isImportantConversation());
+ assertTrue(captor.getValue().canBubble());
}
@Test
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/notification/row/NotificationInlineImageResolverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
new file mode 100644
index 0000000..7f48cd1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.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 com.android.systemui.statusbar.notification.row;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationInlineImageResolverTest extends SysuiTestCase {
+
+ NotificationInlineImageResolver mResolver;
+ Bitmap mBitmap;
+ BitmapDrawable mBitmapDrawable;
+ Uri mUri;
+
+ @Before
+ public void setup() {
+ mResolver = spy(new NotificationInlineImageResolver(mContext, null));
+ mBitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+ mBitmapDrawable = new BitmapDrawable(mContext.getResources(), mBitmap);
+ mUri = mock(Uri.class);
+ }
+
+ @Test
+ public void refreshMaxImageSizes() {
+ assertNotEquals("Starts different height", mResolver.mMaxImageHeight, 20);
+ assertNotEquals("Starts different width", mResolver.mMaxImageWidth, 15);
+
+ doReturn(20).when(mResolver).getMaxImageHeight();
+ doReturn(15).when(mResolver).getMaxImageWidth();
+
+ mResolver.updateMaxImageSizes();
+
+ assertEquals("Height matches new config", mResolver.mMaxImageHeight, 20);
+ assertEquals("Width matches new config", mResolver.mMaxImageWidth, 15);
+ }
+
+ @Test
+ public void resolveImage_sizeTooBig() throws IOException {
+ doReturn(mBitmapDrawable).when(mResolver).resolveImageInternal(mUri);
+ mResolver.mMaxImageHeight = 5;
+ mResolver.mMaxImageWidth = 5;
+
+ // original bitmap size is 10x10
+ BitmapDrawable resolved = (BitmapDrawable) mResolver.resolveImage(mUri);
+ Bitmap resolvedBitmap = resolved.getBitmap();
+ assertEquals("Bitmap width reduced", 5, resolvedBitmap.getWidth());
+ assertEquals("Bitmap height reduced", 5, resolvedBitmap.getHeight());
+ assertNotSame("Bitmap replaced", resolvedBitmap, mBitmap);
+ }
+
+ @Test
+ public void resolveImage_sizeOK() throws IOException {
+ doReturn(mBitmapDrawable).when(mResolver).resolveImageInternal(mUri);
+ mResolver.mMaxImageWidth = 15;
+ mResolver.mMaxImageHeight = 15;
+
+ // original bitmap size is 10x10
+ BitmapDrawable resolved = (BitmapDrawable) mResolver.resolveImage(mUri);
+ Bitmap resolvedBitmap = resolved.getBitmap();
+ assertEquals("Bitmap width unchanged", 10, resolvedBitmap.getWidth());
+ assertEquals("Bitmap height unchanged", 10, resolvedBitmap.getHeight());
+ assertSame("Bitmap not replaced", resolvedBitmap, mBitmap);
+ }
+}
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/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index e5ee439..d81b8c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -50,6 +50,7 @@
import android.os.Binder;
import android.os.Handler;
import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -256,7 +257,8 @@
mDependency.injectTestDependency(NotificationFilter.class, mNotificationFilter);
IPowerManager powerManagerService = mock(IPowerManager.class);
- mPowerManager = new PowerManager(mContext, powerManagerService,
+ IThermalService thermalService = mock(IThermalService.class);
+ mPowerManager = new PowerManager(mContext, powerManagerService, thermalService,
Handler.createAsync(Looper.myLooper()));
mNotificationInterruptionStateProvider =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 9a0e97a..a0d551c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -45,6 +45,7 @@
import android.provider.Settings.Global;
import android.telephony.CdmaEriInformation;
import android.telephony.CellSignalStrength;
+import android.telephony.DisplayInfo;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
@@ -96,6 +97,7 @@
protected PhoneStateListener mPhoneStateListener;
protected SignalStrength mSignalStrength;
protected ServiceState mServiceState;
+ protected DisplayInfo mDisplayInfo;
protected NetworkRegistrationInfo mFakeRegInfo;
protected ConnectivityManager mMockCm;
protected WifiManager mMockWm;
@@ -159,6 +161,7 @@
mSignalStrength = mock(SignalStrength.class);
mServiceState = mock(ServiceState.class);
+ mDisplayInfo = mock(DisplayInfo.class);
mFakeRegInfo = new NetworkRegistrationInfo.Builder()
.setTransportType(TRANSPORT_TYPE_WWAN)
@@ -167,6 +170,9 @@
.build();
doReturn(mFakeRegInfo).when(mServiceState)
.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN);
+ doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mDisplayInfo).getNetworkType();
+ doReturn(DisplayInfo.OVERRIDE_NETWORK_TYPE_NONE).when(mDisplayInfo)
+ .getOverrideNetworkType();
mEriInformation = new CdmaEriInformation(CdmaEriInformation.ERI_OFF,
CdmaEriInformation.ERI_ICON_MODE_NORMAL);
@@ -260,33 +266,6 @@
NetworkCapabilities.TRANSPORT_CELLULAR, true, true);
}
- public void setupDefaultNr5GIconConfiguration() {
- NetworkControllerImpl.Config.add5GIconMapping("connected_mmwave:5g_plus", mConfig);
- NetworkControllerImpl.Config.add5GIconMapping("connected:5g", mConfig);
- }
-
- public void setupNr5GIconConfigurationForNotRestrictedRrcCon() {
- NetworkControllerImpl.Config.add5GIconMapping("connected_mmwave:5g_plus", mConfig);
- NetworkControllerImpl.Config.add5GIconMapping("connected:5g_plus", mConfig);
- NetworkControllerImpl.Config.add5GIconMapping("not_restricted_rrc_con:5g", mConfig);
- }
-
- public void setupNr5GIconConfigurationForNotRestrictedRrcIdle() {
- NetworkControllerImpl.Config.add5GIconMapping("connected_mmwave:5g_plus", mConfig);
- NetworkControllerImpl.Config.add5GIconMapping("connected:5g_plus", mConfig);
- NetworkControllerImpl.Config.add5GIconMapping("not_restricted_rrc_idle:5g", mConfig);
- }
-
- public void setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds() {
- final int enableDisplayGraceTimeSec = 30;
- NetworkControllerImpl.Config.setDisplayGraceTime(enableDisplayGraceTimeSec, mConfig);
- }
-
- public void setupDefaultNr5GIconDisplayGracePeriodTime_disabled() {
- final int disableDisplayGraceTimeSec = 0;
- NetworkControllerImpl.Config.setDisplayGraceTime(disableDisplayGraceTimeSec, mConfig);
- }
-
public void setConnectivityViaBroadcast(
int networkType, boolean validated, boolean isConnected) {
setConnectivityCommon(networkType, validated, isConnected);
@@ -369,6 +348,7 @@
protected void updateServiceState() {
Log.d(TAG, "Sending Service State: " + mServiceState);
mPhoneStateListener.onServiceStateChanged(mServiceState);
+ mPhoneStateListener.onDisplayInfoChanged(mDisplayInfo);
}
public void updateCallState(int state) {
@@ -384,6 +364,7 @@
.build();
when(mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN))
.thenReturn(fakeRegInfo);
+ when(mDisplayInfo.getNetworkType()).thenReturn(dataNetType);
mPhoneStateListener.onDataConnectionStateChanged(dataState, dataNetType);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index a906d9f..3eb0c44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -3,17 +3,13 @@
import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.net.NetworkCapabilities;
import android.os.Looper;
import android.telephony.NetworkRegistrationInfo;
-import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -24,7 +20,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mockito;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -180,254 +175,6 @@
}
@Test
- public void testNr5GIcon_NrNotRestrictedRrcCon_show5GIcon() {
- setupNr5GIconConfigurationForNotRestrictedRrcCon();
- setupDefaultSignal();
- updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- updateDataActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
- ServiceState ss = Mockito.mock(ServiceState.class);
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED);
- mPhoneStateListener.onServiceStateChanged(ss);
-
- verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, TelephonyIcons.ICON_5G,
- true, DEFAULT_QS_SIGNAL_STRENGTH, TelephonyIcons.ICON_5G, true, true);
- }
-
- @Test
- public void testNr5GIcon_NrNotRestrictedRrcIdle_show5GIcon() {
- setupNr5GIconConfigurationForNotRestrictedRrcIdle();
- setupDefaultSignal();
- updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- updateDataActivity(TelephonyManager.DATA_ACTIVITY_DORMANT);
- ServiceState ss = Mockito.mock(ServiceState.class);
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED);
- mPhoneStateListener.onServiceStateChanged(ss);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G);
- }
-
- @Test
- public void testNr5GIcon_NrConnectedWithoutMMWave_show5GIcon() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultSignal();
- updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- ServiceState ss = Mockito.mock(ServiceState.class);
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
- mPhoneStateListener.onServiceStateChanged(ss);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G);
- }
-
- @Test
- public void testNr5GIcon_NrConnectedWithMMWave_show5GPlusIcon() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultSignal();
- updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- ServiceState ss = Mockito.mock(ServiceState.class);
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss).getNrFrequencyRange();
- mPhoneStateListener.onServiceStateChanged(ss);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G_PLUS);
- }
-
- @Test
- public void testNr5GIcon_NrRestricted_showLteIcon() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultSignal();
- updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- ServiceState ss = Mockito.mock(ServiceState.class);
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_RESTRICTED);
- mPhoneStateListener.onServiceStateChanged(mServiceState);
-
- verifyDataIndicators(TelephonyIcons.ICON_LTE);
- }
-
- @Test
- public void testNr5GIcon_displayGracePeriodTime_enabled() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
- setupDefaultSignal();
- mNetworkController.handleConfigurationChanged();
- mPhoneStateListener.onServiceStateChanged(mServiceState);
-
- ServiceState ss = Mockito.mock(ServiceState.class);
- // While nrIconDisplayGracePeriodMs > 0 & is Nr5G, mIsShowingIconGracefully should be true
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- mPhoneStateListener.onServiceStateChanged(ss);
-
- assertTrue(mConfig.nrIconDisplayGracePeriodMs > 0);
- assertTrue(mMobileSignalController.mIsShowingIconGracefully);
- }
-
- @Test
- public void testNr5GIcon_displayGracePeriodTime_disabled() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultNr5GIconDisplayGracePeriodTime_disabled();
- setupDefaultSignal();
-
- assertTrue(mConfig.nrIconDisplayGracePeriodMs == 0);
-
- // While nrIconDisplayGracePeriodMs <= 0, mIsShowingIconGracefully should be false
- setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
-
- assertFalse(mMobileSignalController.mIsShowingIconGracefully);
- }
-
- @Test
- public void testNr5GIcon_enableDisplayGracePeriodTime_showIconGracefully() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
- setupDefaultSignal();
- mNetworkController.handleConfigurationChanged();
- mPhoneStateListener.onServiceStateChanged(mServiceState);
-
- ServiceState ss = Mockito.mock(ServiceState.class);
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- mPhoneStateListener.onServiceStateChanged(ss);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G);
-
- // Enabled timer Nr5G switch to None Nr5G, showing 5G icon gracefully
- ServiceState ssLte = Mockito.mock(ServiceState.class);
- setNrState(ssLte, NetworkRegistrationInfo.NR_STATE_NONE);
- doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(ssLte).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- mPhoneStateListener.onServiceStateChanged(ssLte);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G);
- }
-
- @Test
- public void testNr5GIcon_disableDisplayGracePeriodTime_showLatestIconImmediately() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultNr5GIconDisplayGracePeriodTime_disabled();
- setupDefaultSignal();
- mNetworkController.handleConfigurationChanged();
-
- setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G);
-
- setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_NONE);
- doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
-
- verifyDataIndicators(TelephonyIcons.ICON_LTE);
- }
-
- @Test
- public void testNr5GIcon_resetDisplayGracePeriodTime_whenDataDisconnected() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
- setupDefaultSignal();
- mNetworkController.handleConfigurationChanged();
- setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G);
-
- // Disabled timer, when out of service, reset timer to display latest state
- updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_NONE);
- doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_DISCONNECTED,
- TelephonyManager.NETWORK_TYPE_UMTS);
-
- verifyDataIndicators(0);
- }
-
- @Test
- public void testNr5GIcon_enableDisplayGracePeriodTime_show5G_switching_5GPlus() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
- setupDefaultSignal();
- mNetworkController.handleConfigurationChanged();
- mPhoneStateListener.onServiceStateChanged(mServiceState);
-
- ServiceState ss5G = Mockito.mock(ServiceState.class);
- setNrState(ss5G, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss5G).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- mPhoneStateListener.onServiceStateChanged(ss5G);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G);
-
- // When timeout enabled, 5G/5G+ switching should be updated immediately
- ServiceState ss5GPlus = Mockito.mock(ServiceState.class);
- setNrState(ss5GPlus, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss5GPlus).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- mPhoneStateListener.onServiceStateChanged(ss5GPlus);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G_PLUS);
- }
-
- @Test
- public void testNr5GIcon_carrierDisabledDisplayGracePeriodTime_shouldUpdateIconImmediately() {
- setupDefaultNr5GIconConfiguration();
- setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
- setupDefaultSignal();
- mNetworkController.handleConfigurationChanged();
- mPhoneStateListener.onServiceStateChanged(mServiceState);
-
- ServiceState ss = Mockito.mock(ServiceState.class);
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED);
- doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- mPhoneStateListener.onServiceStateChanged(ss);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G);
-
- // State from NR_5G to NONE NR_5G with timeout, should show previous 5G icon
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_NONE);
- doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(ss).getNrFrequencyRange();
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
- mPhoneStateListener.onServiceStateChanged(ss);
-
- verifyDataIndicators(TelephonyIcons.ICON_5G);
-
- // Update nrIconDisplayGracePeriodMs to 0
- setupDefaultNr5GIconDisplayGracePeriodTime_disabled();
- mNetworkController.handleConfigurationChanged();
-
- // State from NR_5G to NONE NR_STATE_RESTRICTED, showing corresponding icon
- setNrState(ss, NetworkRegistrationInfo.NR_STATE_RESTRICTED);
- mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
- TelephonyManager.NETWORK_TYPE_LTE);
-
- assertTrue(mConfig.nrIconDisplayGracePeriodMs == 0);
- verifyDataIndicators(TelephonyIcons.ICON_LTE);
- }
-
- @Test
public void testDataDisabledIcon_UserNotSetup() {
setupNetworkController();
when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
@@ -488,6 +235,7 @@
.build();
when(mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN))
.thenReturn(fakeRegInfo);
+ when(mDisplayInfo.getNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_HSPA);
updateServiceState();
verifyDataIndicators(TelephonyIcons.ICON_H);
}
@@ -523,10 +271,4 @@
true, DEFAULT_QS_SIGNAL_STRENGTH, dataIcon, false,
false);
}
-
- private void setNrState(ServiceState ss, int nrState) {
- mFakeRegInfo.setNrState(nrState);
- doReturn(mFakeRegInfo).when(ss)
- .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN);
- }
}
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/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 6261def..72fe95b 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -314,9 +314,13 @@
startStateMachineUpdaters(mHandler);
startTrackDefaultNetwork();
- getWifiManager().registerSoftApCallback(
- mHandler::post /* executor */,
- new TetheringSoftApCallback());
+
+ final WifiManager wifiManager = getWifiManager();
+ if (wifiManager != null) {
+ wifiManager.registerSoftApCallback(
+ mHandler::post /* executor */,
+ new TetheringSoftApCallback());
+ }
}
private void startStateMachineUpdaters(Handler handler) {
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 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/proto/src/system_messages.proto b/proto/src/system_messages.proto
index eda3fb9..cff5504 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -252,6 +252,9 @@
// Package: android
NOTE_ID_WIFI_SIM_REQUIRED = 60;
+ // Inform the user a foreground service while-in-use permission is restricted.
+ NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION = 61;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index 265674a..c6f42f7 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -1,3 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
+qasid@google.com
diff --git a/services/api/current.txt b/services/api/current.txt
index 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 b42a258..e985ddb 100644
--- a/services/api/lint-baseline.txt
+++ b/services/api/lint-baseline.txt
@@ -3,17 +3,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/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7083281..e48ef5a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1534,7 +1534,8 @@
}
@Override
- public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
+ public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
+ int userId, String callingPackageName) {
// The basic principle is: if an app's traffic could possibly go over a
// network, without the app doing anything multinetwork-specific,
// (hence, by "default"), then include that network's capabilities in
@@ -1556,7 +1557,10 @@
NetworkAgentInfo nai = getDefaultNetwork();
NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
if (nc != null) {
- result.put(nai.network, nc);
+ result.put(
+ nai.network,
+ maybeSanitizeLocationInfoForCaller(
+ nc, Binder.getCallingUid(), callingPackageName));
}
synchronized (mVpns) {
@@ -1566,10 +1570,12 @@
Network[] networks = vpn.getUnderlyingNetworks();
if (networks != null) {
for (Network network : networks) {
- nai = getNetworkAgentInfoForNetwork(network);
- nc = getNetworkCapabilitiesInternal(nai);
+ nc = getNetworkCapabilitiesInternal(network);
if (nc != null) {
- result.put(network, nc);
+ result.put(
+ network,
+ maybeSanitizeLocationInfoForCaller(
+ nc, Binder.getCallingUid(), callingPackageName));
}
}
}
@@ -1636,20 +1642,26 @@
}
}
+ private NetworkCapabilities getNetworkCapabilitiesInternal(Network network) {
+ return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+ }
+
private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
if (nai == null) return null;
synchronized (nai) {
if (nai.networkCapabilities == null) return null;
return networkCapabilitiesRestrictedForCallerPermissions(
- nai.networkCapabilities,
- Binder.getCallingPid(), Binder.getCallingUid());
+ nai.networkCapabilities, Binder.getCallingPid(), Binder.getCallingUid());
}
}
@Override
- public NetworkCapabilities getNetworkCapabilities(Network network) {
+ public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
+ mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName);
enforceAccessPermission();
- return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+ return maybeSanitizeLocationInfoForCaller(
+ getNetworkCapabilitiesInternal(network),
+ Binder.getCallingUid(), callingPackageName);
}
@VisibleForTesting
@@ -1665,20 +1677,34 @@
}
newNc.setAdministratorUids(Collections.EMPTY_LIST);
- maybeSanitizeLocationInfoForCaller(newNc, callerUid);
-
return newNc;
}
- private void maybeSanitizeLocationInfoForCaller(
- NetworkCapabilities nc, int callerUid) {
- // TODO(b/142072839): Conditionally reset the owner UID if the following
- // conditions are not met:
- // 1. The destination app is the network owner
- // 2. The destination app has the ACCESS_COARSE_LOCATION permission granted
- // if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted
- // 3. The user's location toggle is on
- nc.setOwnerUid(INVALID_UID);
+ @VisibleForTesting
+ @Nullable
+ NetworkCapabilities maybeSanitizeLocationInfoForCaller(
+ @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
+ if (nc == null) {
+ return null;
+ }
+ final NetworkCapabilities newNc = new NetworkCapabilities(nc);
+ if (callerUid != newNc.getOwnerUid()) {
+ newNc.setOwnerUid(INVALID_UID);
+ return newNc;
+ }
+
+ Binder.withCleanCallingIdentity(
+ () -> {
+ if (!mLocationPermissionChecker.checkLocationPermission(
+ callerPkgName, null /* featureId */, callerUid, null /* message */)) {
+ // Caller does not have the requisite location permissions. Reset the
+ // owner's UID in the NetworkCapabilities.
+ newNc.setOwnerUid(INVALID_UID);
+ }
+ }
+ );
+
+ return newNc;
}
private LinkProperties linkPropertiesRestrictedForCallerPermissions(
@@ -1753,7 +1779,7 @@
public boolean isActiveNetworkMetered() {
enforceAccessPermission();
- final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork());
+ final NetworkCapabilities caps = getNetworkCapabilitiesInternal(getActiveNetwork());
if (caps != null) {
return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
} else {
@@ -3430,16 +3456,16 @@
// there is hope for it to become one if it validated, then it is needed.
ensureRunningOnConnectivityServiceThread();
if (nri.request.isRequest() && nai.satisfies(nri.request) &&
- (nai.isSatisfyingRequest(nri.request.requestId) ||
- // Note that this catches two important cases:
- // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
- // is currently satisfying the request. This is desirable when
- // cellular ends up validating but WiFi does not.
- // 2. Unvalidated WiFi will not be reaped when validated cellular
- // is currently satisfying the request. This is desirable when
- // WiFi ends up validating and out scoring cellular.
- nri.mSatisfier.getCurrentScore()
- < nai.getCurrentScoreAsValidated())) {
+ (nai.isSatisfyingRequest(nri.request.requestId)
+ // Note that canPossiblyBeat catches two important cases:
+ // 1. Unvalidated slow networks will not be reaped when an unvalidated fast
+ // network is currently satisfying the request. This is desirable for example
+ // when cellular ends up validating but WiFi/Ethernet does not.
+ // 2. Fast networks will not be reaped when a validated slow network is
+ // currently satisfying the request. This is desirable for example when
+ // Ethernet ends up validating and out scoring WiFi, or WiFi/Ethernet ends
+ // up validating and out scoring cellular.
+ || nai.canPossiblyBeat(nri.mSatisfier))) {
return false;
}
}
@@ -5330,8 +5356,8 @@
}
public String toString() {
- return "uid/pid:" + mUid + "/" + mPid + " " + request +
- (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
+ return "uid/pid:" + mUid + "/" + mPid + " " + request
+ + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
}
}
@@ -6408,8 +6434,13 @@
}
switch (notificationType) {
case ConnectivityManager.CALLBACK_AVAILABLE: {
- putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions(
- networkAgent.networkCapabilities, nri.mPid, nri.mUid));
+ final NetworkCapabilities nc =
+ networkCapabilitiesRestrictedForCallerPermissions(
+ networkAgent.networkCapabilities, nri.mPid, nri.mUid);
+ putParcelable(
+ bundle,
+ maybeSanitizeLocationInfoForCaller(
+ nc, nri.mUid, nri.request.getRequestorPackageName()));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
// For this notification, arg1 contains the blocked status.
@@ -6422,9 +6453,13 @@
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
// networkAgent can't be null as it has been accessed a few lines above.
- final NetworkCapabilities nc = networkCapabilitiesRestrictedForCallerPermissions(
- networkAgent.networkCapabilities, nri.mPid, nri.mUid);
- putParcelable(bundle, nc);
+ final NetworkCapabilities netCap =
+ networkCapabilitiesRestrictedForCallerPermissions(
+ networkAgent.networkCapabilities, nri.mPid, nri.mUid);
+ putParcelable(
+ bundle,
+ maybeSanitizeLocationInfoForCaller(
+ netCap, nri.mUid, nri.request.getRequestorPackageName()));
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 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/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 207a6aa..5db5115 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -194,8 +194,6 @@
// time
private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
- private static final String FEATURE_ID = "LocationService";
-
private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
private final Object mLock = new Object();
@@ -215,11 +213,6 @@
private PackageManager mPackageManager;
private PowerManager mPowerManager;
- // TODO: sharing a location fudger with mock providers can leak information as the mock provider
- // can be used to retrieve offset information. the fudger should likely be reset whenever mock
- // providers are added or removed
- private LocationFudger mLocationFudger;
-
private GeofenceManager mGeofenceManager;
private GeocoderProxy mGeocodeProvider;
@@ -245,7 +238,7 @@
private int mBatterySaverMode;
private LocationManagerService(Context context) {
- mContext = context.createFeatureContext(FEATURE_ID);
+ mContext = context;
mHandler = FgThread.getHandler();
mLocalService = new LocalService();
@@ -287,8 +280,6 @@
mPackageManager = mContext.getPackageManager();
mAppOps = mContext.getSystemService(AppOpsManager.class);
mPowerManager = mContext.getSystemService(PowerManager.class);
-
- mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
mGeofenceManager = new GeofenceManager(mContext, mSettingsHelper);
PowerManagerInternal localPowerManager =
@@ -665,6 +656,8 @@
private final String mName;
+ private final LocationFudger mLocationFudger;
+
// if the provider is enabled for a given user id - null or not present means unknown
@GuardedBy("mLock")
private final SparseArray<Boolean> mEnabled;
@@ -682,6 +675,7 @@
private LocationProviderManager(String name) {
mName = name;
+ mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
mEnabled = new SparseArray<>(2);
mLastLocation = new SparseArray<>(2);
mLastCoarseLocation = new SparseArray<>(2);
@@ -706,7 +700,9 @@
synchronized (mLock) {
mProvider.setMockProvider(provider);
- // when removing a mock provider, also clear any mock last locations
+ // when removing a mock provider, also clear any mock last locations and reset the
+ // location fudger. the mock provider could have been used to infer the current
+ // location fudger offsets.
if (provider == null) {
for (int i = 0; i < mLastLocation.size(); i++) {
Location lastLocation = mLastLocation.valueAt(i);
@@ -721,6 +717,8 @@
mLastCoarseLocation.setValueAt(i, null);
}
}
+
+ mLocationFudger.resetOffsets();
}
}
}
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/SensorNotificationService.java b/services/core/java/com/android/server/SensorNotificationService.java
index 9082dca..7f5befa 100644
--- a/services/core/java/com/android/server/SensorNotificationService.java
+++ b/services/core/java/com/android/server/SensorNotificationService.java
@@ -16,8 +16,10 @@
package com.android.server;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.hardware.GeomagneticField;
import android.hardware.Sensor;
import android.hardware.SensorAdditionalInfo;
@@ -29,7 +31,9 @@
import android.location.LocationManager;
import android.os.Bundle;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Slog;
public class SensorNotificationService extends SystemService
@@ -48,8 +52,6 @@
private static final long MILLIS_2010_1_1 = 1262358000000l;
- private static final String FEATURE_ID = "SensorNotificationService";
-
private Context mContext;
private SensorManager mSensorManager;
private LocationManager mLocationManager;
@@ -59,8 +61,8 @@
private long mLocalGeomagneticFieldUpdateTime = -LOCATION_MIN_TIME;
public SensorNotificationService(Context context) {
- super(context.createFeatureContext(FEATURE_ID));
- mContext = getContext();
+ super(context);
+ mContext = context;
}
public void onStart() {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 53dbb93..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);
@@ -4409,6 +4445,25 @@
}
}
+ @Override
+ public void prepareAppDataAfterInstall(String packageName, int uid) {
+ int userId = UserHandle.getUserId(uid);
+ final Environment.UserEnvironment userEnv = new Environment.UserEnvironment(userId);
+
+ // The installer may have downloaded OBBs for this newly installed application;
+ // make sure the OBB dir for the application is setup correctly, if it exists.
+ File[] packageObbDirs = userEnv.buildExternalStorageAppObbDirs(packageName);
+ for (File packageObbDir : packageObbDirs) {
+ try {
+ mVold.fixupAppDir(packageObbDir.getCanonicalPath() + "/", uid);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to get canonical path for " + packageName);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to fixup app dir for " + packageName);
+ }
+ }
+ }
+
public boolean hasExternalStorage(int uid, String packageName) {
// No need to check for system uid. This avoids a deadlock between
// PackageManagerService and AppOpsService.
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index a1ccd84..8900eee 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -100,7 +100,7 @@
"media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
"media.swcodec", // /apex/com.android.media.swcodec/bin/mediaswcodec
"com.android.bluetooth", // Bluetooth service
- "/system/bin/statsd", // Stats daemon
+ "/apex/com.android.os.statsd/bin/statsd", // Stats daemon
};
public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 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/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 430a5b9..2bcb28d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -49,6 +49,7 @@
import android.app.PendingIntent;
import android.app.Service;
import android.app.ServiceStartArgs;
+import android.app.admin.DevicePolicyEventLogger;
import android.appwidget.AppWidgetManagerInternal;
import android.content.ComponentName;
import android.content.ComponentName.WithComponentName;
@@ -61,7 +62,6 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -79,6 +79,7 @@
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.stats.devicepolicy.DevicePolicyEnums;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -89,7 +90,6 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.webkit.WebViewZygote;
-import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.app.procstats.ServiceState;
@@ -1912,6 +1912,8 @@
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
+ maybeLogBindCrossProfileService(userId, callingPackage, callerApp.info.uid);
+
getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
} finally {
@@ -1921,6 +1923,21 @@
return 1;
}
+ private void maybeLogBindCrossProfileService(
+ int userId, String callingPackage, int callingUid) {
+ if (UserHandle.isCore(callingUid)) {
+ return;
+ }
+ final int callingUserId = UserHandle.getCallingUserId();
+ if (callingUserId == userId
+ || !mAm.mUserController.isSameProfileGroup(callingUserId, userId)) {
+ return;
+ }
+ DevicePolicyEventLogger.createEvent(DevicePolicyEnums.BIND_CROSS_PROFILE_SERVICE)
+ .setStrings(callingPackage)
+ .write();
+ }
+
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
@@ -4668,20 +4685,35 @@
}
// TODO: remove this toast after feature development is done
- private void showWhileInUsePermissionInFgsBlockedToastLocked(String callingPackage) {
- final Resources res = mAm.mContext.getResources();
- final String toastMsg = res.getString(
- R.string.allow_while_in_use_permission_in_fgs, callingPackage);
- mAm.mUiHandler.post(() -> {
- Toast.makeText(mAm.mContext, toastMsg, Toast.LENGTH_LONG).show();
- });
+ private void showWhileInUsePermissionInFgsBlockedNotificationLocked(String callingPackage,
+ String detailInfo) {
+ final Context context = mAm.mContext;
+ final String title = "Foreground Service While-in-use Permission Restricted";
+ final String content = "App affected:" + callingPackage + ", please file a bug report";
+ Notification.Builder n =
+ new Notification.Builder(context,
+ SystemNotificationChannels.ALERTS)
+ .setSmallIcon(R.drawable.stat_sys_vitals)
+ .setWhen(0)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setTicker(title)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setStyle(new Notification.BigTextStyle().bigText(detailInfo));
+ final NotificationManager notificationManager =
+ (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
+ notificationManager.notifyAsUser(null,
+ SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION,
+ n.build(), UserHandle.ALL);
}
// TODO: remove this toast after feature development is done
// show a toast message to ask user to file a bugreport so we know how many apps are impacted by
// the new background started foreground service while-in-use permission restriction.
- void showWhileInUseDebugToastLocked(int uid, int op, int mode) {
- StringBuilder sb = new StringBuilder();
+ void showWhileInUseDebugNotificationLocked(int uid, int op, int mode) {
+ StringBuilder packageNameBuilder = new StringBuilder();
+ StringBuilder detailInfoBuilder = new StringBuilder();
for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
if (pr.uid != uid) {
@@ -4694,17 +4726,22 @@
}
if (!r.mAllowWhileInUsePermissionInFgs
&& r.mInfoDenyWhileInUsePermissionInFgs != null) {
- Slog.wtf(TAG, r.mInfoDenyWhileInUsePermissionInFgs
- + " affected while-use-permission:" + AppOpsManager.opToPublicName(op));
- sb.append(r.mRecentCallingPackage + " ");
+ final String msg = r.mInfoDenyWhileInUsePermissionInFgs
+ + " affected while-in-use permission:"
+ + AppOpsManager.opToPublicName(op);
+ Slog.wtf(TAG, msg);
+ packageNameBuilder.append(r.mRecentCallingPackage + " ");
+ detailInfoBuilder.append(msg);
+ detailInfoBuilder.append("\n");
}
}
}
- final String callingPackageStr = sb.toString();
+ final String callingPackageStr = packageNameBuilder.toString();
if (mAm.mConstants.mFlagForegroundServiceStartsLoggingEnabled
&& !callingPackageStr.isEmpty()) {
- showWhileInUsePermissionInFgsBlockedToastLocked(callingPackageStr);
+ showWhileInUsePermissionInFgsBlockedNotificationLocked(callingPackageStr,
+ detailInfoBuilder.toString());
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9082807..0d8eff5 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];
}
@@ -14605,6 +14610,11 @@
if (index < 0) {
ProcessList.remove(app.pid);
}
+
+ // Remove provider publish timeout because we will start a new timeout when the
+ // restarted process is attaching (if the process contains launching providers).
+ mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, app);
+
mProcessList.addProcessNameLocked(app);
app.pendingStart = false;
mProcessList.startProcessLocked(app,
@@ -19333,7 +19343,8 @@
@Override
public void showWhileInUseDebugToast(int uid, int op, int mode) {
synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.mServices.showWhileInUseDebugToastLocked(uid, op, mode);
+ ActivityManagerService.this.mServices.showWhileInUseDebugNotificationLocked(
+ uid, op, mode);
}
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 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/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index a03f0bb..48ceba9 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.annotation.NonNull;
import android.app.ActivityThread;
import android.content.Context;
import android.database.ContentObserver;
@@ -32,6 +33,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* Helper class for watching a set of core settings which the framework
@@ -42,16 +44,20 @@
final class CoreSettingsObserver extends ContentObserver {
private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName();
- private static class DeviceConfigEntry {
+ private static class DeviceConfigEntry<T> {
String namespace;
String flag;
String coreSettingKey;
- Class<?> type;
- DeviceConfigEntry(String namespace, String flag, String coreSettingKey, Class<?> type) {
+ Class<T> type;
+ T defaultValue;
+
+ DeviceConfigEntry(String namespace, String flag, String coreSettingKey, Class<T> type,
+ @NonNull T defaultValue) {
this.namespace = namespace;
this.flag = flag;
this.coreSettingKey = coreSettingKey;
this.type = type;
+ this.defaultValue = Objects.requireNonNull(defaultValue);
}
}
@@ -105,24 +111,34 @@
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, String.class);
// add other global settings here...
- sDeviceConfigEntries.add(new DeviceConfigEntry(
- DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_CONTROL,
- WidgetFlags.KEY_ENABLE_CURSOR_CONTROL, boolean.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
+ WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, boolean.class,
+ WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES,
+ WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES, boolean.class,
+ WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT,
- WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, int.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, int.class,
+ WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_OPACITY,
- WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, int.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, int.class,
+ WidgetFlags.INSERTION_HANDLE_OPACITY_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_NEW_MAGNIFIER,
- WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, boolean.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, boolean.class,
+ WidgetFlags.ENABLE_NEW_MAGNIFIER_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Float>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ZOOM_FACTOR,
- WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, float.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, float.class,
+ WidgetFlags.MAGNIFIER_ZOOM_FACTOR_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Float>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ASPECT_RATIO,
- WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class));
+ WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class,
+ WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT));
// add other device configs here...
}
@@ -216,23 +232,29 @@
}
}
+ @SuppressWarnings("unchecked")
private void populateSettingsFromDeviceConfig() {
- for (DeviceConfigEntry entry : sDeviceConfigEntries) {
+ for (DeviceConfigEntry<?> entry : sDeviceConfigEntries) {
if (entry.type == String.class) {
+ String defaultValue = ((DeviceConfigEntry<String>) entry).defaultValue;
mCoreSettings.putString(entry.coreSettingKey,
- DeviceConfig.getString(entry.namespace, entry.flag, ""));
+ DeviceConfig.getString(entry.namespace, entry.flag, defaultValue));
} else if (entry.type == int.class) {
+ int defaultValue = ((DeviceConfigEntry<Integer>) entry).defaultValue;
mCoreSettings.putInt(entry.coreSettingKey,
- DeviceConfig.getInt(entry.namespace, entry.flag, 0));
+ DeviceConfig.getInt(entry.namespace, entry.flag, defaultValue));
} else if (entry.type == float.class) {
+ float defaultValue = ((DeviceConfigEntry<Float>) entry).defaultValue;
mCoreSettings.putFloat(entry.coreSettingKey,
- DeviceConfig.getFloat(entry.namespace, entry.flag, 0));
+ DeviceConfig.getFloat(entry.namespace, entry.flag, defaultValue));
} else if (entry.type == long.class) {
+ long defaultValue = ((DeviceConfigEntry<Long>) entry).defaultValue;
mCoreSettings.putLong(entry.coreSettingKey,
- DeviceConfig.getLong(entry.namespace, entry.flag, 0));
+ DeviceConfig.getLong(entry.namespace, entry.flag, defaultValue));
} else if (entry.type == boolean.class) {
+ boolean defaultValue = ((DeviceConfigEntry<Boolean>) entry).defaultValue;
mCoreSettings.putInt(entry.coreSettingKey,
- DeviceConfig.getBoolean(entry.namespace, entry.flag, false) ? 1 : 0);
+ DeviceConfig.getBoolean(entry.namespace, entry.flag, defaultValue) ? 1 : 0);
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index ffa7d92..22559c4 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";
@@ -339,6 +345,14 @@
@EnabledAfter(targetSdkVersion = VersionCodes.Q)
private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
+ /**
+ * Apps have no access to the private data directories of any other app, even if the other
+ * app has made them world-readable.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = VersionCodes.Q)
+ private static final long APP_DATA_DIRECTORY_ISOLATION = 143937733; // See b/143937733
+
ActivityManagerService mService = null;
// To kill process groups asynchronously
@@ -379,6 +393,8 @@
private boolean mAppDataIsolationEnabled = false;
+ private boolean mVoldAppDataIsolationEnabled = false;
+
private ArrayList<String> mAppDataIsolationWhitelistedApps;
/**
@@ -691,6 +707,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());
@@ -2060,7 +2078,14 @@
}
final int minTargetSdk = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ANDROID_APP_DATA_ISOLATION_MIN_SDK, Build.VERSION_CODES.R);
- return app.info.targetSdkVersion >= minTargetSdk;
+ if (app.info.targetSdkVersion < minTargetSdk) {
+ return false;
+ }
+
+ // TODO(b/147266020): Remove non-standard gating above & switch to isChangeEnabled.
+ mPlatformCompat.reportChange(APP_DATA_DIRECTORY_ISOLATION, app.info);
+
+ return true;
}
private Map<String, Pair<String, Long>> getPackageAppDataInfoMap(PackageManagerInternal pmInt,
@@ -2113,6 +2138,13 @@
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/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 4612cfd..3860904 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.transportNamesOf;
import android.annotation.NonNull;
@@ -475,24 +477,16 @@
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}
- private int getCurrentScore(boolean pretendValidated) {
- // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
- // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
- // score. The NetworkScore class would provide a nice place to centralize score constants
- // so they are not scattered about the transports.
-
+ /** Gets the current score */
+ public int getCurrentScore() {
// If this network is explicitly selected and the user has decided to use it even if it's
- // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly
- // selected and we're trying to see what its score could be. This ensures that we don't tear
- // down an explicitly selected network before the user gets a chance to prefer it when
- // a higher-scoring network (e.g., Ethernet) is available.
- if (networkAgentConfig.explicitlySelected
- && (networkAgentConfig.acceptUnvalidated || pretendValidated)) {
+ // unvalidated, give it the maximum score.
+ if (networkAgentConfig.explicitlySelected && networkAgentConfig.acceptUnvalidated) {
return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
}
int score = mNetworkScore.getLegacyScore();
- if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
+ if (!lastValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
}
if (score < 0) score = 0;
@@ -508,18 +502,6 @@
return isWifi && !avoidBadWifi && everValidated;
}
- // Get the current score for this Network. This may be modified from what the
- // NetworkAgent sent, as it has modifiers applied to it.
- public int getCurrentScore() {
- return getCurrentScore(false);
- }
-
- // Get the current score for this Network as if it was validated. This may be modified from
- // what the NetworkAgent sent, as it has modifiers applied to it.
- public int getCurrentScoreAsValidated() {
- return getCurrentScore(true);
- }
-
public void setNetworkScore(@NonNull NetworkScore ns) {
mNetworkScore = ns;
}
@@ -629,6 +611,41 @@
mLingering = false;
}
+ /**
+ * Returns whether this NAI has any chance of ever beating this other agent.
+ *
+ * The chief use case of this is the decision to tear down this network. ConnectivityService
+ * tears down networks that don't satisfy any request, unless they have a chance to beat any
+ * existing satisfier.
+ *
+ * @param other the agent to beat
+ * @return whether this should be given more time to try and beat the other agent
+ * TODO : remove this and migrate to a ranker-based approach
+ */
+ public boolean canPossiblyBeat(@NonNull final NetworkAgentInfo other) {
+ // Any explicitly selected network should be held on.
+ if (networkAgentConfig.explicitlySelected) return true;
+ // An outscored exiting network should be torn down.
+ if (mNetworkScore.isExiting()) return false;
+ // If this network is validated it can be torn down as it can't hope to be better than
+ // it already is.
+ if (networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) return false;
+ // If neither network is validated, keep both until at least one does.
+ if (!other.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) return true;
+ // If this network is not metered but the other is, it should be preferable if it validates.
+ if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
+ && !other.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+ return true;
+ }
+
+ // If the control comes here :
+ // • This network is neither exiting or explicitly selected
+ // • This network is not validated, but the other is
+ // • This network is metered, or both networks are unmetered
+ // Keep it if it's expected to be faster than the other., should it validate.
+ return mNetworkScore.probablyFasterThan(other.mNetworkScore);
+ }
+
public void dumpLingerTimers(PrintWriter pw) {
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java
index c536ab2..80d46e0 100644
--- a/services/core/java/com/android/server/connectivity/NetworkRanker.java
+++ b/services/core/java/com/android/server/connectivity/NetworkRanker.java
@@ -16,6 +16,9 @@
package com.android.server.connectivity;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkScore.POLICY_IGNORE_ON_WIFI;
import static com.android.internal.util.FunctionalUtils.findFirst;
@@ -42,13 +45,20 @@
@NonNull final Collection<NetworkAgentInfo> nais) {
final ArrayList<NetworkAgentInfo> candidates = new ArrayList<>(nais);
candidates.removeIf(nai -> !nai.satisfies(request));
- // Enforce policy.
- filterBadWifiAvoidancePolicy(candidates);
+
+ // Enforce policy. The order in which the policy is computed is essential, because each
+ // step may remove some of the candidates. For example, filterValidated drops non-validated
+ // networks in presence of validated networks for INTERNET requests, but the bad wifi
+ // avoidance policy takes priority over this, so it must be done before.
+ filterVpn(candidates);
+ filterExplicitlySelected(candidates);
+ filterBadWifiAvoidance(candidates);
+ filterValidated(request, candidates);
NetworkAgentInfo bestNetwork = null;
int bestScore = Integer.MIN_VALUE;
for (final NetworkAgentInfo nai : candidates) {
- final int score = nai.getCurrentScore();
+ final int score = nai.getNetworkScore().getLegacyScore();
if (score > bestScore) {
bestNetwork = nai;
bestScore = score;
@@ -57,9 +67,27 @@
return bestNetwork;
}
- // If some network with wifi transport is present, drop all networks with POLICY_IGNORE_ON_WIFI.
- private void filterBadWifiAvoidancePolicy(
+ // If a network is a VPN it has priority.
+ private void filterVpn(@NonNull final ArrayList<NetworkAgentInfo> candidates) {
+ final NetworkAgentInfo vpn = findFirst(candidates,
+ nai -> nai.networkCapabilities.hasTransport(TRANSPORT_VPN));
+ if (null == vpn) return; // No VPN : this policy doesn't apply.
+ candidates.removeIf(nai -> !nai.networkCapabilities.hasTransport(TRANSPORT_VPN));
+ }
+
+ // If some network is explicitly selected and set to accept unvalidated connectivity, then
+ // drop all networks that are not explicitly selected.
+ private void filterExplicitlySelected(
@NonNull final ArrayList<NetworkAgentInfo> candidates) {
+ final NetworkAgentInfo explicitlySelected = findFirst(candidates,
+ nai -> nai.networkAgentConfig.explicitlySelected
+ && nai.networkAgentConfig.acceptUnvalidated);
+ if (null == explicitlySelected) return; // No explicitly selected network accepting unvalid
+ candidates.removeIf(nai -> !nai.networkAgentConfig.explicitlySelected);
+ }
+
+ // If some network with wifi transport is present, drop all networks with POLICY_IGNORE_ON_WIFI.
+ private void filterBadWifiAvoidance(@NonNull final ArrayList<NetworkAgentInfo> candidates) {
final NetworkAgentInfo wifi = findFirst(candidates,
nai -> nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
&& nai.everValidated
@@ -71,4 +99,16 @@
if (null == wifi) return; // No wifi : this policy doesn't apply
candidates.removeIf(nai -> nai.getNetworkScore().hasPolicy(POLICY_IGNORE_ON_WIFI));
}
+
+ // If some network is validated and the request asks for INTERNET, drop all networks that are
+ // not validated.
+ private void filterValidated(@NonNull final NetworkRequest request,
+ @NonNull final ArrayList<NetworkAgentInfo> candidates) {
+ if (!request.hasCapability(NET_CAPABILITY_INTERNET)) return;
+ final NetworkAgentInfo validated = findFirst(candidates,
+ nai -> nai.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED));
+ if (null == validated) return; // No validated network
+ candidates.removeIf(nai ->
+ !nai.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED));
+ }
}
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/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index ac41434..18adc0b 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -16,6 +16,7 @@
package com.android.server.display;
+import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayViewport;
import android.util.DisplayMetrics;
import android.view.Display;
@@ -288,6 +289,13 @@
public DisplayAddress address;
/**
+ * Product-specific information about the display or the directly connected device on the
+ * display chain. For example, if the display is transitively connected, this field may contain
+ * product information about the intermediate device.
+ */
+ public DeviceProductInfo deviceProductInfo;
+
+ /**
* Display state.
*/
public int state = Display.STATE_ON;
@@ -360,6 +368,7 @@
|| rotation != other.rotation
|| type != other.type
|| !Objects.equals(address, other.address)
+ || !Objects.equals(deviceProductInfo, other.deviceProductInfo)
|| ownerUid != other.ownerUid
|| !Objects.equals(ownerPackageName, other.ownerPackageName)) {
diff |= DIFF_OTHER;
@@ -396,6 +405,7 @@
rotation = other.rotation;
type = other.type;
address = other.address;
+ deviceProductInfo = other.deviceProductInfo;
state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
@@ -429,6 +439,7 @@
if (address != null) {
sb.append(", address ").append(address);
}
+ sb.append(", deviceProductInfo ").append(deviceProductInfo);
sb.append(", state ").append(Display.stateToString(state));
if (ownerUid != 0 || ownerPackageName != null) {
sb.append(", owner ").append(ownerPackageName);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 4ebbdda..e578ac1 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -513,6 +513,7 @@
mInfo.densityDpi = (int) (mDisplayInfo.density * 160 + 0.5f);
mInfo.xDpi = config.xDpi;
mInfo.yDpi = config.yDpi;
+ mInfo.deviceProductInfo = mDisplayInfo.deviceProductInfo;
// Assume that all built-in displays that have secure output (eg. HDCP) also
// support compositing from gralloc protected buffers.
@@ -891,8 +892,8 @@
pw.println("mBacklight=" + mBacklight);
pw.println("mAllmSupported=" + mAllmSupported);
pw.println("mAllmRequested=" + mAllmRequested);
- pw.println("mGameContentTypeSupported" + mGameContentTypeSupported);
- pw.println("mGameContentTypeRequested" + mGameContentTypeRequested);
+ pw.println("mGameContentTypeSupported=" + mGameContentTypeSupported);
+ pw.println("mGameContentTypeRequested=" + mGameContentTypeRequested);
pw.println("mDisplayInfo=" + mDisplayInfo);
pw.println("mDisplayConfigs=");
for (int i = 0; i < mDisplayConfigs.length; i++) {
@@ -902,14 +903,7 @@
for (int i = 0; i < mSupportedModes.size(); i++) {
pw.println(" " + mSupportedModes.valueAt(i));
}
- pw.print("mSupportedColorModes=[");
- for (int i = 0; i < mSupportedColorModes.size(); i++) {
- if (i != 0) {
- pw.print(", ");
- }
- pw.print(mSupportedColorModes.get(i));
- }
- pw.println("]");
+ pw.print("mSupportedColorModes=" + mSupportedColorModes.toString());
}
private int findDisplayConfigIdLocked(int modeId) {
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 0c9445a..ac81a6c 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -269,6 +269,7 @@
mBaseDisplayInfo.type = deviceInfo.type;
mBaseDisplayInfo.address = deviceInfo.address;
+ mBaseDisplayInfo.deviceProductInfo = deviceInfo.deviceProductInfo;
mBaseDisplayInfo.name = deviceInfo.name;
mBaseDisplayInfo.uniqueId = deviceInfo.uniqueId;
mBaseDisplayInfo.appWidth = maskedWidth;
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/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 6174e54..b84d322 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -77,7 +77,7 @@
private static final int NUM_LOGICAL_ADDRESS = 16;
- private static final int MAX_CEC_MESSAGE_HISTORY = 200;
+ private static final int MAX_HDMI_MESSAGE_HISTORY = 250;
// Predicate for whether the given logical address is remote device's one or not.
private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
@@ -111,9 +111,9 @@
// Stores the local CEC devices in the system. Device type is used for key.
private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>();
- // Stores recent CEC messages history for debugging purpose.
- private final ArrayBlockingQueue<MessageHistoryRecord> mMessageHistory =
- new ArrayBlockingQueue<>(MAX_CEC_MESSAGE_HISTORY);
+ // Stores recent CEC messages and HDMI Hotplug event history for debugging purpose.
+ private final ArrayBlockingQueue<Dumpable> mMessageHistory =
+ new ArrayBlockingQueue<>(MAX_HDMI_MESSAGE_HISTORY);
private final NativeWrapper mNativeWrapperImpl;
@@ -618,7 +618,7 @@
void sendCommand(final HdmiCecMessage cecMessage,
final HdmiControlService.SendMessageCallback callback) {
assertRunOnServiceThread();
- addMessageToHistory(false /* isReceived */, cecMessage);
+ addCecMessageToHistory(false /* isReceived */, cecMessage);
runOnIoThread(new Runnable() {
@Override
public void run() {
@@ -658,7 +658,7 @@
assertRunOnServiceThread();
HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body);
HdmiLogger.debug("[R]:" + command);
- addMessageToHistory(true /* isReceived */, command);
+ addCecMessageToHistory(true /* isReceived */, command);
onReceiveCommand(command);
}
@@ -669,16 +669,26 @@
private void handleHotplug(int port, boolean connected) {
assertRunOnServiceThread();
HdmiLogger.debug("Hotplug event:[port:%d, connected:%b]", port, connected);
+ addHotplugEventToHistory(port, connected);
mService.onHotplug(port, connected);
}
@ServiceThreadOnly
- private void addMessageToHistory(boolean isReceived, HdmiCecMessage message) {
+ private void addHotplugEventToHistory(int port, boolean connected) {
assertRunOnServiceThread();
- MessageHistoryRecord record = new MessageHistoryRecord(isReceived, message);
- if (!mMessageHistory.offer(record)) {
+ addEventToHistory(new HotplugHistoryRecord(port, connected));
+ }
+
+ @ServiceThreadOnly
+ private void addCecMessageToHistory(boolean isReceived, HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ addEventToHistory(new MessageHistoryRecord(isReceived, message));
+ }
+
+ private void addEventToHistory(Dumpable event) {
+ if (!mMessageHistory.offer(event)) {
mMessageHistory.poll();
- mMessageHistory.offer(record);
+ mMessageHistory.offer(event);
}
}
@@ -689,10 +699,11 @@
mLocalDevices.valueAt(i).dump(pw);
pw.decreaseIndent();
}
+
pw.println("CEC message history:");
pw.increaseIndent();
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- for (MessageHistoryRecord record : mMessageHistory) {
+ for (Dumpable record : mMessageHistory) {
record.dump(pw, sdf);
}
pw.decreaseIndent();
@@ -792,17 +803,27 @@
}
}
- private final class MessageHistoryRecord {
- private final long mTime;
+ private abstract static class Dumpable {
+ protected final long mTime;
+
+ Dumpable() {
+ mTime = System.currentTimeMillis();
+ }
+
+ abstract void dump(IndentingPrintWriter pw, SimpleDateFormat sdf);
+ }
+
+ private static final class MessageHistoryRecord extends Dumpable {
private final boolean mIsReceived; // true if received message and false if sent message
private final HdmiCecMessage mMessage;
- public MessageHistoryRecord(boolean isReceived, HdmiCecMessage message) {
- mTime = System.currentTimeMillis();
+ MessageHistoryRecord(boolean isReceived, HdmiCecMessage message) {
+ super();
mIsReceived = isReceived;
mMessage = message;
}
+ @Override
void dump(final IndentingPrintWriter pw, SimpleDateFormat sdf) {
pw.print(mIsReceived ? "[R]" : "[S]");
pw.print(" time=");
@@ -811,4 +832,26 @@
pw.println(mMessage);
}
}
+
+ private static final class HotplugHistoryRecord extends Dumpable {
+ private final int mPort;
+ private final boolean mConnected;
+
+ HotplugHistoryRecord(int port, boolean connected) {
+ super();
+ mPort = port;
+ mConnected = connected;
+ }
+
+ @Override
+ void dump(final IndentingPrintWriter pw, SimpleDateFormat sdf) {
+ pw.print("[H]");
+ pw.print(" time=");
+ pw.print(sdf.format(new Date(mTime)));
+ pw.print(" hotplug port=");
+ pw.print(mPort);
+ pw.print(" connected=");
+ pw.println(mConnected);
+ }
+ }
}
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/CountryDetectorBase.java b/services/core/java/com/android/server/location/CountryDetectorBase.java
index b158388..8326ef9 100644
--- a/services/core/java/com/android/server/location/CountryDetectorBase.java
+++ b/services/core/java/com/android/server/location/CountryDetectorBase.java
@@ -31,15 +31,13 @@
* @hide
*/
public abstract class CountryDetectorBase {
- private static final String FEATURE_ID = "CountryDetector";
-
protected final Handler mHandler;
protected final Context mContext;
protected CountryListener mListener;
protected Country mDetectedCountry;
- public CountryDetectorBase(Context context) {
- mContext = context.createFeatureContext(FEATURE_ID);
+ public CountryDetectorBase(Context ctx) {
+ mContext = ctx;
mHandler = new Handler();
}
@@ -47,7 +45,7 @@
* Start detecting the country that the user is in.
*
* @return the country if it is available immediately, otherwise null should
- * be returned.
+ * be returned.
*/
public abstract Country detectCountry();
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/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java
index a069e7a..1f458ed 100644
--- a/services/core/java/com/android/server/location/LocationFudger.java
+++ b/services/core/java/com/android/server/location/LocationFudger.java
@@ -87,6 +87,13 @@
mRandom = random;
mAccuracyM = Math.max(accuracyM, MIN_ACCURACY_M);
+ resetOffsets();
+ }
+
+ /**
+ * Resets the random offsets completely.
+ */
+ public void resetOffsets() {
mLatitudeOffsetM = nextRandomOffset();
mLongitudeOffsetM = nextRandomOffset();
mNextUpdateRealtimeMs = mClock.millis() + OFFSET_UPDATE_INTERVAL_MS;
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/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 05867ba..f7e1398 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -214,6 +214,8 @@
* Updates the mSessionInfo. Returns true if the session info is changed.
*/
boolean updateSessionInfosIfNeededLocked() {
+ // Prevent to execute this method before mBtRouteProvider is created.
+ if (mBtRouteProvider == null) return false;
RoutingSessionInfo oldSessionInfo = mSessionInfos.isEmpty() ? null : mSessionInfos.get(0);
RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
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/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fd86f1d..0d402e5 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3440,6 +3440,27 @@
}
@Override
+ public ParceledListSlice<ConversationChannelWrapper> getConversations(
+ boolean onlyImportant) {
+ enforceSystemOrSystemUI("getConversations");
+ ArrayList<ConversationChannelWrapper> conversations =
+ mPreferencesHelper.getConversations(onlyImportant);
+ for (ConversationChannelWrapper conversation : conversations) {
+ LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery()
+ .setPackage(conversation.getPkg())
+ .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED)
+ .setShortcutIds(Arrays.asList(
+ conversation.getNotificationChannel().getConversationId()));
+ List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(
+ query, UserHandle.of(UserHandle.getUserId(conversation.getUid())));
+ if (shortcuts != null && !shortcuts.isEmpty()) {
+ conversation.setShortcutInfo(shortcuts.get(0));
+ }
+ }
+ return new ParceledListSlice<>(conversations);
+ }
+
+ @Override
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
String pkg, int uid, boolean includeDeleted) {
enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage");
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 20c8625..b8186ed 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1186,6 +1186,44 @@
return groups;
}
+ public ArrayList<ConversationChannelWrapper> getConversations(boolean onlyImportant) {
+ synchronized (mPackagePreferences) {
+ ArrayList<ConversationChannelWrapper> conversations = new ArrayList<>();
+
+ for (PackagePreferences p : mPackagePreferences.values()) {
+ int N = p.channels.size();
+ for (int i = 0; i < N; i++) {
+ final NotificationChannel nc = p.channels.valueAt(i);
+ if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()
+ && (nc.isImportantConversation() || !onlyImportant)) {
+ ConversationChannelWrapper conversation = new ConversationChannelWrapper();
+ conversation.setPkg(p.pkg);
+ conversation.setUid(p.uid);
+ conversation.setNotificationChannel(nc);
+ conversation.setParentChannelLabel(
+ p.channels.get(nc.getParentChannelId()).getName());
+ boolean blockedByGroup = false;
+ if (nc.getGroup() != null) {
+ NotificationChannelGroup group = p.groups.get(nc.getGroup());
+ if (group != null) {
+ if (group.isBlocked()) {
+ blockedByGroup = true;
+ } else {
+ conversation.setGroupLabel(group.getName());
+ }
+ }
+ }
+ if (!blockedByGroup) {
+ conversations.add(conversation);
+ }
+ }
+ }
+ }
+
+ return conversations;
+ }
+ }
+
public ArrayList<ConversationChannelWrapper> getConversations(String pkg, int uid) {
Objects.requireNonNull(pkg);
synchronized (mPackagePreferences) {
@@ -1199,6 +1237,8 @@
final NotificationChannel nc = r.channels.valueAt(i);
if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()) {
ConversationChannelWrapper conversation = new ConversationChannelWrapper();
+ conversation.setPkg(r.pkg);
+ conversation.setUid(r.uid);
conversation.setNotificationChannel(nc);
conversation.setParentChannelLabel(
r.channels.get(nc.getParentChannelId()).getName());
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 f6eb76b..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;
}
@@ -15158,10 +15182,13 @@
// We purposefully exclude FLAG_STORAGE_EXTERNAL here, since
// this task was only focused on moving data on internal storage.
+ // We don't want ART profiles cleared, because they don't move,
+ // so we would be deleting the only copy (b/149200535).
+ final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE
+ | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
for (int userId : userIds) {
try {
- mInstaller.destroyAppData(volumeUuid, move.packageName, userId,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE, 0);
+ mInstaller.destroyAppData(volumeUuid, move.packageName, userId, flags, 0);
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
}
@@ -15317,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);
}
@@ -15346,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
@@ -15819,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
@@ -15922,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;
}
@@ -15944,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);
}
@@ -16058,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,
@@ -16191,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) {
@@ -16211,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),
@@ -16328,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 {
@@ -16372,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");
}
@@ -16393,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);
@@ -16415,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
@@ -16451,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. "
@@ -16506,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);
}
@@ -16518,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
@@ -16584,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());
}
}
}
@@ -16634,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) {
@@ -16814,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
@@ -16836,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
@@ -17003,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,
@@ -17055,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");
@@ -17079,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(
@@ -17115,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) {
@@ -17136,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;
}
@@ -17186,7 +17179,7 @@
}
private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
- if (isExternal(pkg)) {
+ if (pkg.isExternalStorage()) {
if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
return mSettings.getExternalVersion();
} else {
@@ -17646,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");
}
@@ -17660,7 +17654,7 @@
Slog.i(TAG, "Enabling system stub after removal; pkg: "
+ stubPkg.getPackageName());
}
- enableCompressedPackage(stubPkg);
+ enableCompressedPackage(stubPkg, stubPs);
}
}
}
@@ -18043,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());
}
@@ -18476,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;
}
@@ -18506,7 +18504,7 @@
} else {
flags = 0;
}
- prepareAppDataContentsLIF(pkg, userId, flags);
+ prepareAppDataContentsLIF(pkg, ps, userId, flags);
return true;
}
@@ -19963,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;
}
}
@@ -19980,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) {
@@ -21213,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();
}
}
@@ -21336,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,
@@ -21733,6 +21734,7 @@
}
UserManagerInternal umInternal = mInjector.getUserManagerInternal();
+ StorageManagerInternal smInternal = mInjector.getStorageManagerInternal();
for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) {
final int flags;
if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
@@ -21746,6 +21748,13 @@
if (ps.getInstalled(user.id)) {
// TODO: when user data is locked, mark that we're still dirty
prepareAppDataLIF(pkg, user.id, flags);
+
+ if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
+ // Prepare app data on external storage; currently this is used to
+ // setup any OBB dirs that were created by the installer correctly.
+ int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid()));
+ smInternal.prepareAppDataAfterInstall(pkg.getPackageName(), uid);
+ }
}
}
}
@@ -21792,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);
@@ -21846,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();
@@ -21865,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,
@@ -22054,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");
}
@@ -22080,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");
}
@@ -22090,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");
@@ -22270,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,
@@ -23002,7 +23015,7 @@
}
@Override
- public Object getDisabledSystemPackage(@NonNull String packageName) {
+ public PackageSetting getDisabledSystemPackage(@NonNull String packageName) {
synchronized (mLock) {
return mSettings.getDisabledSystemPkgLPr(packageName);
}
@@ -23352,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);
@@ -23444,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();
}
}
@@ -23679,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);
@@ -24174,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());
@@ -24197,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) {
@@ -24230,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 377fd16..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);
@@ -2773,6 +2818,13 @@
userId, /* doCache= */ false);
}
+ @Override
+ public List<ShortcutManager.ShareShortcutInfo> getShareTargets(
+ @NonNull String callingPackage, @NonNull IntentFilter intentFilter, int userId) {
+ return ShortcutService.this.getShareTargets(
+ callingPackage, intentFilter, userId).getList();
+ }
+
private void updateCachedShortcutsInternal(int launcherUserId,
@NonNull String callingPackage, @NonNull String packageName,
@NonNull List<String> shortcutIds, int userId, boolean doCache) {
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/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 491c5ab..da3cbf9 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -16,15 +16,18 @@
package com.android.server.power;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.thermal.V1_0.ThermalStatus;
import android.hardware.thermal.V1_0.ThermalStatusCode;
import android.hardware.thermal.V1_1.IThermalCallback;
import android.hardware.thermal.V2_0.IThermalChangedCallback;
+import android.hardware.thermal.V2_0.TemperatureThreshold;
import android.hardware.thermal.V2_0.ThrottlingSeverity;
import android.os.Binder;
import android.os.CoolingDevice;
+import android.os.Handler;
import android.os.HwBinder;
import android.os.IThermalEventListener;
import android.os.IThermalService;
@@ -36,6 +39,7 @@
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.ShellCommand;
+import android.os.SystemClock;
import android.os.Temperature;
import android.util.ArrayMap;
import android.util.EventLog;
@@ -43,6 +47,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
@@ -54,6 +59,7 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -100,6 +106,9 @@
/** Hal ready. */
private final AtomicBoolean mHalReady = new AtomicBoolean();
+ /** Watches temperatures to forecast when throttling will occur */
+ private final TemperatureWatcher mTemperatureWatcher = new TemperatureWatcher();
+
/** Invalid throttling status */
private static final int INVALID_THROTTLING = Integer.MIN_VALUE;
@@ -154,6 +163,7 @@
onTemperatureChanged(temperatures.get(i), false);
}
onTemperatureMapChangedLocked();
+ mTemperatureWatcher.updateSevereThresholds();
mHalReady.set(true);
}
}
@@ -462,6 +472,15 @@
}
}
+ @Override
+ public float getThermalHeadroom(int forecastSeconds) {
+ if (!mHalReady.get()) {
+ return Float.NaN;
+ }
+
+ return mTemperatureWatcher.getForecast(forecastSeconds);
+ }
+
private void dumpItemsLocked(PrintWriter pw, String prefix,
Collection<?> items) {
for (Iterator iterator = items.iterator(); iterator.hasNext();) {
@@ -616,6 +635,10 @@
protected abstract List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
int type);
+ @NonNull
+ protected abstract List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
+ int type);
+
protected abstract boolean connectToHal();
protected abstract void dump(PrintWriter pw, String prefix);
@@ -728,6 +751,12 @@
}
@Override
+ protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
+ int type) {
+ return new ArrayList<>();
+ }
+
+ @Override
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
@@ -857,6 +886,12 @@
}
@Override
+ protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
+ int type) {
+ return new ArrayList<>();
+ }
+
+ @Override
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
@@ -975,6 +1010,32 @@
}
@Override
+ protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
+ int type) {
+ synchronized (mHalLock) {
+ List<TemperatureThreshold> ret = new ArrayList<>();
+ if (mThermalHal20 == null) {
+ return ret;
+ }
+ try {
+ mThermalHal20.getTemperatureThresholds(shouldFilter, type,
+ (status, thresholds) -> {
+ if (ThermalStatusCode.SUCCESS == status.code) {
+ ret.addAll(thresholds);
+ } else {
+ Slog.e(TAG,
+ "Couldn't get temperature thresholds because of HAL "
+ + "error: " + status.debugMessage);
+ }
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getTemperatureThresholds, reconnecting...", e);
+ }
+ return ret;
+ }
+ }
+
+ @Override
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
@@ -1001,4 +1062,190 @@
}
}
+ private class TemperatureWatcher {
+ private final Handler mHandler = BackgroundThread.getHandler();
+
+ /** Map of skin temperature sensor name to a corresponding list of samples */
+ @GuardedBy("mSamples")
+ private final ArrayMap<String, ArrayList<Sample>> mSamples = new ArrayMap<>();
+
+ /** Map of skin temperature sensor name to the corresponding SEVERE temperature threshold */
+ @GuardedBy("mSamples")
+ private ArrayMap<String, Float> mSevereThresholds = new ArrayMap<>();
+
+ @GuardedBy("mSamples")
+ private long mLastForecastCallTimeMillis = 0;
+
+ void updateSevereThresholds() {
+ synchronized (mSamples) {
+ List<TemperatureThreshold> thresholds =
+ mHalWrapper.getTemperatureThresholds(true, Temperature.TYPE_SKIN);
+ for (int t = 0; t < thresholds.size(); ++t) {
+ TemperatureThreshold threshold = thresholds.get(t);
+ if (threshold.hotThrottlingThresholds.length <= ThrottlingSeverity.SEVERE) {
+ continue;
+ }
+ float temperature =
+ threshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE];
+ if (!Float.isNaN(temperature)) {
+ mSevereThresholds.put(threshold.name,
+ threshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE]);
+ }
+ }
+ }
+ }
+
+ private static final int INACTIVITY_THRESHOLD_MILLIS = 10000;
+ private static final int RING_BUFFER_SIZE = 30;
+
+ private void updateTemperature() {
+ synchronized (mSamples) {
+ if (SystemClock.elapsedRealtime() - mLastForecastCallTimeMillis
+ < INACTIVITY_THRESHOLD_MILLIS) {
+ // Trigger this again after a second as long as forecast has been called more
+ // recently than the inactivity timeout
+ mHandler.postDelayed(this::updateTemperature, 1000);
+ } else {
+ // Otherwise, we've been idle for at least 10 seconds, so we should
+ // shut down
+ mSamples.clear();
+ return;
+ }
+
+ long now = SystemClock.elapsedRealtime();
+ List<Temperature> temperatures = mHalWrapper.getCurrentTemperatures(true,
+ Temperature.TYPE_SKIN);
+
+ for (int t = 0; t < temperatures.size(); ++t) {
+ Temperature temperature = temperatures.get(t);
+
+ // Filter out invalid temperatures. If this results in no values being stored at
+ // all, the mSamples.empty() check in getForecast() will catch it.
+ if (Float.isNaN(temperature.getValue())) {
+ continue;
+ }
+
+ ArrayList<Sample> samples = mSamples.computeIfAbsent(temperature.getName(),
+ k -> new ArrayList<>(RING_BUFFER_SIZE));
+ if (samples.size() == RING_BUFFER_SIZE) {
+ samples.remove(0);
+ }
+ samples.add(new Sample(now, temperature.getValue()));
+ }
+ }
+ }
+
+ /**
+ * Calculates the trend using a linear regression. As the samples are degrees Celsius with
+ * associated timestamps in milliseconds, the slope is in degrees Celsius per millisecond.
+ */
+ private float getSlopeOf(List<Sample> samples) {
+ long sumTimes = 0L;
+ float sumTemperatures = 0.0f;
+ for (int s = 0; s < samples.size(); ++s) {
+ Sample sample = samples.get(s);
+ sumTimes += sample.time;
+ sumTemperatures += sample.temperature;
+ }
+ long meanTime = sumTimes / samples.size();
+ float meanTemperature = sumTemperatures / samples.size();
+
+ long sampleVariance = 0L;
+ float sampleCovariance = 0.0f;
+ for (int s = 0; s < samples.size(); ++s) {
+ Sample sample = samples.get(s);
+ long timeDelta = sample.time - meanTime;
+ float temperatureDelta = sample.temperature - meanTemperature;
+ sampleVariance += timeDelta * timeDelta;
+ sampleCovariance += timeDelta * temperatureDelta;
+ }
+
+ return sampleCovariance / sampleVariance;
+ }
+
+ /**
+ * Used to determine the temperature corresponding to 0.0. Given that 1.0 is pinned at the
+ * temperature corresponding to the SEVERE threshold, we set 0.0 to be that temperature
+ * minus DEGREES_BETWEEN_ZERO_AND_ONE.
+ */
+ private static final float DEGREES_BETWEEN_ZERO_AND_ONE = 30.0f;
+
+ private float normalizeTemperature(float temperature, float severeThreshold) {
+ synchronized (mSamples) {
+ float zeroNormalized = severeThreshold - DEGREES_BETWEEN_ZERO_AND_ONE;
+ if (temperature <= zeroNormalized) {
+ return 0.0f;
+ }
+ float delta = temperature - zeroNormalized;
+ return delta / DEGREES_BETWEEN_ZERO_AND_ONE;
+ }
+ }
+
+ private static final int MINIMUM_SAMPLE_COUNT = 3;
+
+ float getForecast(int forecastSeconds) {
+ synchronized (mSamples) {
+ mLastForecastCallTimeMillis = System.currentTimeMillis();
+ if (mSamples.isEmpty()) {
+ updateTemperature();
+ }
+
+ // If somehow things take much longer than expected or there are no temperatures
+ // to sample, return early
+ if (mSamples.isEmpty()) {
+ Slog.e(TAG, "No temperature samples found");
+ return Float.NaN;
+ }
+
+ // If we don't have any thresholds, we can't normalize the temperatures,
+ // so return early
+ if (mSevereThresholds.isEmpty()) {
+ Slog.e(TAG, "No temperature thresholds found");
+ return Float.NaN;
+ }
+
+ float maxNormalized = Float.NaN;
+ for (Map.Entry<String, ArrayList<Sample>> entry : mSamples.entrySet()) {
+ String name = entry.getKey();
+ ArrayList<Sample> samples = entry.getValue();
+
+ Float threshold = mSevereThresholds.get(name);
+ if (threshold == null) {
+ Slog.e(TAG, "No threshold found for " + name);
+ continue;
+ }
+
+ float currentTemperature = samples.get(0).temperature;
+
+ if (samples.size() < MINIMUM_SAMPLE_COUNT) {
+ // Don't try to forecast, just use the latest one we have
+ float normalized = normalizeTemperature(currentTemperature, threshold);
+ if (Float.isNaN(maxNormalized) || normalized > maxNormalized) {
+ maxNormalized = normalized;
+ }
+ continue;
+ }
+
+ float slope = getSlopeOf(samples);
+ float normalized = normalizeTemperature(
+ currentTemperature + slope * forecastSeconds * 1000, threshold);
+ if (Float.isNaN(maxNormalized) || normalized > maxNormalized) {
+ maxNormalized = normalized;
+ }
+ }
+
+ return maxNormalized;
+ }
+ }
+
+ private class Sample {
+ public long time;
+ public float temperature;
+
+ Sample(long time, float temperature) {
+ this.time = time;
+ this.temperature = temperature;
+ }
+ }
+ }
}
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/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index 761fbf8..e72ba8d 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -50,7 +50,6 @@
implements AlarmManager.OnAlarmListener, Handler.Callback, LocationListener {
private static final String TAG = "TwilightService";
- private static final String FEATURE_ID = "TwilightService";
private static final boolean DEBUG = false;
private static final int MSG_START_LISTENING = 1;
@@ -74,7 +73,7 @@
protected TwilightState mLastTwilightState;
public TwilightService(Context context) {
- super(context.createFeatureContext(FEATURE_ID));
+ super(context);
mHandler = new Handler(Looper.getMainLooper(), this);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 46596e35..688f474 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -111,6 +111,7 @@
import static com.android.server.wm.TaskProto.ADJUST_IME_AMOUNT;
import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS;
import static com.android.server.wm.TaskProto.BOUNDS;
+import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER;
import static com.android.server.wm.TaskProto.DEFER_REMOVAL;
import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
import static com.android.server.wm.TaskProto.DISPLAY_ID;
@@ -731,53 +732,14 @@
newBounds);
hasNewOverrideBounds = true;
}
-
- // Use override windowing mode to prevent extra bounds changes if inheriting the mode.
- if (overrideWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || overrideWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- // If entering split screen or if something about the available split area changes,
- // recalculate the split windows to match the new configuration.
- if (rotationChanged || windowingModeChanged
- || prevDensity != getConfiguration().densityDpi
- || prevScreenW != getConfiguration().screenWidthDp
- || prevScreenH != getConfiguration().screenHeightDp) {
- calculateDockedBoundsForConfigChange(newParentConfig, newBounds);
- hasNewOverrideBounds = true;
- }
- }
}
if (windowingModeChanged) {
- // Use override windowing mode to prevent extra bounds changes if inheriting the mode.
- if (overrideWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- getStackDockedModeBounds(null /* dockedBounds */, null /* currentTempTaskBounds */,
- newBounds /* outStackBounds */, mTmpRect2 /* outTempTaskBounds */);
- // immediately resize so docked bounds are available in onSplitScreenModeActivated
- setTaskDisplayedBounds(null);
- setTaskBounds(newBounds);
- setBounds(newBounds);
- newBounds.set(newBounds);
- } else if (overrideWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- Rect dockedBounds = display.getRootSplitScreenPrimaryTask().getBounds();
- final boolean isMinimizedDock =
- display.mDisplayContent.getDockedDividerController().isMinimizedDock();
- if (isMinimizedDock) {
- Task topTask = display.getRootSplitScreenPrimaryTask().getTopMostTask();
- if (topTask != null) {
- dockedBounds = topTask.getBounds();
- }
- }
- getStackDockedModeBounds(dockedBounds, null /* currentTempTaskBounds */,
- newBounds /* outStackBounds */, mTmpRect2 /* outTempTaskBounds */);
- hasNewOverrideBounds = true;
- }
+ display.onStackWindowingModeChanged(this);
}
if (hasNewOverrideBounds) {
- if (inSplitScreenPrimaryWindowingMode()) {
- mStackSupervisor.resizeDockedStackLocked(new Rect(newBounds),
- null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- null /* tempOtherTaskBounds */, null /* tempOtherTaskInsetBounds */,
- PRESERVE_WINDOWS, true /* deferResume */);
+ if (inSplitScreenWindowingMode()) {
+ setBounds(newBounds);
} else if (overrideWindowingMode != WINDOWING_MODE_PINNED) {
// For pinned stack, resize is now part of the {@link WindowContainerTransaction}
resize(new Rect(newBounds), null /* tempTaskBounds */,
@@ -920,11 +882,7 @@
// warning toast about it.
mAtmService.getTaskChangeNotificationController()
.notifyActivityDismissingDockedStack();
- final ActivityStack primarySplitStack = display.getRootSplitScreenPrimaryTask();
- primarySplitStack.setWindowingModeInSurfaceTransaction(WINDOWING_MODE_UNDEFINED,
- false /* animate */, false /* showRecents */,
- false /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */,
- primarySplitStack == this ? creating : false);
+ display.onSplitScreenModeDismissed();
}
}
@@ -1218,7 +1176,7 @@
display.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
if (topFullScreenStack != null) {
final ActivityStack primarySplitScreenStack = display.getRootSplitScreenPrimaryTask();
- if (display.getIndexOf(topFullScreenStack)
+ if (primarySplitScreenStack != null && display.getIndexOf(topFullScreenStack)
> display.getIndexOf(primarySplitScreenStack)) {
primarySplitScreenStack.moveToFront(reason + " splitScreenToTop");
}
@@ -3999,17 +3957,6 @@
? ((WindowContainer) oldParent).getDisplayContent() : null;
super.onParentChanged(newParent, oldParent);
- if (display != null && inSplitScreenPrimaryWindowingMode()
- // only do this for the base stack
- && !newParent.inSplitScreenPrimaryWindowingMode()) {
- // If we created a docked stack we want to resize it so it resizes all other stacks
- // in the system.
- getStackDockedModeBounds(null /* dockedBounds */, null /* currentTempTaskBounds */,
- mTmpRect /* outStackBounds */, mTmpRect2 /* outTempTaskBounds */);
- mStackSupervisor.resizeDockedStackLocked(getRequestedOverrideBounds(), mTmpRect,
- mTmpRect2, null, null, PRESERVE_WINDOWS);
- }
-
// Resume next focusable stack after reparenting to another display if we aren't removing
// the prevous display.
if (oldDisplay != null && oldDisplay.isRemoving()) {
@@ -4955,6 +4902,12 @@
}
@Override
+ public SurfaceControl getParentSurfaceControl() {
+ // Tile is a "virtual" parent, so we need to intercept the parent surface here
+ return mTile != null ? mTile.getSurfaceControl() : super.getParentSurfaceControl();
+ }
+
+ @Override
void removeImmediately() {
// TODO(task-hierarchy): remove this override when tiles are in hierarchy
if (mTile != null) {
@@ -5007,6 +4960,10 @@
if (!matchParentBounds()) {
final Rect bounds = getRequestedOverrideBounds();
bounds.dumpDebug(proto, BOUNDS);
+ } else if (getStack().getTile() != null) {
+ // use tile's bounds here for cts.
+ final Rect bounds = getStack().getTile().getRequestedOverrideBounds();
+ bounds.dumpDebug(proto, BOUNDS);
}
getOverrideDisplayedBounds().dumpDebug(proto, DISPLAYED_BOUNDS);
mAdjustedBounds.dumpDebug(proto, ADJUSTED_BOUNDS);
@@ -5026,6 +4983,8 @@
proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
}
+ proto.write(CREATED_BY_ORGANIZER, this instanceof TaskTile);
+
proto.end(token);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 7720f7f..70cd01b 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2457,7 +2457,9 @@
// split-screen in split-screen.
mService.getTaskChangeNotificationController()
.notifyActivityDismissingDockedStack();
- moveTasksToFullscreenStackLocked(dockedStack, actualStack == dockedStack);
+ dockedStack.getDisplay().onSplitScreenModeDismissed();
+ dockedStack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+ true /* notifyClients */);
}
return;
}
@@ -2819,7 +2821,7 @@
final DisplayContent display = task.getStack().getDisplay();
final ActivityStack topSecondaryStack =
display.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- if (topSecondaryStack.isActivityTypeHome()) {
+ if (topSecondaryStack != null && topSecondaryStack.isActivityTypeHome()) {
// If the home activity is the top split-screen secondary stack, then the
// primary split-screen stack is in the minimized mode which means it can't
// receive input keys, so we should move the focused app to the home app so that
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 132e486..882d5c7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -37,7 +37,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -229,6 +228,7 @@
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
+import android.view.WindowContainerTransaction;
import android.view.WindowManager;
import com.android.internal.R;
@@ -2269,6 +2269,9 @@
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
+ if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
+ return setTaskWindowingModeSplitScreen(taskId, windowingMode, toTop);
+ }
final Task task = mRootWindowContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
@@ -2286,10 +2289,16 @@
}
final ActivityStack stack = task.getStack();
+ // Convert some windowing-mode changes into root-task reparents for split-screen.
+ if (stack.getTile() != null) {
+ stack.getDisplay().onSplitScreenModeDismissed();
+ }
if (toTop) {
stack.moveToFront("setTaskWindowingMode", task);
}
stack.setWindowingMode(windowingMode);
+ stack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+ true /* notifyClients */);
return true;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2719,36 +2728,8 @@
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
- if (isInLockTaskMode()) {
- Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: Is in lock task mode="
- + getLockTaskModeState());
- return false;
- }
-
- final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
- if (task == null) {
- Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId);
- return false;
- }
- if (!task.isActivityTypeStandardOrUndefined()) {
- throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
- + " non-standard task " + taskId + " to split-screen windowing mode");
- }
-
- if (DEBUG_STACK) Slog.d(TAG_STACK,
- "setTaskWindowingModeSplitScreenPrimary: moving task=" + taskId
- + " to createMode=" + createMode + " toTop=" + toTop);
- mWindowManager.setDockedStackCreateStateLocked(createMode, initialBounds);
- final int windowingMode = task.getWindowingMode();
- final ActivityStack stack = task.getStack();
- if (toTop) {
- stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task);
- }
- stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate, showRecents,
- false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
- false /* creating */);
- return windowingMode != task.getWindowingMode();
+ return setTaskWindowingModeSplitScreen(taskId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ toTop);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2756,6 +2737,49 @@
}
/**
+ * Moves the specified task into a split-screen tile.
+ */
+ private boolean setTaskWindowingModeSplitScreen(int taskId, int windowingMode, boolean toTop) {
+ if (!WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
+ throw new IllegalArgumentException("Calling setTaskWindowingModeSplitScreen with non"
+ + "split-screen mode: " + windowingMode);
+ }
+ if (isInLockTaskMode()) {
+ Slog.w(TAG, "setTaskWindowingModeSplitScreen: Is in lock task mode="
+ + getLockTaskModeState());
+ return false;
+ }
+
+ final Task task = mRootWindowContainer.anyTaskForId(taskId,
+ MATCH_TASK_IN_STACKS_ONLY);
+ if (task == null) {
+ Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId);
+ return false;
+ }
+ if (!task.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
+ + " non-standard task " + taskId + " to split-screen windowing mode");
+ }
+
+ final int prevMode = task.getWindowingMode();
+ final ActivityStack stack = task.getStack();
+ TaskTile tile = null;
+ for (int i = stack.getDisplay().getStackCount() - 1; i >= 0; --i) {
+ tile = stack.getDisplay().getStackAt(i).asTile();
+ if (tile != null && tile.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ break;
+ }
+ }
+ if (tile == null) {
+ throw new IllegalStateException("Can't enter split without associated tile");
+ }
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reparent(stack.mRemoteToken, tile.mRemoteToken, toTop);
+ mTaskOrganizerController.applyContainerTransaction(wct, null);
+ return prevMode != task.getWindowingMode();
+ }
+
+ /**
* Removes stacks in the input windowing modes from the system if they are of activity type
* ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
*/
@@ -3963,46 +3987,6 @@
}
/**
- * Dismisses split-screen multi-window mode.
- * @param toTop If true the current primary split-screen stack will be placed or left on top.
- */
- @Override
- public void dismissSplitScreenMode(boolean toTop) {
- enforceCallerIsRecentsOrHasPermission(
- MANAGE_ACTIVITY_STACKS, "dismissSplitScreenMode()");
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- final ActivityStack stack =
- mRootWindowContainer.getDefaultDisplay().getRootSplitScreenPrimaryTask();
- if (stack == null) {
- Slog.w(TAG, "dismissSplitScreenMode: primary split-screen stack not found.");
- return;
- }
-
- if (toTop) {
- // Caller wants the current split-screen primary stack to be the top stack after
- // it goes fullscreen, so move it to the front.
- stack.moveToFront("dismissSplitScreenMode");
- } else {
- // In this case the current split-screen primary stack shouldn't be the top
- // stack after it goes fullscreen, so we move the focus to the top-most
- // split-screen secondary stack next to it.
- final ActivityStack otherStack = stack.getDisplay().getTopStackInWindowingMode(
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- if (otherStack != null) {
- otherStack.moveToFront("dismissSplitScreenMode_other");
- }
- }
-
- stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- /**
* Dismisses Pip
* @param animate True if the dismissal should be animated.
* @param animationDuration The duration of the resize animation in milliseconds or -1 if the
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 840abb1..e60ab3f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -16,9 +16,7 @@
package com.android.server.wm;
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -32,6 +30,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -56,9 +55,6 @@
import static android.view.View.GONE;
import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_TOP;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -84,9 +80,6 @@
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
-import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
-import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
-import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -105,12 +98,15 @@
import static com.android.server.wm.DisplayContentProto.DOCKED_STACK_DIVIDER_CONTROLLER;
import static com.android.server.wm.DisplayContentProto.DPI;
import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
+import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
import static com.android.server.wm.DisplayContentProto.ID;
import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
import static com.android.server.wm.DisplayContentProto.OVERLAY_WINDOWS;
+import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
import static com.android.server.wm.DisplayContentProto.ROTATION;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
+import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE;
import static com.android.server.wm.DisplayContentProto.TASKS;
import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
@@ -1553,6 +1549,20 @@
}
/**
+ * If the provided {@link ActivityRecord} can be displayed in an orientation different from the
+ * display's, it will be rotated to match its requested orientation.
+ *
+ * @see #rotationForActivityInDifferentOrientation(ActivityRecord).
+ * @see WindowToken#applyFixedRotationTransform(DisplayInfo, DisplayFrames, Configuration)
+ */
+ void rotateInDifferentOrientationIfNeeded(ActivityRecord activityRecord) {
+ int rotation = rotationForActivityInDifferentOrientation(activityRecord);
+ if (rotation != NO_ROTATION) {
+ startFixedRotationTransform(activityRecord, rotation);
+ }
+ }
+
+ /**
* Update rotation of the display.
*
* @return {@code true} if the rotation has been changed. In this case YOU MUST CALL
@@ -2794,54 +2804,9 @@
void adjustForImeIfNeeded() {
final WindowState imeWin = mInputMethodWindow;
- final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
- && !mDividerControllerLocked.isImeHideRequested();
- final ActivityStack dockedStack = getRootSplitScreenPrimaryTask();
- final boolean dockVisible = dockedStack != null;
- final Task topDockedTask = dockVisible ? dockedStack.getTask((t) -> true): null;
- final ActivityStack imeTargetStack = mWmService.getImeFocusStackLocked();
- final int imeDockSide = (dockVisible && imeTargetStack != null) ?
- imeTargetStack.getDockSide() : DOCKED_INVALID;
- final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
- final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
+ final boolean imeVisible = imeWin != null && imeWin.isVisibleLw()
+ && imeWin.isDisplayedLw();
final int imeHeight = mDisplayFrames.getInputMethodWindowVisibleHeight();
- final boolean imeHeightChanged = imeVisible &&
- imeHeight != mDividerControllerLocked.getImeHeightAdjustedFor();
-
- // This includes a case where the docked stack is unminimizing and IME is visible for the
- // bottom side stack. The condition prevents adjusting the override task bounds for IME to
- // the minimized docked stack bounds.
- final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock()
- || (topDockedTask != null && imeOnBottom && !dockedStack.isAdjustedForIme()
- && dockedStack.getBounds().height() < topDockedTask.getBounds().height());
-
- // The divider could be adjusted for IME position, or be thinner than usual,
- // or both. There are three possible cases:
- // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
- // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
- // - If IME is not visible, divider is not moved and is normal width.
-
- if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
- for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
- final ActivityStack stack = mTaskContainers.getChildAt(i);
- final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
- if (stack.isVisible() && (imeOnBottom || isDockedOnBottom)
- && stack.inSplitScreenWindowingMode()) {
- stack.setAdjustedForIme(imeWin, imeOnBottom && imeHeightChanged);
- } else {
- stack.resetAdjustedForIme(false);
- }
- }
- mDividerControllerLocked.setAdjustedForIme(
- imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
- } else {
- for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
- final ActivityStack stack = mTaskContainers.getChildAt(i);
- stack.resetAdjustedForIme(!dockVisible);
- }
- mDividerControllerLocked.setAdjustedForIme(
- false /*ime*/, false /*divider*/, dockVisible /*animate*/, imeWin, imeHeight);
- }
mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
}
@@ -3625,20 +3590,25 @@
mInputMethodTarget = target;
mInputMethodTargetWaitingAnim = targetWaitingAnim;
assignWindowLayers(false /* setLayoutNeeded */);
- mInputMethodControlTarget = computeImeControlTarget();
- mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
+ updateImeControlTarget(mInputMethodTarget);
updateImeParent();
}
/**
* IME control target is the window that controls the IME visibility and animation.
* This window is same as the window on which startInput is called.
- * @param target the window that receives IME control.
+ * @param target the window that receives IME control. This is ignored if we aren't attaching
+ * the IME to an app (eg. when in multi-window mode).
*
* @see #getImeControlTarget()
*/
- void updateImeControlTarget(WindowState target) {
- mInputMethodControlTarget = target;
+ void updateImeControlTarget(InsetsControlTarget target) {
+ if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) {
+ mInputMethodControlTarget = mRemoteInsetsControlTarget;
+ } else {
+ // Otherwise, we just use the ime target
+ mInputMethodControlTarget = target;
+ }
mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
}
@@ -3671,19 +3641,6 @@
return mWindowContainers.getSurfaceControl();
}
- /**
- * Computes which control-target the IME should be attached to.
- */
- @VisibleForTesting
- InsetsControlTarget computeImeControlTarget() {
- if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) {
- return mRemoteInsetsControlTarget;
- }
-
- // Otherwise, we just use the ime target
- return mInputMethodTarget;
- }
-
void setLayoutNeeded() {
if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
mLayoutNeeded = true;
@@ -4069,7 +4026,7 @@
}
}
- /** @returns the orientation of the display when it's rotation is ROTATION_0. */
+ /** @return the orientation of the display when it's rotation is ROTATION_0. */
int getNaturalOrientation() {
return mBaseDisplayWidth < mBaseDisplayHeight
? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
@@ -4510,8 +4467,6 @@
}
} else {
mRootSplitScreenPrimaryTask = stack;
- mDisplayContent.onSplitScreenModeActivated();
- mDividerControllerLocked.notifyDockedStackExistsChanged(true);
}
}
}
@@ -4523,11 +4478,6 @@
mRootPinnedTask = null;
} else if (stack == mRootSplitScreenPrimaryTask) {
mRootSplitScreenPrimaryTask = null;
- mDisplayContent.onSplitScreenModeDismissed();
- // Re-set the split-screen create mode whenever the split-screen stack is removed.
- mWmService.setDockedStackCreateStateLocked(
- SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
- mDividerControllerLocked.notifyDockedStackExistsChanged(false);
}
}
@@ -5943,6 +5893,33 @@
return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent);
}
+ /** @return the tile to create the next stack in. */
+ private TaskTile updateLaunchTile(int windowingMode) {
+ if (!isSplitScreenWindowingMode(windowingMode)) {
+ // Only split-screen windowing modes interact with tiles.
+ return null;
+ }
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final TaskTile t = getStackAt(i).asTile();
+ if (t == null || t.getRequestedOverrideWindowingMode() != windowingMode) {
+ continue;
+ }
+ // If not already set, pick a launch tile which is not the one we are launching
+ // into.
+ if (mLaunchTile == null) {
+ for (int j = 0, n = getStackCount(); j < n; ++j) {
+ TaskTile tt = getStackAt(j).asTile();
+ if (tt != t) {
+ mLaunchTile = tt;
+ break;
+ }
+ }
+ }
+ return t;
+ }
+ return mLaunchTile;
+ }
+
@VisibleForTesting
ActivityStack createStackUnchecked(int windowingMode, int activityType,
int stackId, boolean onTop, ActivityInfo info, Intent intent) {
@@ -5955,13 +5932,20 @@
info.applicationInfo = new ApplicationInfo();
}
+ TaskTile tile = updateLaunchTile(windowingMode);
+ if (tile != null) {
+ // Since this stack will be put into a tile, its windowingMode will be inherited.
+ windowingMode = WINDOWING_MODE_UNDEFINED;
+ }
final ActivityStack stack = new ActivityStack(this, stackId,
mRootWindowContainer.mStackSupervisor, activityType, info, intent);
addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
true /* creating */);
-
+ if (tile != null) {
+ tile.addChild(stack, 0 /* index */);
+ }
return stack;
}
@@ -6181,16 +6165,15 @@
void onSplitScreenModeDismissed() {
mAtmService.deferWindowLayout();
try {
- // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
+ mLaunchTile = null;
for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack otherStack = getStackAt(i);
- if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
- continue;
+ final TaskTile t = getStackAt(i).asTile();
+ if (t != null) {
+ t.removeAllChildren();
}
- otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED, false /* animate */,
- false /* showRecents */, false /* enteringSplitScreenMode */,
- true /* deferEnsuringVisibility */, false /* creating */);
}
+ mDividerControllerLocked.setMinimizedDockedStack(false /* minimized */,
+ false /* animate */);
} finally {
final ActivityStack topFullscreenStack =
getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -6208,27 +6191,6 @@
}
}
- void onSplitScreenModeActivated() {
- mAtmService.deferWindowLayout();
- try {
- // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
- final ActivityStack splitScreenPrimaryStack = getRootSplitScreenPrimaryTask();
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack otherStack = getStackAt(i);
- if (otherStack == splitScreenPrimaryStack
- || !otherStack.affectedBySplitScreenResize()) {
- continue;
- }
- otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
- false /* animate */, false /* showRecents */,
- true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */,
- false /* creating */);
- }
- } finally {
- mAtmService.continueWindowLayout();
- }
- }
-
/**
* Returns true if the {@param windowingMode} is supported based on other parameters passed in.
* @param windowingMode The windowing mode we are checking support for.
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e443fe4..f02a9dd 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -131,7 +131,6 @@
import android.graphics.Region;
import android.hardware.input.InputManager;
import android.hardware.power.V1_0.PowerHint;
-import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -304,6 +303,8 @@
private boolean mIsFreeformWindowOverlappingWithNavBar;
+ private boolean mLastImmersiveMode;
+
private final StatusBarController mStatusBarController;
private final BarController mNavigationBarController;
@@ -3182,8 +3183,8 @@
if (nb) mNavigationBarController.showTransient();
updateSystemUiVisibilityLw();
}
- mImmersiveModeConfirmation.confirmCurrentPrompt();
}
+ mImmersiveModeConfirmation.confirmCurrentPrompt();
}
}
@@ -3210,7 +3211,7 @@
updateSystemUiVisibilityLw();
}
- private int updateSystemUiVisibilityLw() {
+ int updateSystemUiVisibilityLw() {
// If there is no window focused, there will be nobody to handle the events
// anyway, so just hang on in whatever state we're in until things settle down.
WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
@@ -3566,9 +3567,11 @@
vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
// update navigation bar
- boolean oldImmersiveMode = isImmersiveMode(oldVis);
- boolean newImmersiveMode = isImmersiveMode(vis);
+ boolean newInsetsMode = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL;
+ boolean oldImmersiveMode = newInsetsMode ? mLastImmersiveMode : isImmersiveMode(oldVis);
+ boolean newImmersiveMode = newInsetsMode ? isImmersiveMode(win) : isImmersiveMode(vis);
if (oldImmersiveMode != newImmersiveMode) {
+ mLastImmersiveMode = newImmersiveMode;
final String pkg = win.getOwningPackage();
mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
mService.mPolicy.isUserSetupComplete(),
@@ -3673,6 +3676,7 @@
}
}
+ // TODO(b/118118435): Remove this after migration
private boolean isImmersiveMode(int vis) {
final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
return mNavigationBar != null
@@ -3681,6 +3685,16 @@
&& canHideNavigationBar();
}
+ private boolean isImmersiveMode(WindowState win) {
+ final int behavior = win.mAttrs.insetsFlags.behavior;
+ return mNavigationBar != null
+ && canHideNavigationBar()
+ && (behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
+ || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
+ && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
+ && win != getNotificationShade();
+ }
+
/**
* @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
*/
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 1a0dcb9..64c5faa 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -527,9 +527,15 @@
}
mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
mIsWaitingForRemoteRotation = false;
- mDisplayContent.sendNewConfiguration();
- if (t != null) {
- mService.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+ mService.mAtmService.deferWindowLayout();
+ try {
+ mDisplayContent.sendNewConfiguration();
+ if (t != null) {
+ mService.mAtmService.mTaskOrganizerController.applyContainerTransaction(t,
+ null /* organizer */);
+ }
+ } finally {
+ mService.mAtmService.continueWindowLayout();
}
}
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 872379e..6431e11 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -745,7 +745,7 @@
* @param minimizedDock Whether the docked stack is currently minimized.
* @param animate Whether to animate the change.
*/
- private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
+ void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
final boolean wasMinimized = mMinimizedDock;
mMinimizedDock = minimizedDock;
if (minimizedDock == wasMinimized) {
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a8fe349..b3890cd 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -182,6 +182,7 @@
}
if (changed) {
notifyInsetsChanged();
+ mDisplayContent.getDisplayPolicy().updateSystemUiVisibilityLw();
}
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 00947d7..44034ed 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -31,14 +31,14 @@
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.KeyguardControllerProto.AOD_SHOWING;
import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_SHOWING;
import static com.android.server.wm.KeyguardOccludedProto.DISPLAY_ID;
import static com.android.server.wm.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
-import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.os.IBinder;
import android.os.RemoteException;
@@ -411,8 +411,7 @@
if (stack == null) {
return;
}
- mStackSupervisor.moveTasksToFullscreenStackLocked(stack,
- stack.isFocusedStackOnDisplay());
+ mRootWindowContainer.getDefaultDisplay().onSplitScreenModeDismissed();
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 251d0f1..e923e64 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -20,7 +20,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
-import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -34,6 +33,7 @@
import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.app.ActivityManager.TaskSnapshot;
import android.app.WindowConfiguration;
import android.graphics.Point;
@@ -414,15 +414,15 @@
}
// Save the minimized home height
- final ActivityStack dockedStack =
- mDisplayContent.getRootSplitScreenPrimaryTask();
- mDisplayContent.getDockedDividerController().getHomeStackBoundsInDockedMode(
- mDisplayContent.getConfiguration(),
- dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(),
- mMinimizedHomeBounds);
+ mMinimizedHomeBounds = mDisplayContent.getRootHomeTask().getBounds();
mService.mWindowPlacerLocked.performSurfacePlacement();
+ // If the target activity has a fixed orientation which is different from the current top
+ // activity, it will be rotated before being shown so we avoid a screen rotation
+ // animation when showing the Recents view.
+ mDisplayContent.rotateInDifferentOrientationIfNeeded(mTargetActivityRecord);
+
// Notify that the animation has started
if (mStatusBar != null) {
mStatusBar.onRecentsAnimationStateChanged(true /* running */);
@@ -695,6 +695,9 @@
mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
mTargetActivityRecord.token);
}
+ if (mTargetActivityRecord.hasFixedRotationTransform()) {
+ mTargetActivityRecord.clearFixedRotationTransform();
+ }
}
// Notify that the animation has ended
@@ -828,6 +831,19 @@
return task != null && isAnimatingTask(task) && !isTargetApp(windowState.mActivityRecord);
}
+ /**
+ * If the animation target ActivityRecord has a fixed rotation ({@link
+ * WindowToken#hasFixedRotationTransform()}, the provided wallpaper will be rotated accordingly.
+ *
+ * This avoids any screen rotation animation when animating to the Recents view.
+ */
+ void applyFixedRotationTransformIfNeeded(@NonNull WindowToken wallpaper) {
+ if (mTargetActivityRecord == null) {
+ return;
+ }
+ wallpaper.applyFixedRotationTransform(mTargetActivityRecord);
+ }
+
@VisibleForTesting
class TaskAnimationAdapter implements AnimationAdapter {
@@ -844,8 +860,8 @@
mTask = task;
mIsRecentTaskInvisible = isRecentTaskInvisible;
final WindowContainer container = mTask.getParent();
- container.getRelativeDisplayedPosition(mPosition);
mBounds.set(container.getDisplayedBounds());
+ mPosition.set(mBounds.left, mBounds.top);
}
RemoteAnimationTarget createRemoteAnimationTarget() {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 34b5c11..5554b1d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -422,6 +422,8 @@
/** When set, will force the task to report as invisible. */
boolean mForceHidden = false;
+ SurfaceControl.Transaction mMainWindowSizeChangeTransaction;
+
private final FindRootHelper mFindRootHelper = new FindRootHelper();
private class FindRootHelper {
private ActivityRecord mRoot;
@@ -2145,12 +2147,6 @@
// For floating tasks, calculate the smallest width from the bounds of the task
inOutConfig.smallestScreenWidthDp = (int) (
Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
- } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
- // Iterating across all screen orientations, and return the minimum of the task
- // width taking into account that the bounds might change because the snap
- // algorithm snaps to a different value
- inOutConfig.smallestScreenWidthDp =
- getSmallestScreenWidthDpForDockedBounds(mTmpFullBounds);
}
// otherwise, it will just inherit
}
@@ -3257,6 +3253,10 @@
return this;
}
+ TaskTile asTile() {
+ return null;
+ }
+
// TODO(task-merge): Figure-out how this should work with hierarchy tasks.
boolean shouldBeVisible(ActivityRecord starting) {
return true;
@@ -3981,4 +3981,17 @@
mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
this, true /* force */);
}
+
+ /**
+ * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this
+ * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy
+ * to resize, and it will defer the transaction until that resize frame completes.
+ */
+ void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) {
+ mMainWindowSizeChangeTransaction = t;
+ }
+
+ SurfaceControl.Transaction getMainWindowSizeChangeTransaction() {
+ return mMainWindowSizeChangeTransaction;
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 4b13a0c..202e089 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -492,6 +492,10 @@
if (!(container instanceof Task)) {
throw new IllegalArgumentException("Invalid container in hierarchy op");
}
+ if (container.getDisplayContent() == null) {
+ Slog.w(TAG, "Container is no longer attached: " + container);
+ return 0;
+ }
if (hop.isReparent()) {
// special case for tiles since they are "virtual" parents
if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
@@ -553,6 +557,12 @@
WindowContainerTransaction.Change c) {
int effects = sanitizeAndApplyChange(wc, c);
+ final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
+ if (t != null) {
+ Task tr = (Task) wc;
+ tr.setMainWindowSizeChangeTransaction(t);
+ }
+
Rect enterPipBounds = c.getEnterPipBounds();
if (enterPipBounds != null) {
Task tr = (Task) wc;
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
index 369db05..74d5c33 100644
--- a/services/core/java/com/android/server/wm/TaskTile.java
+++ b/services/core/java/com/android/server/wm/TaskTile.java
@@ -31,7 +31,6 @@
import android.graphics.Rect;
import android.os.IBinder;
import android.util.Slog;
-import android.view.SurfaceControl;
import java.util.ArrayList;
import java.util.Comparator;
@@ -78,30 +77,9 @@
// Virtual parent, so don't notify children.
}
- /**
- * If there is a disconnection, this will clean up any vestigial surfaces left on the tile
- * leash by moving known children to a new surfacecontrol and then removing the old one.
- */
- void cleanupSurfaces() {
- if (mSurfaceControl == null) {
- return;
- }
- SurfaceControl oldSurface = mSurfaceControl;
- WindowContainer parentWin = getParent();
- if (parentWin == null) {
- return;
- }
- mSurfaceControl = parentWin.makeChildSurface(null).setName("TaskTile " + mTaskId + " - "
- + getRequestedOverrideWindowingMode()).setContainerLayer().build();
- SurfaceControl.Transaction t = parentWin.getPendingTransaction();
- t.show(mSurfaceControl);
- for (int i = 0; i < mChildren.size(); ++i) {
- if (mChildren.get(i).getSurfaceControl() == null) {
- continue;
- }
- mChildren.get(i).reparentSurfaceControl(t, mSurfaceControl);
- }
- t.remove(oldSurface);
+ @Override
+ TaskTile asTile() {
+ return this;
}
@Override
@@ -215,6 +193,12 @@
super.removeImmediately();
}
+ @Override
+ void taskOrganizerDied() {
+ super.taskOrganizerDied();
+ removeImmediately();
+ }
+
static TaskTile forToken(IBinder token) {
try {
return (TaskTile) ((TaskToken) token).getContainer();
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index d23bf97..1e22141 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -122,10 +122,37 @@
mDisplayContent.setLayoutNeeded();
}
- final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+ final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+
+ if (visible) {
+ final WindowState wallpaperTarget = wallpaperController.getWallpaperTarget();
+ final RecentsAnimationController recentsAnimationController =
+ mWmService.getRecentsAnimationController();
+ if (wallpaperTarget != null
+ && recentsAnimationController != null
+ && recentsAnimationController.isAnimatingTask(wallpaperTarget.getTask())) {
+ // If the Recents animation is running, and the wallpaper target is the animating
+ // task we want the wallpaper to be rotated in the same orientation as the
+ // RecentsAnimation's target (e.g the launcher)
+ recentsAnimationController.applyFixedRotationTransformIfNeeded(this);
+ } else if (wallpaperTarget != null
+ && wallpaperTarget.mToken.hasFixedRotationTransform()) {
+ // If the wallpaper target has a fixed rotation, we want the wallpaper to follow its
+ // rotation
+ applyFixedRotationTransform(wallpaperTarget.mToken);
+ } else if (hasFixedRotationTransform()) {
+ clearFixedRotationTransform();
+ }
+ }
+
+ DisplayInfo displayInfo = getFixedRotationTransformDisplayInfo();
+ if (displayInfo == null) {
+ displayInfo = mDisplayContent.getDisplayInfo();
+ }
+
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
- final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+
for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
final WindowState wallpaper = mChildren.get(wallpaperNdx);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2a7d551..68b8348 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7492,15 +7492,14 @@
synchronized (mGlobalLock) {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc != null) {
- WindowState imeTarget = dc.getImeControlTarget();
- if (imeTarget == null) {
+ InsetsControlTarget imeControlTarget = dc.mInputMethodControlTarget;
+ if (imeControlTarget == null) {
return;
}
// If there was a pending IME show(), reset it as IME has been
// requested to be hidden.
- imeTarget.getDisplayContent().getInsetsStateController().getImeSourceProvider()
- .abortShowImePostLayout();
- imeTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */);
+ dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
+ imeControlTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1cfd0d4..b250083 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2686,18 +2686,6 @@
mWmService.mTaskSnapshotController.onAppDied(win.mActivityRecord);
}
win.removeIfPossible(shouldKeepVisibleDeadAppWindow());
- if (win.mAttrs.type == TYPE_DOCK_DIVIDER) {
- // The owner of the docked divider died :( We reset the docked stack,
- // just in case they have the divider at an unstable position. Better
- // also reset drag resizing state, because the owner can't do it
- // anymore.
- final ActivityStack stack =
- dc.getRootSplitScreenPrimaryTask();
- if (stack != null) {
- stack.resetDockedStackToMiddle();
- }
- resetSplitScreenResizing = true;
- }
} else if (mHasSurface) {
Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
WindowState.this.removeIfPossible();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9552df7..a1a9af6 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -873,6 +873,14 @@
clipRect = mTmpClipRect;
}
+ if (mSurfaceResized && (mAttrType == TYPE_BASE_APPLICATION) &&
+ (task != null) && (task.getMainWindowSizeChangeTransaction() != null)) {
+ mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(),
+ mWin.getFrameNumber());
+ SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction());
+ task.setMainWindowSizeChangeTransaction(null);
+ }
+
float surfaceWidth = mSurfaceController.getWidth();
float surfaceHeight = mSurfaceController.getHeight();
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 1180566..48c7812 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -377,6 +377,19 @@
onConfigurationChanged(getParent().getConfiguration());
}
+ /**
+ * Copies the {@link FixedRotationTransformState} (if any) from the other WindowToken to this
+ * one.
+ */
+ void applyFixedRotationTransform(WindowToken other) {
+ final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState;
+ if (fixedRotationState != null) {
+ applyFixedRotationTransform(fixedRotationState.mDisplayInfo,
+ fixedRotationState.mDisplayFrames,
+ fixedRotationState.mRotatedOverrideConfiguration);
+ }
+ }
+
/** Clears the transformation and continue updating the orientation change of display. */
void clearFixedRotationTransform() {
if (mFixedRotationTransformState == null) {
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..012fdfc 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 |
@@ -1072,7 +1073,8 @@
private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps";
private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile-max-time-off";
private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline";
-
+ private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package";
+ private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown";
DeviceAdminInfo info;
@@ -1201,6 +1203,9 @@
// Time by which the profile should be turned on according to System.currentTimeMillis().
long mProfileOffDeadline = 0;
+ public String mAlwaysOnVpnPackage;
+ public boolean mAlwaysOnVpnLockdown;
+
ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
info = _info;
@@ -1441,6 +1446,12 @@
if (mProfileMaximumTimeOff != 0) {
writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline);
}
+ if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) {
+ writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_PACKAGE, mAlwaysOnVpnPackage);
+ }
+ if (mAlwaysOnVpnLockdown) {
+ writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown);
+ }
}
void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
@@ -1686,6 +1697,11 @@
} else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) {
mProfileOffDeadline =
Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) {
+ mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE);
+ } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) {
+ mAlwaysOnVpnLockdown = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1918,6 +1934,10 @@
pw.println(mProfileMaximumTimeOff);
pw.print("mProfileOffDeadline=");
pw.println(mProfileOffDeadline);
+ pw.print("mAlwaysOnVpnPackage=");
+ pw.println(mAlwaysOnVpnPackage);
+ pw.print("mAlwaysOnVpnLockdown=");
+ pw.println(mAlwaysOnVpnLockdown);
}
}
@@ -2290,6 +2310,11 @@
context, requestCode, intent, flags, options, user);
}
+ PendingIntent pendingIntentGetBroadcast(
+ Context context, int requestCode, Intent intent, int flags) {
+ return PendingIntent.getBroadcast(context, requestCode, intent, flags);
+ }
+
void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer, int userHandle) {
mContext.getContentResolver().registerContentObserver(uri, notifyForDescendents,
@@ -2748,11 +2773,11 @@
}
if (!mInjector.systemPropertiesGet(PROPERTY_DEVICE_OWNER_PRESENT, "").isEmpty()) {
- Slog.w(LOG_TAG, "Trying to set ro.device_owner, but it has already been set?");
+ Slog.w(LOG_TAG, "Trying to set ro.organization_owned, but it has already been set?");
} else {
final String value = Boolean.toString(hasDeviceOwner);
mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, value);
- Slog.i(LOG_TAG, "Set ro.device_owner property to " + value);
+ Slog.i(LOG_TAG, "Set ro.organization_owned property to " + value);
}
}
@@ -6775,10 +6800,10 @@
* @throws UnsupportedOperationException if the package does not support being set as always-on.
*/
@Override
- public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown,
+ public boolean setAlwaysOnVpnPackage(ComponentName who, String vpnPackage, boolean lockdown,
List<String> lockdownWhitelist)
throws SecurityException {
- enforceProfileOrDeviceOwner(admin);
+ enforceProfileOrDeviceOwner(who);
final int userId = mInjector.userHandleGetCallingUserId();
mInjector.binderWithCleanCallingIdentity(() -> {
@@ -6804,12 +6829,22 @@
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE)
- .setAdmin(admin)
+ .setAdmin(who)
.setStrings(vpnPackage)
.setBoolean(lockdown)
.setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0)
.write();
});
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage)
+ || lockdown != admin.mAlwaysOnVpnLockdown) {
+ admin.mAlwaysOnVpnPackage = vpnPackage;
+ admin.mAlwaysOnVpnLockdown = lockdown;
+ saveSettingsLocked(userId);
+ }
+ }
return true;
}
@@ -6823,6 +6858,15 @@
}
@Override
+ public String getAlwaysOnVpnPackageForUser(int userHandle) {
+ enforceSystemCaller("getAlwaysOnVpnPackageForUser");
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle);
+ return admin != null ? admin.mAlwaysOnVpnPackage : null;
+ }
+ }
+
+ @Override
public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
enforceProfileOrDeviceOwner(admin);
@@ -6832,6 +6876,15 @@
}
@Override
+ public boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle) {
+ enforceSystemCaller("isAlwaysOnVpnLockdownEnabledForUser");
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle);
+ return admin != null ? admin.mAlwaysOnVpnLockdown : null;
+ }
+ }
+
+ @Override
public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin)
throws SecurityException {
enforceProfileOrDeviceOwner(admin);
@@ -7036,9 +7089,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)
@@ -8977,6 +9034,19 @@
return null;
}
+ /**
+ * Returns the ActiveAdmin associated wit the PO or DO on the given user.
+ * @param userHandle
+ * @return
+ */
+ private @Nullable ActiveAdmin getDeviceOrProfileOwnerAdminLocked(int userHandle) {
+ ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
+ if (admin == null && getDeviceOwnerUserId() == userHandle) {
+ admin = getDeviceOwnerAdminLocked();
+ }
+ return admin;
+ }
+
@GuardedBy("getLockObject()")
ActiveAdmin getProfileOwnerOfOrganizationOwnedDeviceLocked(int userHandle) {
return mInjector.binderWithCleanCallingIdentity(() -> {
@@ -10036,35 +10106,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 +14554,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 +15710,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 +15846,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/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 663bf4f..2499614 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -88,7 +88,7 @@
@Override
public void onCreatePredictionSession(AppPredictionContext context,
AppPredictionSessionId sessionId) {
- mSessions.put(sessionId, new SessionInfo(context, mDataManager));
+ mSessions.put(sessionId, new SessionInfo(context, mDataManager, sessionId.getUserId()));
}
@Override
diff --git a/services/people/java/com/android/server/people/SessionInfo.java b/services/people/java/com/android/server/people/SessionInfo.java
index eaa0781..28612f1 100644
--- a/services/people/java/com/android/server/people/SessionInfo.java
+++ b/services/people/java/com/android/server/people/SessionInfo.java
@@ -16,6 +16,7 @@
package com.android.server.people;
+import android.annotation.UserIdInt;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppTarget;
import android.app.prediction.IPredictionCallback;
@@ -38,9 +39,10 @@
private final RemoteCallbackList<IPredictionCallback> mCallbacks =
new RemoteCallbackList<>();
- SessionInfo(AppPredictionContext predictionContext, DataManager dataManager) {
+ SessionInfo(AppPredictionContext predictionContext, DataManager dataManager,
+ @UserIdInt int callingUserId) {
mAppTargetPredictor = AppTargetPredictor.create(predictionContext,
- this::updatePredictions, dataManager);
+ this::updatePredictions, dataManager, callingUserId);
}
void addCallback(IPredictionCallback callback) {
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 dd9cbd0..7eb2176 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -34,13 +34,11 @@
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ShortcutInfo;
-import android.content.pm.ShortcutManager;
import android.content.pm.ShortcutManager.ShareShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.net.Uri;
-import android.os.Binder;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Process;
@@ -83,7 +81,6 @@
*/
public class DataManager {
- private static final String PLATFORM_PACKAGE_NAME = "android";
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
private static final long QUERY_EVENTS_MAX_AGE_MS = DateUtils.DAY_IN_MILLIS;
@@ -106,7 +103,6 @@
private ShortcutServiceInternal mShortcutServiceInternal;
private PackageManagerInternal mPackageManagerInternal;
- private ShortcutManager mShortcutManager;
private UserManager mUserManager;
public DataManager(Context context) {
@@ -125,7 +121,6 @@
public void initialize() {
mShortcutServiceInternal = LocalServices.getService(ShortcutServiceInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mShortcutManager = mContext.getSystemService(ShortcutManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
mShortcutServiceInternal.addListener(new ShortcutServiceListener());
@@ -171,8 +166,7 @@
mNotificationListeners.put(userId, notificationListener);
try {
notificationListener.registerAsSystemService(mContext,
- new ComponentName(PLATFORM_PACKAGE_NAME, getClass().getCanonicalName()),
- userId);
+ new ComponentName(mContext, getClass()), userId);
} catch (RemoteException e) {
// Should never occur for local calls.
}
@@ -242,8 +236,8 @@
* Iterates through all the {@link PackageData}s owned by the unlocked users who are in the
* same profile group as the calling user.
*/
- public void forAllPackages(Consumer<PackageData> consumer) {
- List<UserInfo> users = mUserManager.getEnabledProfiles(mInjector.getCallingUserId());
+ void forPackagesInProfile(@UserIdInt int callingUserId, Consumer<PackageData> consumer) {
+ List<UserInfo> users = mUserManager.getEnabledProfiles(callingUserId);
for (UserInfo userInfo : users) {
UserData userData = getUnlockedUserData(userInfo.id);
if (userData != null) {
@@ -275,8 +269,10 @@
* Gets the {@link ShareShortcutInfo}s from all packages owned by the calling user that match
* the specified {@link IntentFilter}.
*/
- public List<ShareShortcutInfo> getShareShortcuts(@NonNull IntentFilter intentFilter) {
- return mShortcutManager.getShareTargets(intentFilter);
+ public List<ShareShortcutInfo> getShareShortcuts(@NonNull IntentFilter intentFilter,
+ @UserIdInt int callingUserId) {
+ return mShortcutServiceInternal.getShareTargets(
+ mContext.getPackageName(), intentFilter, callingUserId);
}
/** Reports the {@link AppTargetEvent} from App Prediction Manager. */
@@ -323,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);
}
@@ -361,7 +356,7 @@
@ShortcutQuery.QueryFlags int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC
| ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
return mShortcutServiceInternal.getShortcuts(
- mInjector.getCallingUserId(), /*callingPackage=*/ PLATFORM_PACKAGE_NAME,
+ UserHandle.USER_SYSTEM, mContext.getPackageName(),
/*changedSince=*/ 0, packageName, shortcutIds, /*locusIds=*/ null,
/*componentName=*/ null, queryFlags, userId, MY_PID, MY_UID);
}
@@ -775,7 +770,7 @@
@Override
public void onReceive(Context context, Intent intent) {
- forAllPackages(PackageData::saveToDisk);
+ forAllUnlockedUsers(userData -> userData.forAllPackages(PackageData::saveToDisk));
}
}
@@ -809,9 +804,5 @@
Function<String, PackageData> packageDataGetter) {
return new UsageStatsQueryHelper(userId, packageDataGetter);
}
-
- int getCallingUserId() {
- return Binder.getCallingUserHandle().getIdentifier();
- }
}
}
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/people/java/com/android/server/people/prediction/AppTargetPredictor.java b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java
index 44f3e35..19cf8af 100644
--- a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java
@@ -18,6 +18,7 @@
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppTarget;
@@ -42,25 +43,28 @@
/** Creates a {@link AppTargetPredictor} instance based on the prediction context. */
public static AppTargetPredictor create(@NonNull AppPredictionContext predictionContext,
@NonNull Consumer<List<AppTarget>> updatePredictionsMethod,
- @NonNull DataManager dataManager) {
+ @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
if (UI_SURFACE_SHARE.equals(predictionContext.getUiSurface())) {
return new ShareTargetPredictor(
- predictionContext, updatePredictionsMethod, dataManager);
+ predictionContext, updatePredictionsMethod, dataManager, callingUserId);
}
- return new AppTargetPredictor(predictionContext, updatePredictionsMethod, dataManager);
+ return new AppTargetPredictor(
+ predictionContext, updatePredictionsMethod, dataManager, callingUserId);
}
private final AppPredictionContext mPredictionContext;
private final Consumer<List<AppTarget>> mUpdatePredictionsMethod;
private final DataManager mDataManager;
+ final int mCallingUserId;
private final ExecutorService mCallbackExecutor;
AppTargetPredictor(@NonNull AppPredictionContext predictionContext,
@NonNull Consumer<List<AppTarget>> updatePredictionsMethod,
- @NonNull DataManager dataManager) {
+ @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
mPredictionContext = predictionContext;
mUpdatePredictionsMethod = updatePredictionsMethod;
mDataManager = dataManager;
+ mCallingUserId = callingUserId;
mCallbackExecutor = Executors.newSingleThreadExecutor();
}
diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
index 280ced3..90d8216 100644
--- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
@@ -19,6 +19,7 @@
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppTarget;
@@ -45,8 +46,8 @@
ShareTargetPredictor(@NonNull AppPredictionContext predictionContext,
@NonNull Consumer<List<AppTarget>> updatePredictionsMethod,
- @NonNull DataManager dataManager) {
- super(predictionContext, updatePredictionsMethod, dataManager);
+ @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
+ super(predictionContext, updatePredictionsMethod, dataManager, callingUserId);
mIntentFilter = predictionContext.getExtras().getParcelable(
ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY);
}
@@ -84,7 +85,7 @@
List<ShareTarget> getShareTargets() {
List<ShareTarget> shareTargets = new ArrayList<>();
List<ShareShortcutInfo> shareShortcuts =
- getDataManager().getShareShortcuts(mIntentFilter);
+ getDataManager().getShareShortcuts(mIntentFilter, mCallingUserId);
for (ShareShortcutInfo shareShortcut : shareShortcuts) {
ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo();
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/CachedDeviceStateServiceTest.java b/services/tests/servicestests/src/com/android/server/CachedDeviceStateServiceTest.java
index 2a78b6f..2c84f26 100644
--- a/services/tests/servicestests/src/com/android/server/CachedDeviceStateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/CachedDeviceStateServiceTest.java
@@ -26,6 +26,7 @@
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.OsProtoEnums;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -52,13 +53,14 @@
public class CachedDeviceStateServiceTest {
@Mock private BatteryManagerInternal mBatteryManager;
@Mock private IPowerManager mPowerManager;
+ @Mock private IThermalService mThermalService;
private BroadcastInterceptingContext mContext;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
Context context = InstrumentationRegistry.getContext();
- PowerManager powerManager = new PowerManager(context, mPowerManager, null);
+ PowerManager powerManager = new PowerManager(context, mPowerManager, mThermalService, null);
mContext = new BroadcastInterceptingContext(context) {
@Override
public Object getSystemService(String name) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index 69ca643..ae8d554 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -74,6 +74,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallback;
@@ -147,6 +148,7 @@
@Mock private Context mMockContext;
@Mock private IPowerManager mMockIPowerManager;
+ @Mock private IThermalService mMockIThermalService;
@Mock private PackageManager mMockPackageManager;
@Spy private AccessibilityServiceInfo mSpyServiceInfo = new AccessibilityServiceInfo();
@Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
@@ -174,7 +176,7 @@
.thenReturn(mMockMagnificationController);
PowerManager powerManager =
- new PowerManager(mMockContext, mMockIPowerManager, mHandler);
+ new PowerManager(mMockContext, mMockIPowerManager, mMockIThermalService, mHandler);
when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
index 4123556..85b8fcb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.os.Handler;
import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -73,6 +74,7 @@
private KeyEventFilter mKeyEventFilter1;
private KeyEventFilter mKeyEventFilter2;
private IPowerManager mMockPowerManagerService;
+ private IThermalService mMockThermalService;
private MessageCapturingHandler mMessageCapturingHandler;
private ArgumentCaptor<Integer> mFilter1SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
private ArgumentCaptor<Integer> mFilter2SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
@@ -82,10 +84,12 @@
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
mInputEventsHandler = new MessageCapturingHandler(looper, null);
mMockPowerManagerService = mock(IPowerManager.class);
+ mMockThermalService = mock(IThermalService.class);
// TODO: It would be better to mock PowerManager rather than its binder, but the class is
// final.
PowerManager powerManager =
- new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler(looper));
+ new PowerManager(mock(Context.class), mMockPowerManagerService, mMockThermalService,
+ new Handler(looper));
mMessageCapturingHandler = new MessageCapturingHandler(looper, null);
mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHandler, SEND_FRAMEWORK_KEY_EVENT,
mLock, powerManager, mMessageCapturingHandler);
diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
index e90cb46..ac0cac1 100644
--- a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
@@ -37,6 +37,7 @@
import android.content.Context;
import android.os.IBinder;
import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.PowerManager;
import android.os.RemoteException;
import android.provider.DeviceConfig;
@@ -74,6 +75,8 @@
@Mock
private IPowerManager mMockIPowerManager;
@Mock
+ private IThermalService mMockIThermalService;
+ @Mock
Context mContext;
@Before
@@ -84,7 +87,7 @@
// setup power manager mock
PowerManager mPowerManager;
doReturn(true).when(mMockIPowerManager).isInteractive();
- mPowerManager = new PowerManager(mContext, mMockIPowerManager, null);
+ mPowerManager = new PowerManager(mContext, mMockIPowerManager, mMockIThermalService, null);
Object mLock = new Object();
// setup a spy on attention manager
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/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 9e98427..fa19814 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -34,6 +34,7 @@
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPortInfo;
import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -123,6 +124,7 @@
private HdmiPortInfo[] mHdmiPortInfo;
@Mock private IPowerManager mIPowerManagerMock;
+ @Mock private IThermalService mIThermalServiceMock;
@Before
public void setUp() throws Exception {
@@ -130,7 +132,8 @@
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
- PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock, null);
+ PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
+ mIThermalServiceMock, null);
when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
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 3ecd319..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
@@ -54,10 +54,8 @@
import android.content.IntentFilter;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ShortcutInfo;
-import android.content.pm.ShortcutManager;
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;
@@ -74,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;
@@ -87,6 +86,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -110,7 +110,6 @@
@Mock private ShortcutServiceInternal mShortcutServiceInternal;
@Mock private UsageStatsManagerInternal mUsageStatsManagerInternal;
@Mock private PackageManagerInternal mPackageManagerInternal;
- @Mock private ShortcutManager mShortcutManager;
@Mock private UserManager mUserManager;
@Mock private TelephonyManager mTelephonyManager;
@Mock private TelecomManager mTelecomManager;
@@ -123,7 +122,6 @@
private NotificationChannel mNotificationChannel;
private DataManager mDataManager;
- private int mCallingUserId;
private CancellationSignal mCancellationSignal;
private TestInjector mInjector;
@@ -145,14 +143,11 @@
}).when(mPackageManagerInternal).forEachInstalledPackage(any(Consumer.class), anyInt());
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+ when(mContext.getPackageName()).thenReturn("android");
Context originalContext = getInstrumentation().getTargetContext();
when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
- when(mContext.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(mShortcutManager);
- when(mContext.getSystemServiceName(ShortcutManager.class)).thenReturn(
- Context.SHORTCUT_SERVICE);
-
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mContext.getSystemServiceName(UserManager.class)).thenReturn(
Context.USER_SERVICE);
@@ -191,8 +186,6 @@
NOTIFICATION_CHANNEL_ID, "test channel", NotificationManager.IMPORTANCE_DEFAULT);
mNotificationChannel.setConversationId("test", TEST_SHORTCUT_ID);
- mCallingUserId = USER_ID_PRIMARY;
-
mCancellationSignal = new CancellationSignal();
mInjector = new TestInjector();
@@ -222,9 +215,7 @@
mDataManager.onShortcutAddedOrUpdated(
buildShortcutInfo("pkg_3", USER_ID_SECONDARY, "sc_3", buildPerson()));
- List<ConversationInfo> conversations = new ArrayList<>();
- mDataManager.forAllPackages(
- packageData -> packageData.forAllConversations(conversations::add));
+ List<ConversationInfo> conversations = getConversationsInPrimary();
// USER_ID_SECONDARY is not in the same profile group as USER_ID_PRIMARY.
assertEquals(2, conversations.size());
@@ -250,18 +241,14 @@
mDataManager.onShortcutAddedOrUpdated(
buildShortcutInfo("pkg_2", USER_ID_PRIMARY_MANAGED, "sc_2", buildPerson()));
- List<ConversationInfo> conversations = new ArrayList<>();
- mDataManager.forAllPackages(
- packageData -> packageData.forAllConversations(conversations::add));
+ List<ConversationInfo> conversations = getConversationsInPrimary();
// USER_ID_PRIMARY_MANAGED is not locked, so only USER_ID_PRIMARY's conversation is stored.
assertEquals(1, conversations.size());
assertEquals("sc_1", conversations.get(0).getShortcutId());
mDataManager.onUserStopped(USER_ID_PRIMARY);
- conversations.clear();
- mDataManager.forAllPackages(
- packageData -> packageData.forAllConversations(conversations::add));
+ conversations = getConversationsInPrimary();
assertTrue(conversations.isEmpty());
}
@@ -289,12 +276,8 @@
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
mDataManager.reportAppTargetEvent(appTargetEvent, intentFilter);
- List<Range<Long>> activeShareTimeSlots = new ArrayList<>();
- mDataManager.forAllPackages(packageData ->
- activeShareTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.TYPE_SHARE_IMAGE)
- .getActiveTimeSlots()));
+ List<Range<Long>> activeShareTimeSlots = getActiveSlotsForTestShortcut(
+ Event.SHARE_EVENT_TYPES);
assertEquals(1, activeShareTimeSlots.size());
}
@@ -315,9 +298,7 @@
USER_ID_PRIMARY);
contentObserver.onChange(false, ContactsContract.Contacts.CONTENT_URI, USER_ID_PRIMARY);
- List<ConversationInfo> conversations = new ArrayList<>();
- mDataManager.forAllPackages(
- packageData -> packageData.forAllConversations(conversations::add));
+ List<ConversationInfo> conversations = getConversationsInPrimary();
assertEquals(1, conversations.size());
assertEquals(TEST_SHORTCUT_ID, conversations.get(0).getShortcutId());
@@ -338,12 +319,8 @@
listenerService.onNotificationPosted(mStatusBarNotification);
- List<Range<Long>> activeNotificationOpenTimeSlots = new ArrayList<>();
- mDataManager.forAllPackages(packageData ->
- activeNotificationOpenTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.TYPE_NOTIFICATION_POSTED)
- .getActiveTimeSlots()));
+ List<Range<Long>> activeNotificationOpenTimeSlots = getActiveSlotsForTestShortcut(
+ Event.NOTIFICATION_EVENT_TYPES);
assertEquals(1, activeNotificationOpenTimeSlots.size());
}
@@ -361,12 +338,8 @@
listenerService.onNotificationRemoved(mStatusBarNotification, null,
NotificationListenerService.REASON_CLICK);
- List<Range<Long>> activeNotificationOpenTimeSlots = new ArrayList<>();
- mDataManager.forAllPackages(packageData ->
- activeNotificationOpenTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.TYPE_NOTIFICATION_OPENED)
- .getActiveTimeSlots()));
+ List<Range<Long>> activeNotificationOpenTimeSlots = getActiveSlotsForTestShortcut(
+ Event.NOTIFICATION_EVENT_TYPES);
assertEquals(1, activeNotificationOpenTimeSlots.size());
}
@@ -469,12 +442,7 @@
mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
new Event(currentTimestamp - MILLIS_PER_MINUTE * 5L, Event.TYPE_CALL_MISSED));
- List<Range<Long>> activeTimeSlots = new ArrayList<>();
- mDataManager.forAllPackages(packageData ->
- activeTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.CALL_EVENT_TYPES)
- .getActiveTimeSlots()));
+ List<Range<Long>> activeTimeSlots = getActiveSlotsForTestShortcut(Event.CALL_EVENT_TYPES);
assertEquals(3, activeTimeSlots.size());
}
@@ -498,12 +466,7 @@
mInjector.mMmsQueryHelper.mEventConsumer.accept(PHONE_NUMBER, outgoingSmsEvent);
mInjector.mSmsQueryHelper.mEventConsumer.accept(PHONE_NUMBER, incomingSmsEvent);
- List<Range<Long>> activeTimeSlots = new ArrayList<>();
- mDataManager.forAllPackages(packageData ->
- activeTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.SMS_EVENT_TYPES)
- .getActiveTimeSlots()));
+ List<Range<Long>> activeTimeSlots = getActiveSlotsForTestShortcut(Event.SMS_EVENT_TYPES);
assertEquals(2, activeTimeSlots.size());
}
@@ -551,22 +514,12 @@
mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
new Event(currentTimestamp - MILLIS_PER_MINUTE, Event.TYPE_CALL_OUTGOING));
- List<Range<Long>> activeTimeSlots = new ArrayList<>();
- mDataManager.forAllPackages(packageData ->
- activeTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.CALL_EVENT_TYPES)
- .getActiveTimeSlots()));
+ List<Range<Long>> activeTimeSlots = getActiveSlotsForTestShortcut(Event.CALL_EVENT_TYPES);
assertEquals(1, activeTimeSlots.size());
mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultDialer(null);
mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
- activeTimeSlots.clear();
- mDataManager.forAllPackages(packageData ->
- activeTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.CALL_EVENT_TYPES)
- .getActiveTimeSlots()));
+ activeTimeSlots = getActiveSlotsForTestShortcut(Event.CALL_EVENT_TYPES);
assertTrue(activeTimeSlots.isEmpty());
}
@@ -583,22 +536,12 @@
mInjector.mMmsQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
new Event(currentTimestamp - MILLIS_PER_MINUTE, Event.TYPE_SMS_OUTGOING));
- List<Range<Long>> activeTimeSlots = new ArrayList<>();
- mDataManager.forAllPackages(packageData ->
- activeTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.SMS_EVENT_TYPES)
- .getActiveTimeSlots()));
+ List<Range<Long>> activeTimeSlots = getActiveSlotsForTestShortcut(Event.SMS_EVENT_TYPES);
assertEquals(1, activeTimeSlots.size());
mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultSmsApp(null);
mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
- activeTimeSlots.clear();
- mDataManager.forAllPackages(packageData ->
- activeTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.SMS_EVENT_TYPES)
- .getActiveTimeSlots()));
+ activeTimeSlots = getActiveSlotsForTestShortcut(Event.SMS_EVENT_TYPES);
assertTrue(activeTimeSlots.isEmpty());
}
@@ -607,6 +550,24 @@
LocalServices.addService(clazz, mock);
}
+ private List<ConversationInfo> getConversationsInPrimary() {
+ List<ConversationInfo> conversations = new ArrayList<>();
+ mDataManager.forPackagesInProfile(USER_ID_PRIMARY,
+ packageData -> packageData.forAllConversations(conversations::add));
+ return conversations;
+ }
+
+ private List<Range<Long>> getActiveSlotsForTestShortcut(
+ Set<Integer> eventTypes) {
+ List<Range<Long>> activeSlots = new ArrayList<>();
+ mDataManager.forPackagesInProfile(USER_ID_PRIMARY, packageData ->
+ activeSlots.addAll(
+ packageData.getEventHistory(TEST_SHORTCUT_ID)
+ .getEventIndex(eventTypes)
+ .getActiveTimeSlots()));
+ return activeSlots;
+ }
+
private ShortcutInfo buildShortcutInfo(String packageName, int userId, String id,
@Nullable Person person) {
Context mockContext = mock(Context.class);
@@ -778,10 +739,5 @@
mSmsQueryHelper = new TestSmsQueryHelper(context, eventConsumer);
return mSmsQueryHelper;
}
-
- @Override
- int getCallingUserId() {
- return mCallingUserId;
- }
}
}
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/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
index 808906e..f498a94 100644
--- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -73,7 +74,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mDataManager.getShareShortcuts(any())).thenReturn(mShareShortcuts);
+ when(mDataManager.getShareShortcuts(any(), anyInt())).thenReturn(mShareShortcuts);
when(mDataManager.getPackage(PACKAGE_1, USER_ID)).thenReturn(mPackageData1);
when(mDataManager.getPackage(PACKAGE_2, USER_ID)).thenReturn(mPackageData2);
@@ -82,7 +83,8 @@
.setPredictedTargetCount(NUM_PREDICTED_TARGETS)
.setExtras(new Bundle())
.build();
- mPredictor = new ShareTargetPredictor(predictionContext, targets -> { }, mDataManager);
+ mPredictor = new ShareTargetPredictor(
+ predictionContext, targets -> { }, mDataManager, USER_ID);
}
@Test
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/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
index ccf7ca9..624cb83 100644
--- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
@@ -28,10 +28,12 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.hardware.thermal.V2_0.TemperatureThreshold;
import android.os.CoolingDevice;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.IThermalEventListener;
+import android.os.IThermalService;
import android.os.IThermalStatusListener;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -72,6 +74,8 @@
@Mock
private IPowerManager mIPowerManagerMock;
@Mock
+ private IThermalService mIThermalServiceMock;
+ @Mock
private IThermalEventListener mEventListener1;
@Mock
private IThermalEventListener mEventListener2;
@@ -133,6 +137,12 @@
}
@Override
+ protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
+ int type) {
+ return new ArrayList<>();
+ }
+
+ @Override
protected boolean connectToHal() {
return true;
}
@@ -153,7 +163,7 @@
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mFakeHal = new ThermalHalFake();
- mPowerManager = new PowerManager(mContext, mIPowerManagerMock, null);
+ mPowerManager = new PowerManager(mContext, mIPowerManagerMock, mIThermalServiceMock, null);
when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE);
when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
resetListenerMock();
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
index d5cdbeb..035a2f1 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -36,6 +36,7 @@
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IRecoverySystemProgressListener;
+import android.os.IThermalService;
import android.os.Looper;
import android.os.PowerManager;
@@ -62,6 +63,7 @@
private RecoverySystemService.UncryptSocket mUncryptSocket;
private Context mContext;
private IPowerManager mIPowerManager;
+ private IThermalService mIThermalService;
private FileWriter mUncryptUpdateFileWriter;
private LockSettingsInternal mLockSettingsInternal;
@@ -77,8 +79,9 @@
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
mIPowerManager = mock(IPowerManager.class);
+ mIThermalService = mock(IThermalService.class);
PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
- new Handler(looper));
+ mIThermalService, new Handler(looper));
mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal);
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/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 604fcd3..ccce043 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -359,8 +359,12 @@
@Before
public void setUp() throws Exception {
+ // Shell permisssions will override permissions of our app, so add all necessary permissions
+ // fo this test here:
InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
- "android.permission.WRITE_DEVICE_CONFIG", "android.permission.READ_DEVICE_CONFIG");
+ "android.permission.WRITE_DEVICE_CONFIG",
+ "android.permission.READ_DEVICE_CONFIG",
+ "android.permission.READ_CONTACTS");
MockitoAnnotations.initMocks(this);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 0adf15c..7f9732b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -108,6 +108,7 @@
private static final int UID_N_MR1 = 0;
private static final UserHandle USER = UserHandle.of(0);
private static final int UID_O = 1111;
+ private static final int UID_P = 2222;
private static final String SYSTEM_PKG = "android";
private static final int SYSTEM_UID = 1000;
private static final UserHandle USER2 = UserHandle.of(10);
@@ -141,9 +142,11 @@
upgrade.targetSdkVersion = Build.VERSION_CODES.O;
when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy);
when(mPm.getApplicationInfoAsUser(eq(PKG_O), anyInt(), anyInt())).thenReturn(upgrade);
+ when(mPm.getApplicationInfoAsUser(eq(PKG_P), anyInt(), anyInt())).thenReturn(upgrade);
when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade);
when(mPm.getPackageUidAsUser(eq(PKG_N_MR1), anyInt())).thenReturn(UID_N_MR1);
when(mPm.getPackageUidAsUser(eq(PKG_O), anyInt())).thenReturn(UID_O);
+ when(mPm.getPackageUidAsUser(eq(PKG_P), anyInt())).thenReturn(UID_P);
when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID);
PackageInfo info = mock(PackageInfo.class);
info.signatures = new Signature[] {mock(Signature.class)};
@@ -2945,6 +2948,92 @@
}
@Test
+ public void testGetConversations_all() {
+ String convoId = "convo";
+ NotificationChannel messages =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
+ NotificationChannel calls =
+ new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false);
+ NotificationChannel p =
+ new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false);
+
+ NotificationChannel channel =
+ new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
+ channel.setConversationId(messages.getId(), convoId);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+
+ NotificationChannel diffConvo =
+ new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
+ diffConvo.setConversationId(p.getId(), "different convo");
+ mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false);
+
+ NotificationChannel channel2 =
+ new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
+ channel2.setConversationId(calls.getId(), convoId);
+ channel2.setImportantConversation(true);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
+
+ List<ConversationChannelWrapper> convos = mHelper.getConversations(false);
+
+ assertEquals(3, convos.size());
+ assertTrue(conversationWrapperContainsChannel(convos, channel));
+ assertTrue(conversationWrapperContainsChannel(convos, diffConvo));
+ assertTrue(conversationWrapperContainsChannel(convos, channel2));
+ }
+
+ @Test
+ public void testGetConversations_onlyImportant() {
+ String convoId = "convo";
+ NotificationChannel messages =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
+ NotificationChannel calls =
+ new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false);
+ NotificationChannel p =
+ new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false);
+
+ NotificationChannel channel =
+ new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
+ channel.setConversationId(messages.getId(), convoId);
+ channel.setImportantConversation(true);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+
+ NotificationChannel diffConvo =
+ new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
+ diffConvo.setConversationId(p.getId(), "different convo");
+ diffConvo.setImportantConversation(true);
+ mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false);
+
+ NotificationChannel channel2 =
+ new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
+ channel2.setConversationId(calls.getId(), convoId);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
+
+ List<ConversationChannelWrapper> convos = mHelper.getConversations(true);
+
+ assertEquals(2, convos.size());
+ assertTrue(conversationWrapperContainsChannel(convos, channel));
+ assertTrue(conversationWrapperContainsChannel(convos, diffConvo));
+ assertFalse(conversationWrapperContainsChannel(convos, channel2));
+ }
+
+ private boolean conversationWrapperContainsChannel(List<ConversationChannelWrapper> list,
+ NotificationChannel expected) {
+ for (ConversationChannelWrapper ccw : list) {
+ if (ccw.getNotificationChannel().equals(expected)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Test
public void testGetConversations_invalidPkg() {
assertThat(mHelper.getConversations("bad", 1)).isEmpty();
}
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/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index c110a0c..b917e1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -29,6 +29,7 @@
import static android.app.ActivityManager.START_SWITCHES_CANCELED;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -64,8 +65,10 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -80,6 +83,9 @@
import android.platform.test.annotations.Presubmit;
import android.service.voice.IVoiceInteractionSession;
import android.view.Gravity;
+import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
+import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
@@ -999,7 +1005,8 @@
assertThat(outActivity[0].inSplitScreenWindowingMode()).isFalse();
// Move activity to split-screen-primary stack and make sure it has the focus.
- top.getRootTask().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ TestSplitOrganizer splitOrg = new TestSplitOrganizer(mService, top.getDisplayId());
+ splitOrg.mPrimary.addChild(top.getRootTask(), 0 /* index */);
top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent");
// Activity must landed on split-screen-secondary when launch adjacent.
@@ -1022,4 +1029,58 @@
verify(recentTasks, times(1)).add(any());
}
+
+ static class TestSplitOrganizer extends ITaskOrganizer.Stub {
+ final ActivityTaskManagerService mService;
+ TaskTile mPrimary;
+ TaskTile mSecondary;
+ boolean mInSplit = false;
+ int mDisplayId;
+ TestSplitOrganizer(ActivityTaskManagerService service, int displayId) {
+ mService = service;
+ mDisplayId = displayId;
+ mService.mTaskOrganizerController.registerTaskOrganizer(this,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ mService.mTaskOrganizerController.registerTaskOrganizer(this,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ IWindowContainer primary = mService.mTaskOrganizerController.createRootTask(
+ displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
+ mPrimary = TaskTile.forToken(primary.asBinder());
+ IWindowContainer secondary = mService.mTaskOrganizerController.createRootTask(
+ displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
+ mSecondary = TaskTile.forToken(secondary.asBinder());
+ }
+ @Override
+ public void taskAppeared(ActivityManager.RunningTaskInfo info) {
+ }
+ @Override
+ public void taskVanished(IWindowContainer wc) {
+ }
+ @Override
+ public void transactionReady(int id, SurfaceControl.Transaction t) {
+ }
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ if (mInSplit) {
+ return;
+ }
+ if (info.topActivityType != ACTIVITY_TYPE_UNDEFINED) {
+ if (info.configuration.windowConfiguration.getWindowingMode()
+ == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ mInSplit = true;
+ mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
+ mSecondary.mRemoteToken);
+ // move everything to secondary because test expects this but usually sysui
+ // does it.
+ DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
+ for (int i = dc.getStackCount() - 1; i >= 0; --i) {
+ if (!WindowConfiguration.isSplitScreenWindowingMode(
+ dc.getStackAt(i).getWindowingMode())) {
+ mSecondary.addChild(dc.getStackAt(i), 0);
+ }
+ }
+ }
+ }
+ }
+ };
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index ba57745..2b0ad89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -605,6 +605,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -625,6 +626,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
addWindow(mWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index a672a95..4449069 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1098,7 +1098,6 @@
assertSecurityException(expectCallable,
() -> mService.setTaskWindowingModeSplitScreenPrimary(0,
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true));
- assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true));
assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0));
assertSecurityException(expectCallable,
() -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 7753a32..6a8917c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -20,7 +20,9 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
@@ -53,6 +55,8 @@
import static org.mockito.Mockito.never;
import android.app.ActivityManager.TaskSnapshot;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
@@ -65,12 +69,16 @@
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.google.common.truth.Truth;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+
/**
* Build/Install/Run:
* atest WmTests:RecentsAnimationControllerTest
@@ -330,6 +338,107 @@
assertTrue(activity.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
}
+ @Test
+ public void testRecentViewInFixedPortraitWhenTopAppInLandscape() {
+ mWm.mIsFixedRotationTransformEnabled = true;
+ mWm.setRecentsAnimationController(mController);
+
+ final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ final ActivityRecord homeAppWindow =
+ new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(homeStack)
+ .setCreateTask(true)
+ .build();
+ final ActivityRecord appWindow = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState win0 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+ appWindow.addWindow(win0);
+
+ final ActivityRecord landActivity = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ landActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, landActivity, "win1");
+ landActivity.addWindow(win1);
+
+ assertEquals(landActivity.getTask().getTopVisibleActivity(), landActivity);
+ assertEquals(landActivity.findMainWindow(), win1);
+
+ // Ensure that the display is in Landscape
+ landActivity.onDescendantOrientationChanged(landActivity.token, landActivity);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE,
+ mDisplayContent.getConfiguration().orientation);
+
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeAppWindow);
+
+ // Check that the home app is in portrait
+ assertEquals(Configuration.ORIENTATION_PORTRAIT,
+ homeAppWindow.getConfiguration().orientation);
+ }
+
+ @Test
+ public void testWallpaperHasFixedRotationApplied() {
+ mWm.mIsFixedRotationTransformEnabled = true;
+ mWm.setRecentsAnimationController(mController);
+
+ // Create a portrait home stack, a wallpaper and a landscape application displayed on top.
+
+ // Home stack
+ final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ final ActivityRecord homeActivity =
+ new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(homeStack)
+ .setCreateTask(true)
+ .build();
+ homeActivity.setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+
+ final WindowState homeWindow = createWindow(null, TYPE_BASE_APPLICATION, homeActivity,
+ "homeWindow");
+ homeActivity.addWindow(homeWindow);
+ homeWindow.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+
+ // Landscape application
+ final ActivityRecord activity = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState applicationWindow = createWindow(null, TYPE_BASE_APPLICATION, activity,
+ "applicationWindow");
+ activity.addWindow(applicationWindow);
+ activity.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+
+ // Wallpaper
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
+ "wallpaperWindow");
+
+ // Make sure the landscape activity is on top and the display is in landscape
+ activity.moveFocusableActivityToTop("test");
+ mDisplayContent.getConfiguration().windowConfiguration.setRotation(
+ mDisplayContent.getRotation());
+
+
+ spyOn(mDisplayContent.mWallpaperController);
+ doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+
+ // Start the recents animation
+ mController
+ .initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
+
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+
+ // Check preconditions
+ ArrayList<WallpaperWindowToken> wallpapers = new ArrayList<>(1);
+ mDisplayContent.forAllWallpaperWindows(wallpapers::add);
+
+ Truth.assertThat(wallpapers).hasSize(1);
+ Truth.assertThat(wallpapers.get(0).getTopChild()).isEqualTo(wallpaperWindow);
+
+ // Actual check
+ assertEquals(Configuration.ORIENTATION_PORTRAIT,
+ wallpapers.get(0).getConfiguration().orientation);
+ }
+
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index b5663bd..851b052 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -260,4 +260,9 @@
public SurfaceControl.Transaction unsetColor(SurfaceControl sc) {
return this;
}
+
+ @Override
+ public SurfaceControl.Transaction setShadowRadius(SurfaceControl sc, float shadowRadius) {
+ return this;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 0312df6..cd53ece 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -28,19 +28,17 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -49,6 +47,7 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.PictureInPictureParams;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -56,7 +55,6 @@
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
-import android.content.pm.ActivityInfo;
import android.util.Rational;
import android.view.Display;
import android.view.ITaskOrganizer;
@@ -458,9 +456,9 @@
private List<TaskTile> getTaskTiles(DisplayContent dc) {
ArrayList<TaskTile> out = new ArrayList<>();
for (int i = dc.getStackCount() - 1; i >= 0; --i) {
- final Task t = dc.getStackAt(i);
- if (t instanceof TaskTile) {
- out.add((TaskTile) t);
+ final TaskTile t = dc.getStackAt(i).asTile();
+ if (t != null) {
+ out.add(t);
}
}
return out;
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 18b640f..c3d3d83 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -86,6 +86,7 @@
public class StorageStatsService extends IStorageStatsManager.Stub {
private static final String TAG = "StorageStatsService";
+ private static final String PROP_STORAGE_CRATES = "fw.storage_crates";
private static final String PROP_DISABLE_QUOTA = "fw.disable_quota";
private static final String PROP_VERIFY_STORAGE = "fw.verify_storage";
@@ -595,6 +596,13 @@
Uri.parse("content://com.android.externalstorage.documents/"), null, false);
}
+ private static void checkCratesEnable() {
+ final boolean enable = SystemProperties.getBoolean(PROP_STORAGE_CRATES, false);
+ if (!enable) {
+ throw new IllegalStateException("Storage Crate feature is disabled.");
+ }
+ }
+
/**
* To enforce the calling or self to have the {@link android.Manifest.permission#MANAGE_CRATES}
* permission.
@@ -650,6 +658,7 @@
@Override
public ParceledListSlice<CrateInfo> queryCratesForPackage(String volumeUuid,
@NonNull String packageName, @UserIdInt int userId, @NonNull String callingPackage) {
+ checkCratesEnable();
if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
@@ -677,6 +686,7 @@
@Override
public ParceledListSlice<CrateInfo> queryCratesForUid(String volumeUuid, int uid,
@NonNull String callingPackage) {
+ checkCratesEnable();
final int userId = UserHandle.getUserId(uid);
if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
@@ -718,6 +728,7 @@
@Override
public ParceledListSlice<CrateInfo> queryCratesForUser(String volumeUuid, int userId,
@NonNull String callingPackage) {
+ checkCratesEnable();
if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 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..4604cd2
--- 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:
@@ -3532,7 +3576,7 @@
* ATIS-1000082.
* @return the verification status.
*/
- public @VerificationStatus int getCallerNumberVerificationStatus() {
+ public final @VerificationStatus int getCallerNumberVerificationStatus() {
return mCallerNumberVerificationStatus;
}
@@ -3544,7 +3588,7 @@
* by
* {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}.
*/
- public void setCallerNumberVerificationStatus(
+ public final void setCallerNumberVerificationStatus(
@VerificationStatus int callerNumberVerificationStatus) {
mCallerNumberVerificationStatus = callerNumberVerificationStatus;
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
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/BootImageProfileTest/TEST_MAPPING b/tests/BootImageProfileTest/DISABLED_TEST_MAPPING
similarity index 100%
rename from tests/BootImageProfileTest/TEST_MAPPING
rename to tests/BootImageProfileTest/DISABLED_TEST_MAPPING
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index 638b6d1..480b12b 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -50,6 +50,7 @@
<application>
<uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.net.ipsec.ike" />
</application>
<instrumentation
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index 490c467..23caf49 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -26,6 +26,7 @@
import android.os.IBinder
import com.android.networkstack.metrics.DataStallStatsUtils
import com.android.networkstack.netlink.TcpSocketTracker
+import com.android.server.NetworkStackService
import com.android.server.NetworkStackService.NetworkMonitorConnector
import com.android.server.NetworkStackService.NetworkStackConnector
import com.android.server.connectivity.NetworkMonitor
@@ -88,6 +89,7 @@
val nm = NetworkMonitor(this@TestNetworkStackService, cb,
this.network,
mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
+ mock(NetworkStackService.NetworkStackServiceManager::class.java),
NetworkMonitorDeps(privateDnsBypassNetwork),
mock(DataStallStatsUtils::class.java),
mock(TcpSocketTracker::class.java))
diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java
index 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/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 0886975..6d4a1b2 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1180,6 +1180,10 @@
Arrays.asList(new UserInfo[] {
new UserInfo(VPN_USER, "", 0),
}));
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
+ when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
+ .thenReturn(applicationInfo);
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
// http://b/25897652 .
@@ -2054,14 +2058,15 @@
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- // Bring up wifi with a score of 70.
+ // Bring up validated wifi.
// Cell is lingered because it would not satisfy any request, even if it validated.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.adjustScore(50);
- mWiFiNetworkAgent.connect(false); // Score: 70
+ mWiFiNetworkAgent.connect(true); // Score: 60
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -3041,7 +3046,7 @@
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
mService.requestNetwork(networkCapabilities, null, 0, null,
- ConnectivityManager.TYPE_WIFI, TEST_PACKAGE_NAME);
+ ConnectivityManager.TYPE_WIFI, mContext.getPackageName());
});
class NonParcelableSpecifier extends NetworkSpecifier {
@@ -5845,7 +5850,7 @@
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ trustedCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
verify(mNetworkManagementService).setDefaultNetId(eq(mWiFiNetworkAgent.getNetwork().netId));
reset(mNetworkManagementService);
@@ -6438,17 +6443,89 @@
assertEquals(wifiLp, mService.getActiveLinkProperties());
}
+ private void setupLocationPermissions(
+ int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = targetSdk;
+ when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
+ .thenReturn(applicationInfo);
+
+ when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
+
+ if (op != null) {
+ when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
+ }
+
+ if (perm != null) {
+ mServiceContext.setPermission(perm, PERMISSION_GRANTED);
+ }
+ }
+
+ private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
+ final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
+
+ return mService
+ .maybeSanitizeLocationInfoForCaller(netCap, callerUid, mContext.getPackageName())
+ .getOwnerUid();
+ }
+
@Test
- public void testNetworkCapabilitiesRestrictedForCallerPermissions() {
- int callerUid = Process.myUid();
- final NetworkCapabilities originalNc = new NetworkCapabilities();
- originalNc.setOwnerUid(callerUid);
+ public void testMaybeSanitizeLocationInfoForCallerWithFineLocationAfterQ() throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
- final NetworkCapabilities newNc =
- mService.networkCapabilitiesRestrictedForCallerPermissions(
- originalNc, Process.myPid(), callerUid);
+ final int myUid = Process.myUid();
+ assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
- assertEquals(Process.INVALID_UID, newNc.getOwnerUid());
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationPreQ() throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerLocationOff() throws Exception {
+ // Test that even with fine location permission, and UIDs matching, the UID is sanitized.
+ setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWrongUid() throws Exception {
+ // Test that even with fine location permission, not being the owner leads to sanitization.
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationAfterQ() throws Exception {
+ // Test that not having fine location permission leads to sanitization.
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+
+ // Test that without the location permission, the owner field is sanitized.
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWithoutLocationPermission() throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
+
+ // Test that without the location permission, the owner field is sanitized.
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
}
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -6734,21 +6811,6 @@
mContext.getOpPackageName()));
}
- private void setupLocationPermissions(
- int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = targetSdk;
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
- .thenReturn(applicationInfo);
-
- when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
-
- when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
-
- mServiceContext.setPermission(perm, PERMISSION_GRANTED);
- }
-
private void setUpConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
diff --git a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
index a6b371a..d2532c2 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
+++ b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
@@ -16,14 +16,18 @@
package com.android.server.connectivity
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.LinkProperties
+import android.net.Network
+import android.net.NetworkAgentConfig
import android.net.NetworkCapabilities
+import android.net.NetworkInfo
import android.net.NetworkRequest
+import android.net.NetworkScore
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import kotlin.test.assertEquals
import kotlin.test.assertNull
@@ -33,10 +37,24 @@
class NetworkRankerTest {
private val ranker = NetworkRanker()
- private fun makeNai(satisfy: Boolean, score: Int) = mock(NetworkAgentInfo::class.java).also {
- doReturn(satisfy).`when`(it).satisfies(any())
- doReturn(score).`when`(it).currentScore
- it.networkCapabilities = NetworkCapabilities()
+ private fun makeNai(satisfy: Boolean, score: Int) = object : NetworkAgentInfo(
+ null /* messenger */,
+ null /* asyncChannel*/,
+ Network(100),
+ NetworkInfo(TYPE_WIFI, 0 /* subtype */, "" /* typename */, "" /* subtypename */),
+ LinkProperties(),
+ NetworkCapabilities(),
+ NetworkScore.Builder().setLegacyScore(score).build(),
+ null /* context */,
+ null /* handler */,
+ NetworkAgentConfig(),
+ null /* connectivityService */,
+ null /* netd */,
+ null /* dnsResolver */,
+ null /* networkManagementService */,
+ 0 /* factorySerialNumber */) {
+ override fun satisfies(request: NetworkRequest?): Boolean = satisfy
+ override fun getCurrentScore(): Int = score
}
@Test
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/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index 957216e..26916bc 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -38,6 +38,7 @@
"android.app.activity.ActivityThreadClientTest",
// Test specifications for FrameworksCoreTests.
"android.app.servertransaction.", // all tests under the package.
+ "android.view.CutoutSpecificationTest",
"android.view.DisplayCutoutTest",
"android.view.InsetsAnimationControlImplTest",
"android.view.InsetsControllerTest",
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 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/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1c330e2..3025caf 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -125,6 +125,8 @@
DhcpInfo getDhcpInfo();
+ void setScanAlwaysAvailable(boolean isAvailable);
+
boolean isScanAlwaysAvailable();
boolean acquireWifiLock(IBinder lock, int lockType, String tag, in WorkSource ws);
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 0db3313..ae5bf7d 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -17,6 +17,7 @@
package android.net.wifi;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -202,6 +203,11 @@
private final List<MacAddress> mAllowedClientList;
/**
+ * Whether auto shutdown of soft AP is enabled or not.
+ */
+ private final boolean mAutoShutdownEnabled;
+
+ /**
* Delay in milliseconds before shutting down soft AP when
* there are no connected devices.
*/
@@ -240,9 +246,9 @@
/** Private constructor for Builder and Parcelable implementation. */
private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
@Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel,
- @SecurityType int securityType, int maxNumberOfClients, int shutdownTimeoutMillis,
- boolean clientControlByUser, @NonNull List<MacAddress> blockedList,
- @NonNull List<MacAddress> allowedList) {
+ @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled,
+ int shutdownTimeoutMillis, boolean clientControlByUser,
+ @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList) {
mSsid = ssid;
mBssid = bssid;
mPassphrase = passphrase;
@@ -251,6 +257,7 @@
mChannel = channel;
mSecurityType = securityType;
mMaxNumberOfClients = maxNumberOfClients;
+ mAutoShutdownEnabled = shutdownTimeoutEnabled;
mShutdownTimeoutMillis = shutdownTimeoutMillis;
mClientControlByUser = clientControlByUser;
mBlockedClientList = new ArrayList<>(blockedList);
@@ -274,6 +281,7 @@
&& mChannel == other.mChannel
&& mSecurityType == other.mSecurityType
&& mMaxNumberOfClients == other.mMaxNumberOfClients
+ && mAutoShutdownEnabled == other.mAutoShutdownEnabled
&& mShutdownTimeoutMillis == other.mShutdownTimeoutMillis
&& mClientControlByUser == other.mClientControlByUser
&& Objects.equals(mBlockedClientList, other.mBlockedClientList)
@@ -283,8 +291,9 @@
@Override
public int hashCode() {
return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid,
- mBand, mChannel, mSecurityType, mMaxNumberOfClients, mShutdownTimeoutMillis,
- mClientControlByUser, mBlockedClientList, mAllowedClientList);
+ mBand, mChannel, mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled,
+ mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList,
+ mAllowedClientList);
}
@Override
@@ -299,6 +308,7 @@
sbuf.append(" \n Channel =").append(mChannel);
sbuf.append(" \n SecurityType=").append(getSecurityType());
sbuf.append(" \n MaxClient=").append(mMaxNumberOfClients);
+ sbuf.append(" \n AutoShutdownEnabled=").append(mAutoShutdownEnabled);
sbuf.append(" \n ShutdownTimeoutMillis=").append(mShutdownTimeoutMillis);
sbuf.append(" \n ClientControlByUser=").append(mClientControlByUser);
sbuf.append(" \n BlockedClientList=").append(mBlockedClientList);
@@ -316,6 +326,7 @@
dest.writeInt(mChannel);
dest.writeInt(mSecurityType);
dest.writeInt(mMaxNumberOfClients);
+ dest.writeBoolean(mAutoShutdownEnabled);
dest.writeInt(mShutdownTimeoutMillis);
dest.writeBoolean(mClientControlByUser);
dest.writeTypedList(mBlockedClientList);
@@ -335,7 +346,7 @@
in.readString(),
in.readParcelable(MacAddress.class.getClassLoader()),
in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(),
- in.readInt(), in.readInt(), in.readBoolean(),
+ in.readInt(), in.readBoolean(), in.readInt(), in.readBoolean(),
in.createTypedArrayList(MacAddress.CREATOR),
in.createTypedArrayList(MacAddress.CREATOR));
}
@@ -429,6 +440,18 @@
}
/**
+ * Returns whether auto shutdown is enabled or not.
+ * The Soft AP will shutdown when there are no devices associated to it for
+ * the timeout duration. See {@link Builder#setAutoShutdownEnabled(boolean)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isAutoShutdownEnabled() {
+ return mAutoShutdownEnabled;
+ }
+
+ /**
* Returns the shutdown timeout in milliseconds.
* The Soft AP will shutdown when there are no devices associated to it for
* the timeout duration. See {@link Builder#setShutdownTimeoutMillis(int)}.
@@ -551,6 +574,7 @@
private int mChannel;
private int mMaxNumberOfClients;
private int mSecurityType;
+ private boolean mAutoShutdownEnabled;
private int mShutdownTimeoutMillis;
private boolean mClientControlByUser;
private List<MacAddress> mBlockedClientList;
@@ -568,6 +592,7 @@
mChannel = 0;
mMaxNumberOfClients = 0;
mSecurityType = SECURITY_TYPE_OPEN;
+ mAutoShutdownEnabled = true; // enabled by default.
mShutdownTimeoutMillis = 0;
mClientControlByUser = false;
mBlockedClientList = new ArrayList<>();
@@ -588,6 +613,7 @@
mChannel = other.mChannel;
mMaxNumberOfClients = other.mMaxNumberOfClients;
mSecurityType = other.mSecurityType;
+ mAutoShutdownEnabled = other.mAutoShutdownEnabled;
mShutdownTimeoutMillis = other.mShutdownTimeoutMillis;
mClientControlByUser = other.mClientControlByUser;
mBlockedClientList = new ArrayList<>(other.mBlockedClientList);
@@ -603,8 +629,8 @@
public SoftApConfiguration build() {
return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients,
- mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList,
- mAllowedClientList);
+ mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser,
+ mBlockedClientList, mAllowedClientList);
}
/**
@@ -789,7 +815,7 @@
* @return Builder for chaining.
*/
@NonNull
- public Builder setMaxNumberOfClients(int maxNumberOfClients) {
+ public Builder setMaxNumberOfClients(@IntRange(from = 0) int maxNumberOfClients) {
if (maxNumberOfClients < 0) {
throw new IllegalArgumentException("maxNumberOfClients should be not negative");
}
@@ -798,6 +824,25 @@
}
/**
+ * Specifies whether auto shutdown is enabled or not.
+ * The Soft AP will shut down when there are no devices connected to it for
+ * the timeout duration.
+ *
+ * <p>
+ * <li>If not set, defaults to true</li>
+ *
+ * @param enable true to enable, false to disable.
+ * @return Builder for chaining.
+ *
+ * @see #setShutdownTimeoutMillis(int)
+ */
+ @NonNull
+ public Builder setAutoShutdownEnabled(boolean enable) {
+ mAutoShutdownEnabled = enable;
+ return this;
+ }
+
+ /**
* Specifies the shutdown timeout in milliseconds.
* The Soft AP will shut down when there are no devices connected to it for
* the timeout duration.
@@ -807,14 +852,16 @@
*
* <p>
* <li>If not set, defaults to 0</li>
- * <li>The shut down timout will apply when
- * {@link Settings.Global.SOFT_AP_TIMEOUT_ENABLED} is true</li>
+ * <li>The shut down timeout will apply when {@link #setAutoShutdownEnabled(boolean)} is
+ * set to true</li>
*
* @param timeoutMillis milliseconds of the timeout delay.
* @return Builder for chaining.
+ *
+ * @see #setAutoShutdownEnabled(boolean)
*/
@NonNull
- public Builder setShutdownTimeoutMillis(int timeoutMillis) {
+ public Builder setShutdownTimeoutMillis(@IntRange(from = 0) int timeoutMillis) {
if (timeoutMillis < 0) {
throw new IllegalArgumentException("Invalid timeout value");
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index f693315..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;
@@ -2755,6 +2756,26 @@
}
/**
+ * Set if scanning is always available.
+ *
+ * If set to {@code true}, apps can issue {@link #startScan} and fetch scan results
+ * even when Wi-Fi is turned off.
+ *
+ * @param isAvailable true to enable, false to disable.
+ * @hide
+ * @see #isScanAlwaysAvailable()
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setScanAlwaysAvailable(boolean isAvailable) {
+ try {
+ mService.setScanAlwaysAvailable(isAvailable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Check if scanning is always available.
*
* If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
@@ -4900,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 {
@@ -4928,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/WifiOemMigrationHook.java b/wifi/java/android/net/wifi/WifiOemMigrationHook.java
index 22d7786..5301dd0 100755
--- a/wifi/java/android/net/wifi/WifiOemMigrationHook.java
+++ b/wifi/java/android/net/wifi/WifiOemMigrationHook.java
@@ -21,8 +21,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
+import android.provider.Settings;
import java.util.List;
@@ -33,6 +35,9 @@
*/
@SystemApi
public final class WifiOemMigrationHook {
+
+ private WifiOemMigrationHook() { }
+
/**
* Container for all the wifi config data to migrate.
*/
@@ -152,8 +157,6 @@
}
}
- private WifiOemMigrationHook() { }
-
/**
* Load data from OEM's config store.
* <p>
@@ -178,4 +181,263 @@
// Note: OEM's should add code to parse data from their config store format here!
return null;
}
+
+ /**
+ * Container for all the wifi settings data to migrate.
+ */
+ public static final class SettingsMigrationData implements Parcelable {
+ private final boolean mScanAlwaysAvailable;
+ private final boolean mP2pFactoryResetPending;
+ private final String mP2pDeviceName;
+ private final boolean mSoftApTimeoutEnabled;
+ private final boolean mWakeupEnabled;
+ private final boolean mScanThrottleEnabled;
+ private final boolean mVerboseLoggingEnabled;
+
+ private SettingsMigrationData(boolean scanAlwaysAvailable, boolean p2pFactoryResetPending,
+ @Nullable String p2pDeviceName, boolean softApTimeoutEnabled, boolean wakeupEnabled,
+ boolean scanThrottleEnabled, boolean verboseLoggingEnabled) {
+ mScanAlwaysAvailable = scanAlwaysAvailable;
+ mP2pFactoryResetPending = p2pFactoryResetPending;
+ mP2pDeviceName = p2pDeviceName;
+ mSoftApTimeoutEnabled = softApTimeoutEnabled;
+ mWakeupEnabled = wakeupEnabled;
+ mScanThrottleEnabled = scanThrottleEnabled;
+ mVerboseLoggingEnabled = verboseLoggingEnabled;
+ }
+
+ public static final @NonNull Parcelable.Creator<SettingsMigrationData> CREATOR =
+ new Parcelable.Creator<SettingsMigrationData>() {
+ @Override
+ public SettingsMigrationData createFromParcel(Parcel in) {
+ boolean scanAlwaysAvailable = in.readBoolean();
+ boolean p2pFactoryResetPending = in.readBoolean();
+ String p2pDeviceName = in.readString();
+ boolean softApTimeoutEnabled = in.readBoolean();
+ boolean wakeupEnabled = in.readBoolean();
+ boolean scanThrottleEnabled = in.readBoolean();
+ boolean verboseLoggingEnabled = in.readBoolean();
+ return new SettingsMigrationData(
+ scanAlwaysAvailable, p2pFactoryResetPending,
+ p2pDeviceName, softApTimeoutEnabled, wakeupEnabled,
+ scanThrottleEnabled, verboseLoggingEnabled);
+ }
+
+ @Override
+ public SettingsMigrationData[] newArray(int size) {
+ return new SettingsMigrationData[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeBoolean(mScanAlwaysAvailable);
+ dest.writeBoolean(mP2pFactoryResetPending);
+ dest.writeString(mP2pDeviceName);
+ dest.writeBoolean(mSoftApTimeoutEnabled);
+ dest.writeBoolean(mWakeupEnabled);
+ dest.writeBoolean(mScanThrottleEnabled);
+ dest.writeBoolean(mVerboseLoggingEnabled);
+ }
+
+ /**
+ * @return True if scans are allowed even when wifi is toggled off, false otherwise.
+ */
+ public boolean isScanAlwaysAvailable() {
+ return mScanAlwaysAvailable;
+ }
+
+ /**
+ * @return indicate whether factory reset request is pending.
+ */
+ public boolean isP2pFactoryResetPending() {
+ return mP2pFactoryResetPending;
+ }
+
+ /**
+ * @return the Wi-Fi peer-to-peer device name
+ */
+ public @Nullable String getP2pDeviceName() {
+ return mP2pDeviceName;
+ }
+
+ /**
+ * @return Whether soft AP will shut down after a timeout period when no devices are
+ * connected.
+ */
+ public boolean isSoftApTimeoutEnabled() {
+ return mSoftApTimeoutEnabled;
+ }
+
+ /**
+ * @return whether Wi-Fi Wakeup feature is enabled.
+ */
+ public boolean isWakeUpEnabled() {
+ return mWakeupEnabled;
+ }
+
+ /**
+ * @return Whether wifi scan throttle is enabled or not.
+ */
+ public boolean isScanThrottleEnabled() {
+ return mScanThrottleEnabled;
+ }
+
+ /**
+ * @return Whether to enable verbose logging in Wi-Fi.
+ */
+ public boolean isVerboseLoggingEnabled() {
+ return mVerboseLoggingEnabled;
+ }
+
+ /**
+ * Builder to create instance of {@link SettingsMigrationData}.
+ */
+ public static final class Builder {
+ private boolean mScanAlwaysAvailable;
+ private boolean mP2pFactoryResetPending;
+ private String mP2pDeviceName;
+ private boolean mSoftApTimeoutEnabled;
+ private boolean mWakeupEnabled;
+ private boolean mScanThrottleEnabled;
+ private boolean mVerboseLoggingEnabled;
+
+ public Builder() {
+ }
+
+ /**
+ * Setting to allow scans even when wifi is toggled off.
+ *
+ * @param available true if available, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setScanAlwaysAvailable(boolean available) {
+ mScanAlwaysAvailable = available;
+ return this;
+ }
+
+ /**
+ * Indicate whether factory reset request is pending.
+ *
+ * @param pending true if pending, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setP2pFactoryResetPending(boolean pending) {
+ mP2pFactoryResetPending = pending;
+ return this;
+ }
+
+ /**
+ * The Wi-Fi peer-to-peer device name
+ *
+ * @param name Name if set, null otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setP2pDeviceName(@Nullable String name) {
+ mP2pDeviceName = name;
+ return this;
+ }
+
+ /**
+ * Whether soft AP will shut down after a timeout period when no devices are connected.
+ *
+ * @param enabled true if enabled, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setSoftApTimeoutEnabled(boolean enabled) {
+ mSoftApTimeoutEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Value to specify if Wi-Fi Wakeup feature is enabled.
+ *
+ * @param enabled true if enabled, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setWakeUpEnabled(boolean enabled) {
+ mWakeupEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Whether wifi scan throttle is enabled or not.
+ *
+ * @param enabled true if enabled, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setScanThrottleEnabled(boolean enabled) {
+ mScanThrottleEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Setting to enable verbose logging in Wi-Fi.
+ *
+ * @param enabled true if enabled, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setVerboseLoggingEnabled(boolean enabled) {
+ mVerboseLoggingEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Build an instance of {@link SettingsMigrationData}.
+ *
+ * @return Instance of {@link SettingsMigrationData}.
+ */
+ public @NonNull SettingsMigrationData build() {
+ return new SettingsMigrationData(mScanAlwaysAvailable, mP2pFactoryResetPending,
+ mP2pDeviceName, mSoftApTimeoutEnabled, mWakeupEnabled, mScanThrottleEnabled,
+ mVerboseLoggingEnabled);
+ }
+ }
+ }
+
+ /**
+ * Load data from Settings.Global values.
+ *
+ * <p>
+ * Note:
+ * <li> This is method is invoked once on the first bootup. OEM can safely delete these settings
+ * once the migration is complete. The first & only relevant invocation of
+ * {@link #loadFromSettings(Context)} ()} occurs when a previously released
+ * device upgrades to the wifi mainline module from an OEM implementation of the wifi stack.
+ * </li>
+ *
+ * @param context Context to use for loading the settings provider.
+ * @return Instance of {@link SettingsMigrationData} for migrating data.
+ */
+ @NonNull
+ public static SettingsMigrationData loadFromSettings(@NonNull Context context) {
+ return new SettingsMigrationData.Builder()
+ .setScanAlwaysAvailable(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1)
+ .setP2pFactoryResetPending(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET, 0) == 1)
+ .setP2pDeviceName(
+ Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.WIFI_P2P_DEVICE_NAME))
+ .setSoftApTimeoutEnabled(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1) == 1)
+ .setWakeUpEnabled(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1)
+ .setScanThrottleEnabled(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_SCAN_THROTTLE_ENABLED, 1) == 1)
+ .setVerboseLoggingEnabled(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0) == 1)
+ .build();
+ }
}
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 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/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index d958488..060ddf0 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -125,6 +125,7 @@
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.setMaxNumberOfClients(10)
+ .setAutoShutdownEnabled(true)
.setShutdownTimeoutMillis(500000)
.enableClientControlByUser(true)
.setClientList(testBlockedClientList, testAllowedClientList)
@@ -136,6 +137,7 @@
assertThat(original.getChannel()).isEqualTo(149);
assertThat(original.isHiddenSsid()).isEqualTo(true);
assertThat(original.getMaxNumberOfClients()).isEqualTo(10);
+ assertThat(original.isAutoShutdownEnabled()).isEqualTo(true);
assertThat(original.getShutdownTimeoutMillis()).isEqualTo(500000);
assertThat(original.isClientControlByUserEnabled()).isEqualTo(true);
assertThat(original.getBlockedClientList()).isEqualTo(testBlockedClientList);
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 853212a..234d929 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -2401,4 +2401,15 @@
assertFalse(mWifiManager.isAutoWakeupEnabled());
verify(mWifiService).isAutoWakeupEnabled();
}
+
+
+ @Test
+ public void testScanAvailable() throws Exception {
+ mWifiManager.setScanAlwaysAvailable(true);
+ verify(mWifiService).setScanAlwaysAvailable(true);
+
+ when(mWifiService.isScanAlwaysAvailable()).thenReturn(false);
+ assertFalse(mWifiManager.isScanAlwaysAvailable());
+ verify(mWifiService).isScanAlwaysAvailable();
+ }
}
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();
}
}