diff options
71 files changed, 1515 insertions, 1559 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index e44e9022bf5d..38bb75f33f02 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -25,7 +25,6 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.AlarmManager; import android.app.AppGlobals; import android.app.IUidObserver; import android.app.job.IJobScheduler; @@ -95,7 +94,6 @@ import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob; import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob; -import com.android.server.job.JobSchedulerServiceDumpProto.RegisteredJob; import com.android.server.job.controllers.BackgroundJobsController; import com.android.server.job.controllers.BatteryController; import com.android.server.job.controllers.ConnectivityController; @@ -117,7 +115,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; @@ -240,18 +237,7 @@ public class JobSchedulerService extends com.android.server.SystemService final SparseIntArray mBackingUpUids = new SparseIntArray(); /** - * Count standby heartbeats, and keep track of which beat each bucket's jobs will - * next become runnable. Index into this array is by normalized bucket: - * { ACTIVE, WORKING, FREQUENT, RARE, NEVER }. The ACTIVE and NEVER bucket - * milestones are not updated: ACTIVE apps get jobs whenever they ask for them, - * and NEVER apps don't get them at all. - */ - final long[] mNextBucketHeartbeat = { 0, 0, 0, 0, Long.MAX_VALUE }; - long mHeartbeat = 0; - long mLastHeartbeatTime = sElapsedRealtimeClock.millis(); - - /** - * Named indices into the STANDBY_BEATS array, for clarity in referring to + * Named indices into standby bucket arrays, for clarity in referring to * specific buckets' bookkeeping. */ public static final int ACTIVE_INDEX = 0; @@ -260,21 +246,6 @@ public class JobSchedulerService extends com.android.server.SystemService public static final int RARE_INDEX = 3; public static final int NEVER_INDEX = 4; - /** - * Bookkeeping about when jobs last run. We keep our own record in heartbeat time, - * rather than rely on Usage Stats' timestamps, because heartbeat time can be - * manipulated for testing purposes and we need job runnability to track that rather - * than real time. - * - * Outer SparseArray slices by user handle; inner map of package name to heartbeat - * is a HashMap<> rather than ArrayMap<> because we expect O(hundreds) of keys - * and it will be accessed in a known-hot code path. - */ - final SparseArray<HashMap<String, Long>> mLastJobHeartbeats = new SparseArray<>(); - - static final String HEARTBEAT_TAG = "*job.heartbeat*"; - final HeartbeatAlarmListener mHeartbeatAlarm = new HeartbeatAlarmListener(); - // -- Pre-allocated temporaries only for use in assignJobsToContextsLocked -- private class ConstantsObserver extends ContentObserver { @@ -311,11 +282,6 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.e(TAG, "Bad jobscheduler settings", e); } } - - if (mConstants.USE_HEARTBEATS) { - // Reset the heartbeat alarm based on the new heartbeat duration - setNextHeartbeatAlarm(); - } } } @@ -465,13 +431,15 @@ public class JobSchedulerService extends com.android.server.SystemService private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count"; private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time"; private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time"; - private static final String KEY_STANDBY_HEARTBEAT_TIME = "standby_heartbeat_time"; - private static final String KEY_STANDBY_WORKING_BEATS = "standby_working_beats"; - private static final String KEY_STANDBY_FREQUENT_BEATS = "standby_frequent_beats"; - private static final String KEY_STANDBY_RARE_BEATS = "standby_rare_beats"; + private static final String DEPRECATED_KEY_STANDBY_HEARTBEAT_TIME = + "standby_heartbeat_time"; + private static final String DEPRECATED_KEY_STANDBY_WORKING_BEATS = "standby_working_beats"; + private static final String DEPRECATED_KEY_STANDBY_FREQUENT_BEATS = + "standby_frequent_beats"; + private static final String DEPRECATED_KEY_STANDBY_RARE_BEATS = "standby_rare_beats"; private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac"; private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac"; - private static final String KEY_USE_HEARTBEATS = "use_heartbeats"; + private static final String DEPRECATED_KEY_USE_HEARTBEATS = "use_heartbeats"; private static final int DEFAULT_MIN_IDLE_COUNT = 1; private static final int DEFAULT_MIN_CHARGING_COUNT = 1; @@ -488,13 +456,8 @@ public class JobSchedulerService extends com.android.server.SystemService private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE; private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS; private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS; - private static final long DEFAULT_STANDBY_HEARTBEAT_TIME = 11 * 60 * 1000L; - private static final int DEFAULT_STANDBY_WORKING_BEATS = 11; // ~ 2 hours, with 11min beats - private static final int DEFAULT_STANDBY_FREQUENT_BEATS = 43; // ~ 8 hours - private static final int DEFAULT_STANDBY_RARE_BEATS = 130; // ~ 24 hours private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f; private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f; - private static final boolean DEFAULT_USE_HEARTBEATS = false; /** * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things @@ -617,26 +580,7 @@ public class JobSchedulerService extends com.android.server.SystemService * The minimum backoff time to allow for exponential backoff. */ long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME; - /** - * How often we recalculate runnability based on apps' standby bucket assignment. - * This should be prime relative to common time interval lengths such as a quarter- - * hour or day, so that the heartbeat drifts relative to wall-clock milestones. - */ - long STANDBY_HEARTBEAT_TIME = DEFAULT_STANDBY_HEARTBEAT_TIME; - /** - * Mapping: standby bucket -> number of heartbeats between each sweep of that - * bucket's jobs. - * - * Bucket assignments as recorded in the JobStatus objects are normalized to be - * indices into this array, rather than the raw constants used - * by AppIdleHistory. - */ - final int[] STANDBY_BEATS = { - 0, - DEFAULT_STANDBY_WORKING_BEATS, - DEFAULT_STANDBY_FREQUENT_BEATS, - DEFAULT_STANDBY_RARE_BEATS - }; + /** * The fraction of a job's running window that must pass before we * consider running it when the network is congested. @@ -647,11 +591,6 @@ public class JobSchedulerService extends com.android.server.SystemService * we consider matching it against a metered network. */ public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC; - /** - * Whether to use heartbeats or rolling window for quota management. True will use - * heartbeats, false will use a rolling window. - */ - public boolean USE_HEARTBEATS = DEFAULT_USE_HEARTBEATS; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -709,19 +648,10 @@ public class JobSchedulerService extends com.android.server.SystemService DEFAULT_MIN_LINEAR_BACKOFF_TIME); MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME, DEFAULT_MIN_EXP_BACKOFF_TIME); - STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME, - DEFAULT_STANDBY_HEARTBEAT_TIME); - STANDBY_BEATS[WORKING_INDEX] = mParser.getInt(KEY_STANDBY_WORKING_BEATS, - DEFAULT_STANDBY_WORKING_BEATS); - STANDBY_BEATS[FREQUENT_INDEX] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS, - DEFAULT_STANDBY_FREQUENT_BEATS); - STANDBY_BEATS[RARE_INDEX] = mParser.getInt(KEY_STANDBY_RARE_BEATS, - DEFAULT_STANDBY_RARE_BEATS); CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC, DEFAULT_CONN_CONGESTION_DELAY_FRAC); CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC, DEFAULT_CONN_PREFETCH_RELAX_FRAC); - USE_HEARTBEATS = mParser.getBoolean(KEY_USE_HEARTBEATS, DEFAULT_USE_HEARTBEATS); } void dump(IndentingPrintWriter pw) { @@ -757,17 +687,8 @@ public class JobSchedulerService extends com.android.server.SystemService pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println(); pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println(); pw.printPair(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println(); - pw.printPair(KEY_STANDBY_HEARTBEAT_TIME, STANDBY_HEARTBEAT_TIME).println(); - pw.print("standby_beats={"); - pw.print(STANDBY_BEATS[0]); - for (int i = 1; i < STANDBY_BEATS.length; i++) { - pw.print(", "); - pw.print(STANDBY_BEATS[i]); - } - pw.println('}'); pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println(); pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println(); - pw.printPair(KEY_USE_HEARTBEATS, USE_HEARTBEATS).println(); pw.decreaseIndent(); } @@ -797,13 +718,8 @@ public class JobSchedulerService extends com.android.server.SystemService proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT); proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME); proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME); - proto.write(ConstantsProto.STANDBY_HEARTBEAT_TIME_MS, STANDBY_HEARTBEAT_TIME); - for (int period : STANDBY_BEATS) { - proto.write(ConstantsProto.STANDBY_BEATS, period); - } proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC); proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC); - proto.write(ConstantsProto.USE_HEARTBEATS, USE_HEARTBEATS); } } @@ -1441,9 +1357,6 @@ public class JobSchedulerService extends com.android.server.SystemService mAppStateTracker = Preconditions.checkNotNull( LocalServices.getService(AppStateTracker.class)); - if (mConstants.USE_HEARTBEATS) { - setNextHeartbeatAlarm(); - } // Register br for package removals and user removals. final IntentFilter filter = new IntentFilter(); @@ -1647,7 +1560,7 @@ public class JobSchedulerService extends com.android.server.SystemService } delayMillis = Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS); - JobStatus newJob = new JobStatus(failureToReschedule, getCurrentHeartbeat(), + JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis, JobStatus.NO_LATEST_RUNTIME, backoffAttempts, failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis()); @@ -1682,8 +1595,7 @@ public class JobSchedulerService extends com.android.server.SystemService * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead * to underscheduling at least, rather than if we had taken the last execution time to be the * start of the execution. - * <p>Unlike a reschedule prior to execution, in this case we advance the next-heartbeat - * tracking as though the job were newly-scheduled. + * * @return A new job representing the execution criteria for this instantiation of the * recurring job. */ @@ -1736,7 +1648,7 @@ public class JobSchedulerService extends com.android.server.SystemService if (newLatestRuntimeElapsed < elapsedNow) { Slog.wtf(TAG, "Rescheduling calculated latest runtime in the past: " + newLatestRuntimeElapsed); - return new JobStatus(periodicToReschedule, getCurrentHeartbeat(), + return new JobStatus(periodicToReschedule, elapsedNow + period - flex, elapsedNow + period, 0 /* backoffAttempt */, sSystemClock.millis() /* lastSuccessfulRunTime */, @@ -1751,64 +1663,13 @@ public class JobSchedulerService extends com.android.server.SystemService newEarliestRunTimeElapsed / 1000 + ", " + newLatestRuntimeElapsed / 1000 + "]s"); } - return new JobStatus(periodicToReschedule, getCurrentHeartbeat(), + return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed, newLatestRuntimeElapsed, 0 /* backoffAttempt */, sSystemClock.millis() /* lastSuccessfulRunTime */, periodicToReschedule.getLastFailedRunTime()); } - /* - * We default to "long enough ago that every bucket's jobs are immediately runnable" to - * avoid starvation of apps in uncommon-use buckets that might arise from repeated - * reboot behavior. - */ - long heartbeatWhenJobsLastRun(String packageName, final @UserIdInt int userId) { - // The furthest back in pre-boot time that we need to bother with - long heartbeat = -mConstants.STANDBY_BEATS[RARE_INDEX]; - boolean cacheHit = false; - synchronized (mLock) { - HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId); - if (jobPackages != null) { - long cachedValue = jobPackages.getOrDefault(packageName, Long.MAX_VALUE); - if (cachedValue < Long.MAX_VALUE) { - cacheHit = true; - heartbeat = cachedValue; - } - } - if (!cacheHit) { - // We haven't seen it yet; ask usage stats about it - final long timeSinceJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId); - if (timeSinceJob < Long.MAX_VALUE) { - // Usage stats knows about it from before, so calculate back from that - // and go from there. - heartbeat = mHeartbeat - (timeSinceJob / mConstants.STANDBY_HEARTBEAT_TIME); - } - // If usage stats returned its "not found" MAX_VALUE, we still have the - // negative default 'heartbeat' value we established above - setLastJobHeartbeatLocked(packageName, userId, heartbeat); - } - } - if (DEBUG_STANDBY) { - Slog.v(TAG, "Last job heartbeat " + heartbeat + " for " - + packageName + "/" + userId); - } - return heartbeat; - } - - long heartbeatWhenJobsLastRun(JobStatus job) { - return heartbeatWhenJobsLastRun(job.getSourcePackageName(), job.getSourceUserId()); - } - - void setLastJobHeartbeatLocked(String packageName, int userId, long heartbeat) { - HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId); - if (jobPackages == null) { - jobPackages = new HashMap<>(); - mLastJobHeartbeats.put(userId, jobPackages); - } - jobPackages.put(packageName, heartbeat); - } - // JobCompletedListener implementations. /** @@ -2176,82 +2037,6 @@ public class JobSchedulerService extends com.android.server.SystemService mMaybeQueueFunctor.postProcess(); } - /** - * Heartbeat tracking. The heartbeat alarm is intentionally non-wakeup. - */ - class HeartbeatAlarmListener implements AlarmManager.OnAlarmListener { - - @Override - public void onAlarm() { - synchronized (mLock) { - final long sinceLast = sElapsedRealtimeClock.millis() - mLastHeartbeatTime; - final long beatsElapsed = sinceLast / mConstants.STANDBY_HEARTBEAT_TIME; - if (beatsElapsed > 0) { - mLastHeartbeatTime += beatsElapsed * mConstants.STANDBY_HEARTBEAT_TIME; - advanceHeartbeatLocked(beatsElapsed); - } - } - setNextHeartbeatAlarm(); - } - } - - // Intentionally does not touch the alarm timing - void advanceHeartbeatLocked(long beatsElapsed) { - if (!mConstants.USE_HEARTBEATS) { - return; - } - mHeartbeat += beatsElapsed; - if (DEBUG_STANDBY) { - Slog.v(TAG, "Advancing standby heartbeat by " + beatsElapsed - + " to " + mHeartbeat); - } - // Don't update ACTIVE or NEVER bucket milestones. Note that mHeartbeat - // will be equal to mNextBucketHeartbeat[bucket] for one beat, during which - // new jobs scheduled by apps in that bucket will be permitted to run - // immediately. - boolean didAdvanceBucket = false; - for (int i = 1; i < mNextBucketHeartbeat.length - 1; i++) { - // Did we reach or cross a bucket boundary? - if (mHeartbeat >= mNextBucketHeartbeat[i]) { - didAdvanceBucket = true; - } - while (mHeartbeat > mNextBucketHeartbeat[i]) { - mNextBucketHeartbeat[i] += mConstants.STANDBY_BEATS[i]; - } - if (DEBUG_STANDBY) { - Slog.v(TAG, " Bucket " + i + " next heartbeat " - + mNextBucketHeartbeat[i]); - } - } - - if (didAdvanceBucket) { - if (DEBUG_STANDBY) { - Slog.v(TAG, "Hit bucket boundary; reevaluating job runnability"); - } - mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); - } - } - - void setNextHeartbeatAlarm() { - final long heartbeatLength; - synchronized (mLock) { - if (!mConstants.USE_HEARTBEATS) { - return; - } - heartbeatLength = mConstants.STANDBY_HEARTBEAT_TIME; - } - final long now = sElapsedRealtimeClock.millis(); - final long nextBeatOrdinal = (now + heartbeatLength) / heartbeatLength; - final long nextHeartbeat = nextBeatOrdinal * heartbeatLength; - if (DEBUG_STANDBY) { - Slog.i(TAG, "Setting heartbeat alarm for " + nextHeartbeat - + " = " + TimeUtils.formatDuration(nextHeartbeat - now)); - } - AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); - am.setExact(AlarmManager.ELAPSED_REALTIME, nextHeartbeat, - HEARTBEAT_TAG, mHeartbeatAlarm, mHandler); - } - /** Returns true if both the calling and source users for the job are started. */ private boolean areUsersStartedLocked(final JobStatus job) { boolean sourceStarted = ArrayUtils.contains(mStartedUsers, job.getSourceUserId()); @@ -2323,54 +2108,6 @@ public class JobSchedulerService extends com.android.server.SystemService return false; } - if (mConstants.USE_HEARTBEATS) { - // If the app is in a non-active standby bucket, make sure we've waited - // an appropriate amount of time since the last invocation. During device- - // wide parole, standby bucketing is ignored. - // - // Jobs in 'active' apps are not subject to standby, nor are jobs that are - // specifically marked as exempt. - if (DEBUG_STANDBY) { - Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString() - + " parole=" + mInParole + " active=" + job.uidActive - + " exempt=" + job.getJob().isExemptedFromAppStandby()); - } - if (!mInParole - && !job.uidActive - && !job.getJob().isExemptedFromAppStandby()) { - final int bucket = job.getStandbyBucket(); - if (DEBUG_STANDBY) { - Slog.v(TAG, " bucket=" + bucket + " heartbeat=" + mHeartbeat - + " next=" + mNextBucketHeartbeat[bucket]); - } - if (mHeartbeat < mNextBucketHeartbeat[bucket]) { - // Only skip this job if the app is still waiting for the end of its nominal - // bucket interval. Once it's waited that long, we let it go ahead and clear. - // The final (NEVER) bucket is special; we never age those apps' jobs into - // runnability. - final long appLastRan = heartbeatWhenJobsLastRun(job); - if (bucket >= mConstants.STANDBY_BEATS.length - || (mHeartbeat > appLastRan - && mHeartbeat < appLastRan + mConstants.STANDBY_BEATS[bucket])) { - if (job.getWhenStandbyDeferred() == 0) { - if (DEBUG_STANDBY) { - Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < " - + (appLastRan + mConstants.STANDBY_BEATS[bucket]) - + " for " + job); - } - job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis()); - } - return false; - } else { - if (DEBUG_STANDBY) { - Slog.v(TAG, "Bucket deferred job aged into runnability at " - + mHeartbeat + " : " + job); - } - } - } - } - } - // The expensive check: validate that the defined package+service is // still present & viable. return isComponentUsable(job); @@ -2439,9 +2176,6 @@ public class JobSchedulerService extends com.android.server.SystemService // Job pending/active doesn't affect the readiness of a job. - // Skipping the heartbeat check as this will only come into play when using the rolling - // window quota management system. - // The expensive check: validate that the defined package+service is // still present & viable. return isComponentUsable(job); @@ -2450,9 +2184,6 @@ public class JobSchedulerService extends com.android.server.SystemService /** Returns the maximum amount of time this job could run for. */ public long getMaxJobExecutionTimeMs(JobStatus job) { synchronized (mLock) { - if (mConstants.USE_HEARTBEATS) { - return JobServiceContext.EXECUTING_TIMESLICE_MILLIS; - } return Math.min(mQuotaController.getMaxJobExecutionTimeMsLocked(job), JobServiceContext.EXECUTING_TIMESLICE_MILLIS); } @@ -2498,56 +2229,6 @@ public class JobSchedulerService extends com.android.server.SystemService final class LocalService implements JobSchedulerInternal { /** - * The current bucket heartbeat ordinal - */ - public long currentHeartbeat() { - return getCurrentHeartbeat(); - } - - /** - * Heartbeat ordinal at which the given standby bucket's jobs next become runnable - */ - public long nextHeartbeatForBucket(int bucket) { - synchronized (mLock) { - return mNextBucketHeartbeat[bucket]; - } - } - - /** - * Heartbeat ordinal for the given app. This is typically the heartbeat at which - * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run - * jobs in a long time is immediately runnable even if the app is bucketed into - * an infrequent time allocation. - */ - public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, - final int appStandbyBucket) { - if (appStandbyBucket == 0 || - appStandbyBucket >= mConstants.STANDBY_BEATS.length) { - // ACTIVE => everything can be run right away - // NEVER => we won't run them anyway, so let them go in the future - // as soon as the app enters normal use - if (DEBUG_STANDBY) { - Slog.v(TAG, "Base heartbeat forced ZERO for new job in " - + packageName + "/" + userId); - } - return 0; - } - - final long baseHeartbeat = heartbeatWhenJobsLastRun(packageName, userId); - if (DEBUG_STANDBY) { - Slog.v(TAG, "Base heartbeat " + baseHeartbeat + " for new job in " - + packageName + "/" + userId); - } - return baseHeartbeat; - } - - public void noteJobStart(String packageName, int userId) { - synchronized (mLock) { - setLastJobHeartbeatLocked(packageName, userId, mHeartbeat); - } - } - - /** * Returns a list of all pending jobs. A running job is not considered pending. Periodic * jobs are always considered pending. */ @@ -3158,12 +2839,6 @@ public class JobSchedulerService extends com.android.server.SystemService } } - long getCurrentHeartbeat() { - synchronized (mLock) { - return mHeartbeat; - } - } - // Shell command infrastructure int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) { try { @@ -3249,21 +2924,6 @@ public class JobSchedulerService extends com.android.server.SystemService return 0; } - // Shell command infrastructure - int executeHeartbeatCommand(PrintWriter pw, int numBeats) { - if (numBeats < 1) { - pw.println(getCurrentHeartbeat()); - return 0; - } - - pw.print("Advancing standby heartbeat by "); - pw.println(numBeats); - synchronized (mLock) { - advanceHeartbeatLocked(numBeats); - } - return 0; - } - void triggerDockState(boolean idleState) { final Intent dockIntent; if (idleState) { @@ -3319,20 +2979,6 @@ public class JobSchedulerService extends com.android.server.SystemService } pw.println(); - pw.println(" Heartbeat:"); - pw.print(" Current: "); pw.println(mHeartbeat); - pw.println(" Next"); - pw.print(" ACTIVE: "); pw.println(mNextBucketHeartbeat[0]); - pw.print(" WORKING: "); pw.println(mNextBucketHeartbeat[1]); - pw.print(" FREQUENT: "); pw.println(mNextBucketHeartbeat[2]); - pw.print(" RARE: "); pw.println(mNextBucketHeartbeat[3]); - pw.print(" Last heartbeat: "); - TimeUtils.formatDuration(mLastHeartbeatTime, nowElapsed, pw); - pw.println(); - pw.print(" Next heartbeat: "); - TimeUtils.formatDuration(mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME, - nowElapsed, pw); - pw.println(); pw.print(" In parole?: "); pw.print(mInParole); pw.println(); @@ -3358,9 +3004,6 @@ public class JobSchedulerService extends com.android.server.SystemService } job.dump(pw, " ", true, nowElapsed); - pw.print(" Last run heartbeat: "); - pw.print(heartbeatWhenJobsLastRun(job)); - pw.println(); pw.print(" Ready: "); pw.print(isReadyToBeExecutedLocked(job)); @@ -3514,15 +3157,6 @@ public class JobSchedulerService extends com.android.server.SystemService } proto.end(settingsToken); - proto.write(JobSchedulerServiceDumpProto.CURRENT_HEARTBEAT, mHeartbeat); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[0]); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[1]); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[2]); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[3]); - proto.write(JobSchedulerServiceDumpProto.LAST_HEARTBEAT_TIME_MILLIS, - mLastHeartbeatTime - nowUptime); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT_TIME_MILLIS, - mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME - nowUptime); proto.write(JobSchedulerServiceDumpProto.IN_PAROLE, mInParole); proto.write(JobSchedulerServiceDumpProto.IN_THERMAL, mThermalConstraint); @@ -3564,7 +3198,6 @@ public class JobSchedulerService extends com.android.server.SystemService } proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_PRESENT, componentPresent); - proto.write(RegisteredJob.LAST_RUN_HEARTBEAT, heartbeatWhenJobsLastRun(job)); proto.end(rjToken); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java index e3614413121a..01d158ba9452 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java @@ -340,15 +340,8 @@ public final class JobSchedulerShellCommand extends ShellCommand { private int doHeartbeat(PrintWriter pw) throws Exception { checkPermission("manipulate scheduler heartbeat"); - final String arg = getNextArg(); - final int numBeats = (arg != null) ? Integer.parseInt(arg) : 0; - - final long ident = Binder.clearCallingIdentity(); - try { - return mInternal.executeHeartbeatCommand(pw, numBeats); - } finally { - Binder.restoreCallingIdentity(ident); - } + pw.println("Heartbeat command is no longer supported"); + return -1; } private int triggerDockState(PrintWriter pw) throws Exception { @@ -401,8 +394,7 @@ public final class JobSchedulerShellCommand extends ShellCommand { pw.println(" -u or --user: specify which user's job is to be run; the default is"); pw.println(" the primary or system user"); pw.println(" heartbeat [num]"); - pw.println(" With no argument, prints the current standby heartbeat. With a positive"); - pw.println(" argument, advances the standby heartbeat by that number."); + pw.println(" No longer used."); pw.println(" monitor-battery [on|off]"); pw.println(" Control monitoring of all battery changes. Off by default. Turning"); pw.println(" on makes get-battery-seq useful."); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 7da128f9d3ec..4d9f1331e6ff 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -285,9 +285,6 @@ public final class JobServiceContext implements ServiceConnection { UsageStatsManagerInternal usageStats = LocalServices.getService(UsageStatsManagerInternal.class); usageStats.setLastJobRunTime(jobPackage, jobUserId, mExecutionStartTimeElapsed); - JobSchedulerInternal jobScheduler = - LocalServices.getService(JobSchedulerInternal.class); - jobScheduler.noteJobStart(jobPackage, jobUserId); mAvailable = false; mStoppedReason = null; mStoppedTime = 0; diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index d69faf37397c..4321fc716b4d 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -189,7 +189,7 @@ public final class JobStore { if (utcTimes != null) { Pair<Long, Long> elapsedRuntimes = convertRtcBoundsToElapsed(utcTimes, elapsedNow); - JobStatus newJob = new JobStatus(job, job.getBaseHeartbeat(), + JobStatus newJob = new JobStatus(job, elapsedRuntimes.first, elapsedRuntimes.second, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime()); newJob.prepareLocked(am); @@ -944,10 +944,9 @@ public final class JobStore { JobSchedulerInternal service = LocalServices.getService(JobSchedulerInternal.class); final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName, sourceUserId, elapsedNow); - long currentHeartbeat = service != null ? service.currentHeartbeat() : 0; JobStatus js = new JobStatus( jobBuilder.build(), uid, sourcePackageName, sourceUserId, - appBucket, currentHeartbeat, sourceTag, + appBucket, sourceTag, elapsedRuntimes.first, elapsedRuntimes.second, lastSuccessfulRunTime, lastFailedRunTime, (rtcIsGood) ? null : rtcRuntimes, internalFlags); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java index f8cf6ae04950..a67aadfc6959 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java @@ -47,7 +47,6 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.JobSchedulerService.Constants; -import com.android.server.job.JobServiceContext; import com.android.server.job.StateControllerProto; import com.android.server.net.NetworkPolicyManagerInternal; @@ -88,8 +87,6 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") private final ArraySet<Network> mAvailableNetworks = new ArraySet<>(); - private boolean mUseQuotaLimit; - private static final int MSG_DATA_SAVER_TOGGLED = 0; private static final int MSG_UID_RULES_CHANGES = 1; private static final int MSG_REEVALUATE_JOBS = 2; @@ -110,8 +107,6 @@ public final class ConnectivityController extends StateController implements mConnManager.registerNetworkCallback(request, mNetworkCallback); mNetPolicyManager.registerListener(mNetPolicyListener); - - mUseQuotaLimit = !mConstants.USE_HEARTBEATS; } @GuardedBy("mLock") @@ -142,24 +137,6 @@ public final class ConnectivityController extends StateController implements } } - @GuardedBy("mLock") - @Override - public void onConstantsUpdatedLocked() { - if (mConstants.USE_HEARTBEATS) { - // App idle exceptions are only requested for the rolling quota system. - if (DEBUG) Slog.i(TAG, "Revoking all standby exceptions"); - for (int i = 0; i < mRequestedWhitelistJobs.size(); ++i) { - int uid = mRequestedWhitelistJobs.keyAt(i); - mNetPolicyManagerInternal.setAppIdleWhitelist(uid, false); - } - mRequestedWhitelistJobs.clear(); - } - if (mUseQuotaLimit == mConstants.USE_HEARTBEATS) { - mUseQuotaLimit = !mConstants.USE_HEARTBEATS; - mHandler.obtainMessage(MSG_REEVALUATE_JOBS).sendToTarget(); - } - } - /** * Returns true if the job's requested network is available. This DOES NOT necesarilly mean * that the UID has been granted access to the network. @@ -237,11 +214,6 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") @Override public void evaluateStateLocked(JobStatus jobStatus) { - if (mConstants.USE_HEARTBEATS) { - // This should only be used for the rolling quota system. - return; - } - if (!jobStatus.hasConnectivityConstraint()) { return; } @@ -263,9 +235,6 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") @Override public void reevaluateStateLocked(final int uid) { - if (mConstants.USE_HEARTBEATS) { - return; - } // Check if we still need a connectivity exception in case the JobService was disabled. ArraySet<JobStatus> jobs = mTrackedJobs.get(uid); if (jobs == null) { @@ -329,9 +298,7 @@ public final class ConnectivityController extends StateController implements */ private boolean isInsane(JobStatus jobStatus, Network network, NetworkCapabilities capabilities, Constants constants) { - final long maxJobExecutionTimeMs = mUseQuotaLimit - ? mService.getMaxJobExecutionTimeMs(jobStatus) - : JobServiceContext.EXECUTING_TIMESLICE_MILLIS; + final long maxJobExecutionTimeMs = mService.getMaxJobExecutionTimeMs(jobStatus); final long downloadBytes = jobStatus.getEstimatedNetworkDownloadBytes(); if (downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { @@ -617,7 +584,6 @@ public final class ConnectivityController extends StateController implements @Override public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) { - pw.print("mUseQuotaLimit="); pw.println(mUseQuotaLimit); if (mRequestedWhitelistJobs.size() > 0) { pw.print("Requested standby exceptions:"); 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 6f2b33453891..ae4abd65ab60 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 @@ -169,12 +169,6 @@ public final class JobStatus { private final int numFailures; /** - * Current standby heartbeat when this job was scheduled or last ran. Used to - * pin the runnability check regardless of the job's app moving between buckets. - */ - private final long baseHeartbeat; - - /** * Which app standby bucket this job's app is in. Updated when the app is moved to a * different bucket. */ @@ -350,8 +344,6 @@ public final class JobStatus { * @param standbyBucket The standby bucket that the source package is currently assigned to, * cached here for speed of handling during runnability evaluations (and updated when bucket * assignments are changed) - * @param heartbeat Timestamp of when the job was created, in the standby-related - * timebase. * @param tag A string associated with the job for debugging/logging purposes. * @param numFailures Count of how many times this job has requested a reschedule because * its work was not yet finished. @@ -364,13 +356,12 @@ public final class JobStatus { * @param internalFlags Non-API property flags about this job */ private JobStatus(JobInfo job, int callingUid, String sourcePackageName, - int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures, + int sourceUserId, int standbyBucket, String tag, int numFailures, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) { this.job = job; this.callingUid = callingUid; this.standbyBucket = standbyBucket; - this.baseHeartbeat = heartbeat; int tempSourceUid = -1; if (sourceUserId != -1 && sourcePackageName != null) { @@ -440,7 +431,7 @@ public final class JobStatus { public JobStatus(JobStatus jobStatus) { this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), - jobStatus.getStandbyBucket(), jobStatus.getBaseHeartbeat(), + jobStatus.getStandbyBucket(), jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(), jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(), @@ -462,13 +453,13 @@ public final class JobStatus { * standby bucket is whatever the OS thinks it should be at this moment. */ public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId, - int standbyBucket, long baseHeartbeat, String sourceTag, + int standbyBucket, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, Pair<Long, Long> persistedExecutionTimesUTC, int innerFlags) { this(job, callingUid, sourcePkgName, sourceUserId, - standbyBucket, baseHeartbeat, + standbyBucket, sourceTag, 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, lastSuccessfulRunTime, lastFailedRunTime, innerFlags); @@ -486,13 +477,13 @@ public final class JobStatus { } /** Create a new job to be rescheduled with the provided parameters. */ - public JobStatus(JobStatus rescheduling, long newBaseHeartbeat, + public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis, long newLatestRuntimeElapsedMillis, int backoffAttempt, long lastSuccessfulRunTime, long lastFailedRunTime) { this(rescheduling.job, rescheduling.getUid(), rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(), - rescheduling.getStandbyBucket(), newBaseHeartbeat, + rescheduling.getStandbyBucket(), rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis, newLatestRuntimeElapsedMillis, lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags()); @@ -529,11 +520,8 @@ public final class JobStatus { int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage, sourceUserId, elapsedNow); JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); - long currentHeartbeat = js != null - ? js.baseHeartbeatForApp(jobPackage, sourceUserId, standbyBucket) - : 0; return new JobStatus(job, callingUid, sourcePkg, sourceUserId, - standbyBucket, currentHeartbeat, tag, 0, + standbyBucket, tag, 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, /*innerFlags=*/ 0); @@ -714,10 +702,6 @@ public final class JobStatus { return standbyBucket; } - public long getBaseHeartbeat() { - return baseHeartbeat; - } - public void setStandbyBucket(int newBucket) { standbyBucket = newBucket; } @@ -1631,10 +1615,6 @@ public final class JobStatus { } pw.print(prefix); pw.print("Standby bucket: "); pw.println(getBucketName()); - if (standbyBucket > 0) { - pw.print(prefix); pw.print("Base heartbeat: "); - pw.println(baseHeartbeat); - } if (whenStandbyDeferred != 0) { pw.print(prefix); pw.print(" Deferred since: "); TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java index b8cfac4d4206..043cda469db2 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -416,13 +416,6 @@ public final class QuotaController extends StateController { private volatile boolean mInParole; - /** - * If the QuotaController should throttle apps based on their standby bucket and job activity. - * If false, all jobs will have their CONSTRAINT_WITHIN_QUOTA bit set to true immediately and - * indefinitely. - */ - private boolean mShouldThrottle; - /** How much time each app will have to run jobs within their standby bucket window. */ private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS; @@ -594,8 +587,6 @@ public final class QuotaController extends StateController { } catch (RemoteException e) { // ignored; both services live in system_server } - - mShouldThrottle = !mConstants.USE_HEARTBEATS; } @Override @@ -607,8 +598,6 @@ public final class QuotaController extends StateController { public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { final int userId = jobStatus.getSourceUserId(); final String pkgName = jobStatus.getSourcePackageName(); - // Still need to track jobs even if mShouldThrottle is false in case it's set to true at - // some point. ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName); if (jobs == null) { jobs = new ArraySet<>(); @@ -616,16 +605,10 @@ public final class QuotaController extends StateController { } jobs.add(jobStatus); jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA); - if (mShouldThrottle) { - final boolean isWithinQuota = isWithinQuotaLocked(jobStatus); - setConstraintSatisfied(jobStatus, isWithinQuota); - if (!isWithinQuota) { - maybeScheduleStartAlarmLocked(userId, pkgName, - getEffectiveStandbyBucket(jobStatus)); - } - } else { - // QuotaController isn't throttling, so always set to true. - jobStatus.setQuotaConstraintSatisfied(true); + final boolean isWithinQuota = isWithinQuotaLocked(jobStatus); + setConstraintSatisfied(jobStatus, isWithinQuota); + if (!isWithinQuota) { + maybeScheduleStartAlarmLocked(userId, pkgName, getEffectiveStandbyBucket(jobStatus)); } } @@ -674,20 +657,6 @@ public final class QuotaController extends StateController { } @Override - public void onConstantsUpdatedLocked() { - if (mShouldThrottle == mConstants.USE_HEARTBEATS) { - mShouldThrottle = !mConstants.USE_HEARTBEATS; - - // Update job bookkeeping out of band. - BackgroundThread.getHandler().post(() -> { - synchronized (mLock) { - maybeUpdateAllConstraintsLocked(); - } - }); - } - } - - @Override public void onAppRemovedLocked(String packageName, int uid) { if (packageName == null) { Slog.wtf(TAG, "Told app removed but given null package name."); @@ -780,8 +749,6 @@ public final class QuotaController extends StateController { boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName, final int standbyBucket) { if (standbyBucket == NEVER_INDEX) return false; - // This check is needed in case the flag is toggled after a job has been registered. - if (!mShouldThrottle) return true; // Quota constraint is not enforced while charging or when parole is on. if (mChargeTracker.isCharging() || mInParole) { @@ -1820,8 +1787,7 @@ public final class QuotaController extends StateController { if (timer != null && timer.isActive()) { timer.rescheduleCutoff(); } - if (!mShouldThrottle || maybeUpdateConstraintForPkgLocked(userId, - packageName)) { + if (maybeUpdateConstraintForPkgLocked(userId, packageName)) { mStateChangedListener.onControllerStateChanged(); } } @@ -2396,7 +2362,7 @@ public final class QuotaController extends StateController { changed = true; } - if (changed && mShouldThrottle) { + if (changed) { // Update job bookkeeping out of band. BackgroundThread.getHandler().post(() -> { synchronized (mLock) { @@ -2561,7 +2527,6 @@ public final class QuotaController extends StateController { @Override public void dumpControllerStateLocked(final IndentingPrintWriter pw, final Predicate<JobStatus> predicate) { - pw.println("Is throttling: " + mShouldThrottle); pw.println("Is charging: " + mChargeTracker.isCharging()); pw.println("In parole: " + mInParole); pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis()); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index f6c72ea9d3b9..bfbf66743f37 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -56,6 +56,7 @@ import "frameworks/base/core/proto/android/telecomm/enums.proto"; import "frameworks/base/core/proto/android/telephony/enums.proto"; import "frameworks/base/core/proto/android/view/enums.proto"; import "frameworks/base/core/proto/android/wifi/enums.proto"; +import "frameworks/base/core/proto/android/stats/textclassifier/textclassifier_enums.proto"; /** * The master atom class. This message defines all of the available @@ -319,6 +320,15 @@ message Atom { 217 [(log_from_module) = "permissioncontroller"]; PermissionAppsFragmentViewed permission_apps_fragment_viewed = 218 [(log_from_module) = "permissioncontroller"]; + TextSelectionEvent text_selection_event = + 219 [(log_from_module) = "textclassifier"]; + TextLinkifyEvent text_linkify_event = + 220 [(log_from_module) = "textclassifier"]; + ConversationActionsEvent conversation_actions_event = + 221 [(log_from_module) = "textclassifier"]; + LanguageDetectionEvent language_detection_event = + 222 [(log_from_module) = "textclassifier"]; + } // Pulled events will start at field 10000. @@ -6790,3 +6800,136 @@ message PermissionAppsFragmentViewed { } optional Category category = 6; } + +/** + * Logs when there is a smart selection related event. + * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java + * Logged from: TextClassifierEventLogger.java + */ +message TextSelectionEvent { + // A session ID. + optional string session_id = 1; + + // Event type of this event. + optional android.stats.textclassifier.EventType event_type = 2; + + // Name of the model that is involved in this event. + optional string model_name = 3; + + // Type of widget that was involved in triggering this event. + optional android.stats.textclassifier.WidgetType widget_type = 4; + + // Index of this event in a session. + optional int32 event_index = 5; + + // Entity type that is involved. + optional string entity_type = 6; + + // Relative word index of the start of the selection. + optional int32 relative_word_start_index = 7; + + // Relative word (exclusive) index of the end of the selection. + optional int32 relative_word_end_index = 8; + + // Relative word index of the start of the smart selection. + optional int32 relative_suggested_word_start_index = 9; + + // Relative word (exclusive) index of the end of the smart selection. + optional int32 relative_suggested_word_end_index = 10; +} + +/** + * Logs when there is a smart linkify related event. + * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java + * Logged from: TextClassifierEventLogger.java + */ +message TextLinkifyEvent { + // A session ID. + optional string session_id = 1; + + // Event type of this event. + optional android.stats.textclassifier.EventType event_type = 2; + + // Name of the model that is involved in this event. + optional string model_name = 3; + + // Type of widget that was involved in triggering this event. + optional android.stats.textclassifier.WidgetType widget_type = 4; + + // Index of this event in a session. + optional int32 event_index = 5; + + // Entity type that is involved. + optional string entity_type = 6; + + // Number of links detected. + optional int32 num_links = 7; + + // The total length of all links. + optional int32 linked_text_length = 8; + + // Length of input text. + optional int32 text_length = 9; + + // Time spent on generating links in ms. + optional int64 latency_millis = 10; +} + +/** + * Logs when there is a conversation actions related event. + * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java + * Logged from: TextClassifierEventLogger.java + */ +message ConversationActionsEvent { + // A session ID. + optional string session_id = 1; + + // Event type of this event. + optional android.stats.textclassifier.EventType event_type = 2; + + // Name of the model that is involved in this event. + optional string model_name = 3; + + // Type of widget that was involved in triggering this event. + optional android.stats.textclassifier.WidgetType widget_type = 4; + + // The first entity type that is involved. + optional string first_entity_type = 5; + + // The second entity type that is involved. + optional string second_entity_type = 6; + + // The third entity type that is involved. + optional string third_entity_type = 7; + + // The score of the first entity type. + optional float score = 8; +} + +/** + * Logs when there is a language detection related event. + * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java + * Logged from: TextClassifierEventLogger.java + */ +message LanguageDetectionEvent { + // A session ID. + optional string session_id = 1; + + // Event type of this event. + optional android.stats.textclassifier.EventType event_type = 2; + + // Name of the model that is involved in this event. + optional string model_name = 3; + + // Type of widget that was involved in triggering this event. + optional android.stats.textclassifier.WidgetType widget_type = 4; + + // Detected language. + optional string language_tag = 5; + + // Score of the detected language. + optional float score = 6; + + // Position of this action. + optional int32 action_index = 7; +} diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index c30a6f491807..eb53b7c20dbc 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -121,8 +121,6 @@ Landroid/bluetooth/IBluetoothManagerCallback$Stub;-><init>()V Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap; Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V -Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V -Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard; Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V @@ -194,7 +192,6 @@ Landroid/content/res/DrawableCache;-><init>()V Landroid/content/UndoManager;-><init>()V Landroid/database/IContentObserver$Stub;-><init>()V Landroid/database/IContentObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/database/IContentObserver; -Landroid/database/IContentObserver;->onChange(ZLandroid/net/Uri;I)V Landroid/database/sqlite/SQLiteConnectionPool;->$assertionsDisabled:Z Landroid/database/sqlite/SQLiteDatabase;->$assertionsDisabled:Z Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager; @@ -723,9 +720,6 @@ Lcom/android/internal/location/GpsNetInitiatedHandler;->handleNiNotification(Lco Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider; -Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)V -Lcom/android/internal/location/ILocationProvider;->setLocationProviderManager(Lcom/android/internal/location/ILocationProviderManager;)V -Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager; Lcom/android/internal/logging/MetricsLogger;-><init>()V @@ -736,7 +730,6 @@ Lcom/android/internal/os/BatterySipper$DrainType;->values()[Lcom/android/interna Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService; Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService; Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback; -Lcom/android/internal/preference/YesNoPreference;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V Lcom/android/internal/R$anim;->fade_in:I Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I Lcom/android/internal/R$array;->config_autoBrightnessLevels:I diff --git a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl index 5f73e551d57c..c9dc019bd2f2 100644 --- a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl +++ b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl @@ -18,6 +18,8 @@ package android.companion; /** @hide */ interface ICompanionDeviceDiscoveryServiceCallback { + @UnsupportedAppUsage oneway void onDeviceSelected(String packageName, int userId, String deviceAddress); + @UnsupportedAppUsage oneway void onDeviceSelectionCancel(); } diff --git a/core/java/android/database/IContentObserver.aidl b/core/java/android/database/IContentObserver.aidl index 22dc9fed59c4..623556695341 100644 --- a/core/java/android/database/IContentObserver.aidl +++ b/core/java/android/database/IContentObserver.aidl @@ -29,5 +29,6 @@ interface IContentObserver * observed. selfUpdate is true if the update was caused by a call to * commit on the cursor that is being observed. */ + @UnsupportedAppUsage oneway void onChange(boolean selfUpdate, in Uri uri, int userId); } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index cc8c182b867e..68857da940d5 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -2337,6 +2337,12 @@ public class CameraDeviceImpl extends CameraDevice final CaptureCallbackHolder holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId); + if (holder == null) { + Log.e(TAG, String.format("Receive capture error on unknown request ID %d", + requestId)); + return; + } + final CaptureRequest request = holder.getRequest(subsequenceId); Runnable failureDispatch = null; diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index b377e8dbe14f..6165146ece0a 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -123,6 +123,7 @@ public class RemoteCallbackList<E extends IInterface> { IBinder binder = callback.asBinder(); try { Callback cb = new Callback(callback, cookie); + unregister(callback); binder.linkToDeath(cb, 0); mCallbacks.put(binder, cb); return true; diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index e1a9898b6292..a26243c7cad5 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -480,7 +480,7 @@ public class EditorInfo implements InputType, Parcelable { * matter what user ID the calling process has. * * <p>Note: This field will be silently ignored when - * {@link android.view.inputmethod.InputMethodSystemProperty#MULTI_CLIENT_IME_ENABLED} is + * {@link com.android.server.inputmethod.InputMethodSystemProperty#MULTI_CLIENT_IME_ENABLED} is * {@code true}.</p> * * <p>Note also that pseudo handles such as {@link UserHandle#ALL} are not supported.</p> diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index a46580dcc539..18d4d691f726 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -464,7 +464,9 @@ public abstract class WebSettings { * Note that the feature will continue to be supported on older versions of * Android as before. * - * This function does not have any effect. + * @deprecated In Android O and afterwards, this function does not have + * any effect, the form data will be saved to platform's autofill service + * if applicable. */ @Deprecated public abstract void setSaveFormData(boolean save); diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java index 5091eea1898d..ad3563316854 100644 --- a/core/java/android/widget/StackView.java +++ b/core/java/android/widget/StackView.java @@ -42,6 +42,8 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.LinearInterpolator; import android.widget.RemoteViews.RemoteView; +import com.android.internal.R; + import java.lang.ref.WeakReference; @RemoteView @@ -1241,14 +1243,40 @@ public class StackView extends AdapterViewAnimator { info.setScrollable(getChildCount() > 1); if (isEnabled()) { if (getDisplayedChild() < getChildCount() - 1) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); + if (mStackMode == ITEMS_SLIDE_UP) { + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN); + } else { + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP); + } } if (getDisplayedChild() > 0) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); + if (mStackMode == ITEMS_SLIDE_UP) { + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP); + } else { + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN); + } } } } + private boolean goForward() { + if (getDisplayedChild() < getChildCount() - 1) { + showNext(); + return true; + } + return false; + } + + private boolean goBackward() { + if (getDisplayedChild() > 0) { + showPrevious(); + return true; + } + return false; + } + /** @hide */ @Override public boolean performAccessibilityActionInternal(int action, Bundle arguments) { @@ -1260,17 +1288,25 @@ public class StackView extends AdapterViewAnimator { } switch (action) { case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { - if (getDisplayedChild() < getChildCount() - 1) { - showNext(); - return true; - } - } return false; + return goForward(); + } case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { - if (getDisplayedChild() > 0) { - showPrevious(); - return true; + return goBackward(); + } + case R.id.accessibilityActionPageUp: { + if (mStackMode == ITEMS_SLIDE_UP) { + return goBackward(); + } else { + return goForward(); + } + } + case R.id.accessibilityActionPageDown: { + if (mStackMode == ITEMS_SLIDE_UP) { + return goForward(); + } else { + return goBackward(); } - } return false; + } } return false; } diff --git a/core/java/com/android/internal/preference/YesNoPreference.java b/core/java/com/android/internal/preference/YesNoPreference.java index 7abf416bf0af..46d14a16de1e 100644 --- a/core/java/com/android/internal/preference/YesNoPreference.java +++ b/core/java/com/android/internal/preference/YesNoPreference.java @@ -16,6 +16,7 @@ package com.android.internal.preference; +import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.os.Parcel; @@ -40,6 +41,7 @@ public class YesNoPreference extends DialogPreference { this(context, attrs, defStyleAttr, 0); } + @UnsupportedAppUsage public YesNoPreference(Context context, AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.yesNoPreferenceStyle); } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index c715577cb7d2..cf0394d466ea 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -58,7 +58,7 @@ oneway interface IStatusBar void topAppWindowChanged(int displayId, boolean menuVisible); void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition, - boolean showImeSwitcher); + boolean showImeSwitcher, boolean isMultiClientImeEnabled); void setWindowState(int display, int window, int state); void showRecentApps(boolean triggeredFromAltTab); diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 598c3917bf95..85ae18e86793 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -49,7 +49,7 @@ interface IStatusBarService @UnsupportedAppUsage void removeIcon(String slot); void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition, - boolean showImeSwitcher); + boolean showImeSwitcher, boolean isMultiClientImeEnabled); void expandSettingsPanel(String subPanel); // ---- Methods below are for use by the status bar policy services ---- diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java index 0d87afa42e3e..e7d240a1035e 100644 --- a/core/java/com/android/internal/widget/MediaNotificationView.java +++ b/core/java/com/android/internal/widget/MediaNotificationView.java @@ -26,8 +26,6 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.RemoteViews; -import java.util.ArrayList; - /** * A TextView that can float around an image on the end. * @@ -44,7 +42,6 @@ public class MediaNotificationView extends FrameLayout { private View mMainColumn; private View mMediaContent; private int mImagePushIn; - private ArrayList<VisibilityChangeListener> mListeners; public MediaNotificationView(Context context) { this(context, null); @@ -171,48 +168,4 @@ public class MediaNotificationView extends FrameLayout { mMainColumn = findViewById(com.android.internal.R.id.notification_main_column); mMediaContent = findViewById(com.android.internal.R.id.notification_media_content); } - - @Override - public void onVisibilityAggregated(boolean isVisible) { - super.onVisibilityAggregated(isVisible); - for (int i = 0; i < mListeners.size(); i++) { - mListeners.get(i).onAggregatedVisibilityChanged(isVisible); - } - } - - /** - * Add a listener to receive updates on the visibility of this view - * - * @param listener The listener to add. - */ - public void addVisibilityListener(VisibilityChangeListener listener) { - if (mListeners == null) { - mListeners = new ArrayList<>(); - } - if (!mListeners.contains(listener)) { - mListeners.add(listener); - } - } - - /** - * Remove the specified listener - * - * @param listener The listener to remove. - */ - public void removeVisibilityListener(VisibilityChangeListener listener) { - if (mListeners != null) { - mListeners.remove(listener); - } - } - - /** - * Interface for receiving updates when the view's visibility changes - */ - public interface VisibilityChangeListener { - /** - * Method called when the visibility of this view has changed - * @param isVisible true if the view is now visible - */ - void onAggregatedVisibilityChanged(boolean isVisible); - } } diff --git a/core/java/com/android/server/job/JobSchedulerInternal.java b/core/java/com/android/server/job/JobSchedulerInternal.java index 425ec473bc8e..dbf3b984d5fe 100644 --- a/core/java/com/android/server/job/JobSchedulerInternal.java +++ b/core/java/com/android/server/job/JobSchedulerInternal.java @@ -16,7 +16,6 @@ package com.android.server.job; -import android.annotation.UserIdInt; import android.app.job.JobInfo; import java.util.List; @@ -27,31 +26,6 @@ import java.util.List; */ public interface JobSchedulerInternal { - // Bookkeeping about app standby bucket scheduling - - /** - * The current bucket heartbeat ordinal - */ - long currentHeartbeat(); - - /** - * Heartbeat ordinal at which the given standby bucket's jobs next become runnable - */ - long nextHeartbeatForBucket(int bucket); - - /** - * Heartbeat ordinal for the given app. This is typically the heartbeat at which - * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run - * jobs in a long time is immediately runnable even if the app is bucketed into - * an infrequent time allocation. - */ - public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, int appBucket); - - /** - * Tell the scheduler when a JobServiceContext starts running a job in an app - */ - void noteJobStart(String packageName, int userId); - /** * Returns a list of pending jobs scheduled by the system service. */ diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index c534aa419595..5d4be5502138 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -38,10 +38,10 @@ message JobSchedulerServiceDumpProto { optional ConstantsProto settings = 1; - optional int32 current_heartbeat = 14; - repeated int32 next_heartbeat = 15; - optional int64 last_heartbeat_time_millis = 16; - optional int64 next_heartbeat_time_millis = 17; + reserved 14; // current_heartbeat + reserved 15; // next_heartbeat + reserved 16; // last_heartbeat_time_millis + reserved 17; // next_heartbeat_time_millis optional bool in_parole = 18; optional bool in_thermal = 19; @@ -64,7 +64,7 @@ message JobSchedulerServiceDumpProto { optional bool is_uid_backing_up = 7; optional bool is_component_present = 8; - optional int64 last_run_heartbeat = 9; + reserved 9; // last_run_heartbeat } repeated RegisteredJob registered_jobs = 3; @@ -214,13 +214,13 @@ message ConstantsProto { // assignment. This should be prime relative to common time interval lengths // such as a quarter-hour or day, so that the heartbeat drifts relative to // wall-clock milestones. - optional int64 standby_heartbeat_time_ms = 19; + reserved 19; // standby_heartbeat_time_ms // Mapping: standby bucket -> number of heartbeats between each sweep of // that bucket's jobs. // Bucket assignments as recorded in the JobStatus objects are normalized to // be indices into this array, rather than the raw constants used by // AppIdleHistory. - repeated int32 standby_beats = 20; + reserved 20; // standby_beats // The fraction of a job's running window that must pass before we // consider running it when the network is congested. optional double conn_congestion_delay_frac = 21; @@ -229,7 +229,7 @@ message ConstantsProto { optional double conn_prefetch_relax_frac = 22; // Whether to use heartbeats or rolling window for quota management. True // will use heartbeats, false will use a rolling window. - optional bool use_heartbeats = 23; + reserved 23; // use_heartbeats message QuotaController { option (.android.msg_privacy).dest = DEST_AUTOMATIC; diff --git a/core/proto/android/stats/textclassifier/textclassifier_enums.proto b/core/proto/android/stats/textclassifier/textclassifier_enums.proto new file mode 100644 index 000000000000..1885f19c6377 --- /dev/null +++ b/core/proto/android/stats/textclassifier/textclassifier_enums.proto @@ -0,0 +1,85 @@ +/* + * 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. + */ + +syntax = "proto2"; +package android.stats.textclassifier; +option java_multiple_files = true; + +enum EventType { + TYPE_UNKNOWN = 0; + // User started a new selection. + SELECTION_STARTED = 1; + // User modified an existing selection. + SELECTION_MODIFIED = 2; + // Smart selection triggered for a single token (word). + SMART_SELECTION_SINGLE = 3; + // Smart selection triggered spanning multiple tokens (words). + SMART_SELECTION_MULTI = 4; + // Something else other than user or the default TextClassifier triggered a selection. + AUTO_SELECTION = 5; + // Smart actions shown to the user. + ACTIONS_SHOWN = 6; + // User clicked a link. + LINK_CLICKED = 7; + // User typed over the selection. + OVERTYPE = 8; + // User clicked on Copy action. + COPY_ACTION = 9; + // User clicked on Paste action. + PASTE_ACTION = 10; + // User clicked on Cut action. + CUT_ACTION = 11; + // User clicked on Share action. + SHARE_ACTION = 12; + // User clicked on a Smart action. + SMART_ACTION = 13; + // User dragged+dropped the selection. + SELECTION_DRAG = 14; + // Selection is destroyed. + SELECTION_DESTROYED = 15; + // User clicked on a custom action. + OTHER_ACTION = 16; + // User clicked on Select All action + SELECT_ALL = 17; + // User reset the smart selection. + SELECTION_RESET = 18; + // User composed a reply. + MANUAL_REPLY = 19; + // TextClassifier generated some actions + ACTIONS_GENERATED = 20; +} + +enum WidgetType { + WIDGET_TYPE_UNKNOWN = 0; + // Standard TextView + WIDGET_TYPE_TEXTVIEW = 1; + // EditText + WIDGET_TYPE_EDITTEXT = 2; + // Not selectable textview + WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = 3; + // Standard Webview + WIDGET_TYPE_WEBVIEW = 4; + // Editable TextView + WIDGET_TYPE_EDIT_WEBVIEW = 5; + // Custom text widget + WIDGET_TYPE_CUSTOM_TEXTVIEW = 6; + // Custom editable text widget. + WIDGET_TYPE_CUSTOM_EDITTEXT = 7; + // Non-selectable text widget. + WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = 8; + // Notification + WIDGET_TYPE_NOTIFICATION = 9; +} diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java index 0eba2edbb3c3..46873b9eb70b 100644 --- a/core/tests/coretests/src/android/os/ParcelTest.java +++ b/core/tests/coretests/src/android/os/ParcelTest.java @@ -43,8 +43,8 @@ public class ParcelTest { // WorkSource can be updated. p.writeInterfaceToken(INTERFACE_TOKEN_1); - assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1)); - assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid()); + assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_2)); + assertEquals(WORK_SOURCE_2, p.readCallingWorkSourceUid()); // WorkSource can be updated to unset value. assertEquals(true, p.replaceCallingWorkSourceUid(Binder.UNSET_WORKSOURCE)); @@ -56,18 +56,16 @@ public class ParcelTest { @Test public void testCallingWorkSourceUidAfterEnforce() { Parcel p = Parcel.obtain(); - // Write headers manually so that we do not invoke #writeInterfaceToken. - p.writeInt(1); // strict mode header - p.writeInt(WORK_SOURCE_1); // worksource header. - p.writeString(INTERFACE_TOKEN_1); // interface token. + p.writeInterfaceToken(INTERFACE_TOKEN_1); + assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1)); p.setDataPosition(0); p.enforceInterface(INTERFACE_TOKEN_1); assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid()); // WorkSource can be updated. - assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1)); - assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid()); + assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_2)); + assertEquals(WORK_SOURCE_2, p.readCallingWorkSourceUid()); p.recycle(); } diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java index 3361fa21e44b..1d294d51a235 100644 --- a/graphics/java/android/graphics/RectF.java +++ b/graphics/java/android/graphics/RectF.java @@ -27,7 +27,7 @@ import java.io.PrintWriter; /** * RectF holds four float coordinates for a rectangle. The rectangle is - * represented by the coordinates of its 4 edges (left, top, right bottom). + * represented by the coordinates of its 4 edges (left, top, right, bottom). * These fields can be accessed directly. Use width() and height() to retrieve * the rectangle's width and height. Note: most methods do not check to see that * the coordinates are sorted correctly (i.e. left <= right and top <= bottom). diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl index a5716304f0d8..8ae972bde4f9 100644 --- a/location/java/com/android/internal/location/ILocationProvider.aidl +++ b/location/java/com/android/internal/location/ILocationProvider.aidl @@ -29,10 +29,13 @@ import com.android.internal.location.ProviderRequest; */ interface ILocationProvider { + @UnsupportedAppUsage oneway void setLocationProviderManager(in ILocationProviderManager manager); + @UnsupportedAppUsage oneway void setRequest(in ProviderRequest request, in WorkSource ws); + @UnsupportedAppUsage oneway void sendExtraCommand(String command, in Bundle extras); // --- deprecated and will be removed the future --- diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 59754e007fbb..81d1ea5137e0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -1434,7 +1434,7 @@ public class AccessPoint implements Comparable<AccessPoint> { void update(@Nullable WifiConfiguration config) { mConfig = config; - if (mConfig != null) { + if (mConfig != null && !isPasspoint()) { ssid = removeDoubleQuotes(mConfig.SSID); } networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID; diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index a7b44443fc9c..2727880685c5 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -366,8 +366,10 @@ public class BugreportProgressService extends Service { checkProgressUpdated(mInfo, (int) progress); } - // TODO(b/127431371): Add error code handling for bugreport API errors. - // Logging errors and removing progress notification for now. + /** + * Logs errors and stops the service on which this bugreport was running. + * Also stops progress notification (if any). + */ @Override public void onError(@BugreportErrorCode int errorCode) { trackInfoWithId(); diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index df3f36e0291b..3f598ffad709 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -95,6 +95,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.plugins.GlobalActionsPanelPlugin; import com.android.systemui.statusbar.phone.ScrimController; +import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.phone.UnlockMethodCache; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.EmergencyDialerConstants; @@ -1523,6 +1524,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private boolean mShowing; private float mScrimAlpha; private ResetOrientationData mResetOrientationData; + private boolean mHadTopUi; + private final StatusBarWindowController mStatusBarWindowController; ActionsDialog(Context context, MyAdapter adapter, GlobalActionsPanelPlugin.PanelViewController plugin) { @@ -1531,6 +1534,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mAdapter = adapter; mColorExtractor = Dependency.get(SysuiColorExtractor.class); mStatusBarService = Dependency.get(IStatusBarService.class); + mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); // Window initialization Window window = getWindow(); @@ -1706,6 +1710,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, public void show() { super.show(); mShowing = true; + mHadTopUi = mStatusBarWindowController.getForceHasTopUi(); + mStatusBarWindowController.setForceHasTopUi(true); mBackgroundDrawable.setAlpha(0); mGlobalActionsLayout.setTranslationX(mGlobalActionsLayout.getAnimationOffsetX()); mGlobalActionsLayout.setTranslationY(mGlobalActionsLayout.getAnimationOffsetY()); @@ -1738,7 +1744,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, .translationX(mGlobalActionsLayout.getAnimationOffsetX()) .translationY(mGlobalActionsLayout.getAnimationOffsetY()) .setDuration(300) - .withEndAction(super::dismiss) + .withEndAction(this::completeDismiss) .setInterpolator(new LogAccelerateInterpolator()) .setUpdateListener(animation -> { int alpha = (int) ((1f - (Float) animation.getAnimatedValue()) @@ -1751,10 +1757,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } void dismissImmediately() { - super.dismiss(); mShowing = false; dismissPanel(); resetOrientation(); + completeDismiss(); + } + + private void completeDismiss() { + mStatusBarWindowController.setForceHasTopUi(mHadTopUi); + super.dismiss(); } private void dismissPanel() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 6329af56077b..fa0fe136b8eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -43,7 +43,6 @@ import android.os.Looper; import android.os.Message; import android.util.Pair; import android.util.SparseArray; -import android.view.inputmethod.InputMethodSystemProperty; import androidx.annotation.VisibleForTesting; @@ -481,7 +480,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, - boolean showImeSwitcher) { + boolean showImeSwitcher, boolean isMultiClientImeEnabled) { synchronized (mLock) { mHandler.removeMessages(MSG_SHOW_IME_BUTTON); SomeArgs args = SomeArgs.obtain(); @@ -489,6 +488,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args.argi2 = vis; args.argi3 = backDisposition; args.argi4 = showImeSwitcher ? 1 : 0; + args.argi5 = isMultiClientImeEnabled ? 1 : 0; args.arg1 = token; Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, args); m.sendToTarget(); @@ -801,11 +801,10 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition, - boolean showImeSwitcher) { + boolean showImeSwitcher, boolean isMultiClientImeEnabled) { if (displayId == INVALID_DISPLAY) return; - if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED - && mLastUpdatedImeDisplayId != displayId + if (!isMultiClientImeEnabled && mLastUpdatedImeDisplayId != displayId && mLastUpdatedImeDisplayId != INVALID_DISPLAY) { // Set previous NavBar's IME window status as invisible when IME // window switched to another display for single-session IME case. @@ -891,7 +890,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args = (SomeArgs) msg.obj; handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */, args.argi2 /* vis */, args.argi3 /* backDisposition */, - args.argi4 != 0 /* showImeSwitcher */); + args.argi4 != 0 /* showImeSwitcher */, + args.argi5 != 0 /* isMultiClientImeEnabled */); break; case MSG_SHOW_RECENT_APPS: for (int i = 0; i < mCallbacks.size(); i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java index 38f9bff2a63f..20e8b733ce6a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java @@ -39,7 +39,6 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.widget.MediaNotificationView; import com.android.systemui.Dependency; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.TransformableView; @@ -68,7 +67,6 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi private View mSeekBarView; private Context mContext; private MetricsLogger mMetricsLogger; - private boolean mIsViewVisible; @VisibleForTesting protected SeekBar.OnSeekBarChangeListener mSeekListener = @@ -90,33 +88,11 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi } }; - MediaNotificationView.VisibilityChangeListener mVisibilityListener = - new MediaNotificationView.VisibilityChangeListener() { - @Override - public void onAggregatedVisibilityChanged(boolean isVisible) { - mIsViewVisible = isVisible; - if (isVisible) { - // Restart timer if we're currently playing and didn't already have one going - PlaybackState state = mMediaController.getPlaybackState(); - if (state != null && state.getState() == PlaybackState.STATE_PLAYING - && mSeekBarTimer == null && mSeekBarView != null - && mSeekBarView.getVisibility() != View.GONE) { - startTimer(); - } - } else { - clearTimer(); - } - } - }; - private MediaController.Callback mMediaCallback = new MediaController.Callback() { @Override public void onSessionDestroyed() { clearTimer(); mMediaController.unregisterCallback(this); - if (mView instanceof MediaNotificationView) { - ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener); - } } @Override @@ -150,16 +126,10 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi mContext = ctx; mMediaManager = Dependency.get(NotificationMediaManager.class); mMetricsLogger = Dependency.get(MetricsLogger.class); - - if (mView instanceof MediaNotificationView) { - MediaNotificationView mediaView = (MediaNotificationView) mView; - mediaView.addVisibilityListener(mVisibilityListener); - } } private void resolveViews() { mActions = mView.findViewById(com.android.internal.R.id.media_actions); - mIsViewVisible = mView.isShown(); final MediaSession.Token token = mRow.getEntry().notification.getNotification().extras .getParcelable(Notification.EXTRA_MEDIA_SESSION); @@ -238,19 +208,18 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi private void startTimer() { clearTimer(); - if (mIsViewVisible) { - mSeekBarTimer = new Timer(true /* isDaemon */); - mSeekBarTimer.schedule(new TimerTask() { - @Override - public void run() { - mHandler.post(mOnUpdateTimerTick); - } - }, 0, PROGRESS_UPDATE_INTERVAL); - } + mSeekBarTimer = new Timer(true /* isDaemon */); + mSeekBarTimer.schedule(new TimerTask() { + @Override + public void run() { + mHandler.post(mOnUpdateTimerTick); + } + }, 0, PROGRESS_UPDATE_INTERVAL); } private void clearTimer() { if (mSeekBarTimer != null) { + // TODO: also trigger this when the notification panel is collapsed mSeekBarTimer.cancel(); mSeekBarTimer.purge(); mSeekBarTimer = null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt index 70d3bff9b822..832ea9e3d72e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone import android.content.Context import android.content.pm.PackageManager import android.hardware.biometrics.BiometricSourceType -import android.hardware.face.FaceManager import android.provider.Settings import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.NotificationLockscreenUserManager @@ -34,6 +33,7 @@ class KeyguardBypassController { private val unlockMethodCache: UnlockMethodCache private val statusBarStateController: StatusBarStateController + private var hasFaceFeature: Boolean /** * The pending unlock type which is set if the bypass was blocked when it happened. @@ -71,11 +71,8 @@ class KeyguardBypassController { unlockMethodCache = UnlockMethodCache.getInstance(context) this.statusBarStateController = statusBarStateController - if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) { - return - } - val faceManager = context.getSystemService(FaceManager::class.java) - if (faceManager?.isHardwareDetected != true) { + hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE) + if (!hasFaceFeature) { return } @@ -165,7 +162,7 @@ class KeyguardBypassController { pw.print(" isPulseExpanding: "); pw.println(isPulseExpanding) pw.print(" launchingAffordance: "); pw.println(launchingAffordance) pw.print(" qSExpanded: "); pw.println(qSExpanded) - pw.print(" bouncerShowing: "); pw.println(bouncerShowing) + pw.print(" hasFaceFeature: "); pw.println(hasFaceFeature) } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index c0a1b123fe77..1d4d0bd17f01 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -103,10 +103,11 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.USER_SWITCHER_ENABLED, 0) != 0; - if (!UserManager.supportsMultipleUsers() - || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH) + // TODO(b/138661450) Move IPC calls to background + if (!userSwitcherEnabled + || !UserManager.supportsMultipleUsers() || UserManager.isDeviceInDemoMode(mContext) - || !userSwitcherEnabled) { + || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index d0626ed780e2..96529929b1b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -3098,10 +3098,8 @@ public class NotificationPanelView extends PanelView implements /** * Whether the camera application can be launched for the camera launch gesture. - * - * @param keyguardIsShowing whether keyguard is being shown */ - public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) { + public boolean canCameraGestureBeLaunched() { if (!mStatusBar.isCameraAllowedByAdmin()) { return false; } @@ -3110,7 +3108,7 @@ public class NotificationPanelView extends PanelView implements String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null) ? null : resolveInfo.activityInfo.packageName; return packageToLaunch != null && - (keyguardIsShowing || !isForegroundApp(packageToLaunch)) + (mBarState != StatusBarState.SHADE || !isForegroundApp(packageToLaunch)) && !mAffordanceHelper.isSwipingInProgress(); } 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 f15b60123a80..17a3a9f79338 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -3785,10 +3785,8 @@ public class StatusBar extends SystemUI implements DemoMode, mLaunchCameraOnFinishedGoingToSleep = true; return; } - if (!mNotificationPanel.canCameraGestureBeLaunched( - mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) { - if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " + - mExpandedVisible); + if (!mNotificationPanel.canCameraGestureBeLaunched()) { + if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now"); return; } if (!mDeviceInteractive) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java index ebac855825c0..0ef981bdb3de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java @@ -76,13 +76,13 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat private final WindowManager mWindowManager; private final IActivityManager mActivityManager; private final DozeParameters mDozeParameters; - private final WindowManager.LayoutParams mLpChanged; + private final LayoutParams mLpChanged; private final boolean mKeyguardScreenRotation; private final long mLockScreenDisplayTimeout; private final Display.Mode mKeyguardDisplayMode; private final KeyguardBypassController mKeyguardBypassController; private ViewGroup mStatusBarView; - private WindowManager.LayoutParams mLp; + private LayoutParams mLp; private boolean mHasTopUi; private boolean mHasTopUiChanged; private int mBarHeight; @@ -117,7 +117,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation(); mDozeParameters = dozeParameters; mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze(); - mLpChanged = new WindowManager.LayoutParams(); + mLpChanged = new LayoutParams(); mKeyguardBypassController = keyguardBypassController; mLockScreenDisplayTimeout = context.getResources() .getInteger(R.integer.config_lockScreenDisplayTimeout); @@ -171,19 +171,19 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat // Now that the status bar window encompasses the sliding panel and its // translucent backdrop, the entire thing is made TRANSLUCENT and is // hardware-accelerated. - mLp = new WindowManager.LayoutParams( + mLp = new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, barHeight, - WindowManager.LayoutParams.TYPE_STATUS_BAR, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, + LayoutParams.TYPE_STATUS_BAR, + LayoutParams.FLAG_NOT_FOCUSABLE + | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING + | LayoutParams.FLAG_SPLIT_TOUCH + | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, PixelFormat.TRANSLUCENT); mLp.token = new Binder(); mLp.gravity = Gravity.TOP; - mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; + mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE; mLp.setTitle("StatusBar"); mLp.packageName = mContext.getPackageName(); mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; @@ -216,9 +216,9 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat private void applyKeyguardFlags(State state) { if (state.keyguardShowing) { - mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; + mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_KEYGUARD; } else { - mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; + mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_KEYGUARD; } final boolean scrimsOccludingWallpaper = @@ -226,9 +226,9 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat final boolean keyguardOrAod = state.keyguardShowing || (state.dozing && mDozeParameters.getAlwaysOn()); if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) { - mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER; } else { - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER; } if (state.dozing) { @@ -267,17 +267,17 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput) || ENABLE_REMOTE_INPUT && state.remoteInputActive || state.bubbleExpanded) { - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE; + mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM; } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) { - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE; + mLpChanged.flags |= LayoutParams.FLAG_ALT_FOCUSABLE_IM; } else { - mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + mLpChanged.flags |= LayoutParams.FLAG_NOT_FOCUSABLE; + mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM; } - mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; + mLpChanged.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE; } private void applyForceShowNavigationFlag(State state) { @@ -335,19 +335,19 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat && state.statusBarState == StatusBarState.KEYGUARD && !state.qsExpanded && !state.forceUserActivity) { mLpChanged.inputFeatures |= - WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; + LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; } else { mLpChanged.inputFeatures &= - ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; + ~LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; } } private void applyStatusBarColorSpaceAgnosticFlag(State state) { if (!isExpanded(state)) { - mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; + mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; } else { mLpChanged.privateFlags &= - ~WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; + ~LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; } } @@ -396,16 +396,16 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat mLpChanged.privateFlags |= WindowManager .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; } else { - mLpChanged.privateFlags &= ~WindowManager - .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; + mLpChanged.privateFlags + &= ~LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; } } private void applyModalFlag(State state) { if (state.headsUpShowing) { - mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCH_MODAL; } else { - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCH_MODAL; } } @@ -413,12 +413,12 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat if (state.forceDozeBrightness) { mLpChanged.screenBrightness = mScreenBrightnessDoze; } else { - mLpChanged.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE; + mLpChanged.screenBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE; } } private void applyHasTopUi(State state) { - mHasTopUiChanged = isExpanded(state); + mHasTopUiChanged = state.forceHasTopUi || isExpanded(state); } private void applyNotTouchable(State state) { @@ -642,6 +642,15 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat apply(mCurrentState); } + public boolean getForceHasTopUi() { + return mCurrentState.forceHasTopUi; + } + + public void setForceHasTopUi(boolean forceHasTopUi) { + mCurrentState.forceHasTopUi = forceHasTopUi; + apply(mCurrentState); + } + private static class State { boolean keyguardShowing; boolean keyguardOccluded; @@ -663,6 +672,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat boolean notTouchable; boolean bubblesShowing; boolean bubbleExpanded; + boolean forceHasTopUi; /** * The {@link StatusBar} state from the status bar. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 84a7d4f0ff15..1e1f21568377 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -129,7 +129,7 @@ public class CommandQueueTest extends SysuiTestCase { @Test public void testShowImeButton() { - mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true); + mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true, false); waitForIdleSync(); verify(mCallbacks).setImeWindowStatus( eq(DEFAULT_DISPLAY), eq(null), eq(1), eq(2), eq(true)); @@ -137,7 +137,7 @@ public class CommandQueueTest extends SysuiTestCase { @Test public void testShowImeButtonForSecondaryDisplay() { - mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true); + mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true, false); waitForIdleSync(); verify(mCallbacks).setImeWindowStatus( eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java index 3da9a4bdf759..db8af3975cc8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java @@ -183,7 +183,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { // Set IME window status for default NavBar. mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, - BACK_DISPOSITION_DEFAULT, true); + BACK_DISPOSITION_DEFAULT, true, false); Handler.getMain().runWithScissors(() -> { }, 500); // Verify IME window state will be updated in default NavBar & external NavBar state reset. @@ -194,7 +194,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { // Set IME window status for external NavBar. mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, - IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true); + IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true, false); Handler.getMain().runWithScissors(() -> { }, 500); // Verify IME window state will be updated in external NavBar & default NavBar state reset. diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index d923bedd15c1..6b88f5a9a6d7 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -398,7 +398,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ if (!mSecurityPolicy.checkAccessibilityAccess(this)) { return null; } - AccessibilityWindowInfo window = mA11yWindowManager.findA11yWindowInfoById(windowId); + AccessibilityWindowInfo window = + mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId); if (window != null) { AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window); windowClone.setConnectionId(mId); @@ -1362,11 +1363,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ || (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS); if (!isA11yFocusAction) { final WindowInfo windowInfo = - mA11yWindowManager.findWindowInfoById(resolvedWindowId); + mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId); if (windowInfo != null) activityToken = windowInfo.activityToken; } final AccessibilityWindowInfo a11yWindowInfo = - mA11yWindowManager.findA11yWindowInfoById(resolvedWindowId); + mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId); if (a11yWindowInfo != null && a11yWindowInfo.isInPictureInPictureMode() && mA11yWindowManager.getPictureInPictureActionReplacingConnection() != null && !isA11yFocusAction) { @@ -1419,11 +1420,13 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ int interactionId, int interrogatingPid, long interrogatingTid) { final RemoteAccessibilityConnection pipActionReplacingConnection = mA11yWindowManager.getPictureInPictureActionReplacingConnection(); - final AccessibilityWindowInfo windowInfo = - mA11yWindowManager.findA11yWindowInfoById(resolvedWindowId); - if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode() + synchronized (mLock) { + final AccessibilityWindowInfo windowInfo = + mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId); + if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode() || (pipActionReplacingConnection == null)) { - return originalCallback; + return originalCallback; + } } return new ActionReplacingCallback(originalCallback, pipActionReplacingConnection.getRemote(), interactionId, diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 814853694347..5ba777c8aef0 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -542,7 +542,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (event.getWindowId() == AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID) { // The replacer window isn't shown to services. Move its events into the pip. - AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindow(); + AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindowLocked(); if (pip != null) { int pipId = pip.getId(); event.setWindowId(pipId); @@ -771,7 +771,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (resolvedUserId != mCurrentUserId) { return null; } - if (mA11yWindowManager.findA11yWindowInfoById(windowId) == null) { + if (mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId) == null) { return null; } return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId, windowId); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java index 1e224cfaea85..315d6fa287f2 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java @@ -429,7 +429,7 @@ public class AccessibilitySecurityPolicy { if (windowId == mAccessibilityWindowManager.getActiveWindowId(userId)) { return true; } - return mAccessibilityWindowManager.findA11yWindowInfoById(windowId) != null; + return mAccessibilityWindowManager.findA11yWindowInfoByIdLocked(windowId) != null; } private boolean isShellAllowedToRetrieveWindowLocked(int userId, int windowId) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java index c12929153781..9687098b6f3f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java @@ -52,13 +52,10 @@ import java.util.Collections; import java.util.List; /** - * This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to receive - * {@link WindowInfo}s from window manager when there's an accessibility change in window. It also - * provides APIs for accessibility manager to manage {@link AccessibilityWindowInfo}s and + * This class provides APIs for accessibility manager to manage {@link AccessibilityWindowInfo}s and * {@link WindowInfo}s. */ -public class AccessibilityWindowManager - implements WindowManagerInternal.WindowsForAccessibilityCallback { +public class AccessibilityWindowManager { private static final String LOG_TAG = "AccessibilityWindowManager"; private static final boolean DEBUG = false; @@ -71,9 +68,6 @@ public class AccessibilityWindowManager private final AccessibilitySecurityPolicy mSecurityPolicy; private final AccessibilityUserManager mAccessibilityUserManager; - private final SparseArray<AccessibilityWindowInfo> mA11yWindowInfoById = new SparseArray<>(); - private final SparseArray<WindowInfo> mWindowInfoById = new SparseArray<>(); - // Connections and window tokens for cross-user windows private final SparseArray<RemoteAccessibilityConnection> mGlobalInteractionConnections = new SparseArray<>(); @@ -84,9 +78,6 @@ public class AccessibilityWindowManager mInteractionConnections = new SparseArray<>(); private final SparseArray<SparseArray<IBinder>> mWindowTokens = new SparseArray<>(); - private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>(); - private List<AccessibilityWindowInfo> mWindows; - private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection; private int mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; @@ -95,15 +86,641 @@ public class AccessibilityWindowManager private long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; private boolean mTouchInteractionInProgress; - private boolean mHasWatchOutsideTouchWindow; - private boolean mTrackingWindows = false; + // TO-DO [Multi-Display] : make DisplayWindowObserver to plural + private DisplayWindowsObserver mDisplayWindowsObserver; + + /** + * This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to + * receive {@link WindowInfo}s from window manager when there's an accessibility change in + * window and holds window lists information per display. + */ + private final class DisplayWindowsObserver implements + WindowManagerInternal.WindowsForAccessibilityCallback { + + private final int mDisplayId; + private final SparseArray<AccessibilityWindowInfo> mA11yWindowInfoById = + new SparseArray<>(); + private final SparseArray<WindowInfo> mWindowInfoById = new SparseArray<>(); + private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>(); + private List<AccessibilityWindowInfo> mWindows; + private boolean mTrackingWindows = false; + private boolean mHasWatchOutsideTouchWindow; + + /** + * Constructor for DisplayWindowsObserver. + */ + DisplayWindowsObserver(int displayId) { + mDisplayId = displayId; + } + + /** + * Starts tracking windows changes from window manager by registering callback. + * + * @return true if callback registers successful. + */ + boolean startTrackingWindowsLocked() { + boolean result = true; + + if (!mTrackingWindows) { + // Turns on the flag before setup the callback. + // In some cases, onWindowsForAccessibilityChanged will be called immediately in + // setWindowsForAccessibilityCallback. We'll lost windows if flag is false. + mTrackingWindows = true; + result = mWindowManagerInternal.setWindowsForAccessibilityCallback( + mDisplayId, this); + if (!result) { + mTrackingWindows = false; + Slog.w(LOG_TAG, "set windowsObserver callbacks fail, displayId:" + + mDisplayId); + } + } + return result; + } + + /** + * Stops tracking windows changes from window manager, and clear all windows info. + */ + void stopTrackingWindowsLocked() { + if (mTrackingWindows) { + mWindowManagerInternal.setWindowsForAccessibilityCallback( + mDisplayId, null); + mTrackingWindows = false; + clearWindowsLocked(); + } + } + + /** + * Returns true if windows changes tracking. + * + * @return true if windows changes tracking + */ + boolean isTrackingWindowsLocked() { + return mTrackingWindows; + } + + /** + * Returns accessibility windows. + * @return accessibility windows. + */ + @Nullable + List<AccessibilityWindowInfo> getWindowListLocked() { + return mWindows; + } + + /** + * Returns accessibility window info according to given windowId. + * + * @param windowId The windowId + * @return The accessibility window info + */ + @Nullable + AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) { + return mA11yWindowInfoById.get(windowId); + } + + /** + * Returns the window info according to given windowId. + * + * @param windowId The windowId + * @return The window info + */ + @Nullable + WindowInfo findWindowInfoByIdLocked(int windowId) { + return mWindowInfoById.get(windowId); + } + + /** + * Returns {@link AccessibilityWindowInfo} of PIP window. + * + * @return PIP accessibility window info + */ + @Nullable + AccessibilityWindowInfo getPictureInPictureWindowLocked() { + if (mWindows != null) { + final int windowCount = mWindows.size(); + for (int i = 0; i < windowCount; i++) { + final AccessibilityWindowInfo window = mWindows.get(i); + if (window.isInPictureInPictureMode()) { + return window; + } + } + } + return null; + } + + /** + * Sets the active flag of the window according to given windowId, others set to inactive. + * + * @param windowId The windowId + */ + void setActiveWindowLocked(int windowId) { + if (mWindows != null) { + final int windowCount = mWindows.size(); + for (int i = 0; i < windowCount; i++) { + AccessibilityWindowInfo window = mWindows.get(i); + if (window.getId() == windowId) { + window.setActive(true); + mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( + AccessibilityEvent.obtainWindowsChangedEvent(windowId, + AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)); + } else { + window.setActive(false); + } + } + } + } + + /** + * Sets the window accessibility focused according to given windowId, others set + * unfocused. + * + * @param windowId The windowId + */ + void setAccessibilityFocusedWindowLocked(int windowId) { + if (mWindows != null) { + final int windowCount = mWindows.size(); + for (int i = 0; i < windowCount; i++) { + AccessibilityWindowInfo window = mWindows.get(i); + if (window.getId() == windowId) { + window.setAccessibilityFocused(true); + mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( + AccessibilityEvent.obtainWindowsChangedEvent( + windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); + + } else { + window.setAccessibilityFocused(false); + } + } + } + } + + /** + * Computes partial interactive region of given windowId. + * + * @param windowId The windowId + * @param outRegion The output to which to write the bounds. + * @return true if outRegion is not empty. + */ + boolean computePartialInteractiveRegionForWindowLocked(int windowId, + @NonNull Region outRegion) { + if (mWindows == null) { + return false; + } + + // Windows are ordered in z order so start from the bottom and find + // the window of interest. After that all windows that cover it should + // be subtracted from the resulting region. Note that for accessibility + // we are returning only interactive windows. + Region windowInteractiveRegion = null; + boolean windowInteractiveRegionChanged = false; + + final int windowCount = mWindows.size(); + final Region currentWindowRegions = new Region(); + for (int i = windowCount - 1; i >= 0; i--) { + AccessibilityWindowInfo currentWindow = mWindows.get(i); + if (windowInteractiveRegion == null) { + if (currentWindow.getId() == windowId) { + currentWindow.getRegionInScreen(currentWindowRegions); + outRegion.set(currentWindowRegions); + windowInteractiveRegion = outRegion; + continue; + } + } else if (currentWindow.getType() + != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) { + currentWindow.getRegionInScreen(currentWindowRegions); + if (windowInteractiveRegion.op(currentWindowRegions, Region.Op.DIFFERENCE)) { + windowInteractiveRegionChanged = true; + } + } + } + + return windowInteractiveRegionChanged; + } + + List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) { + final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId); + if (targetWindow != null && mHasWatchOutsideTouchWindow) { + final List<Integer> outsideWindowsId = new ArrayList<>(); + for (int i = 0; i < mWindowInfoById.size(); i++) { + final WindowInfo window = mWindowInfoById.valueAt(i); + if (window != null && window.layer < targetWindow.layer + && window.hasFlagWatchOutsideTouch) { + outsideWindowsId.add(mWindowInfoById.keyAt(i)); + } + } + return outsideWindowsId; + } + return Collections.emptyList(); + } + + /** + * Callbacks from window manager when there's an accessibility change in windows. + * + * @param forceSend Send the windows for accessibility even if they haven't changed. + * @param windows The windows for accessibility. + */ + @Override + public void onWindowsForAccessibilityChanged(boolean forceSend, + @NonNull List<WindowInfo> windows) { + synchronized (mLock) { + if (DEBUG) { + Slog.i(LOG_TAG, "Display Id = " + mDisplayId); + Slog.i(LOG_TAG, "Windows changed: " + windows); + } + if (shouldUpdateWindowsLocked(forceSend, windows)) { + cacheWindows(windows); + // Lets the policy update the focused and active windows. + updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), + windows); + // Someone may be waiting for the windows - advertise it. + mLock.notifyAll(); + } + } + } + + private boolean shouldUpdateWindowsLocked(boolean forceSend, + @NonNull List<WindowInfo> windows) { + if (forceSend) { + return true; + } + + final int windowCount = windows.size(); + // We computed the windows and if they changed notify the client. + if (mCachedWindowInfos.size() != windowCount) { + // Different size means something changed. + return true; + } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) { + // Since we always traverse windows from high to low layer + // the old and new windows at the same index should be the + // same, otherwise something changed. + for (int i = 0; i < windowCount; i++) { + WindowInfo oldWindow = mCachedWindowInfos.get(i); + WindowInfo newWindow = windows.get(i); + // We do not care for layer changes given the window + // order does not change. This brings no new information + // to the clients. + if (windowChangedNoLayer(oldWindow, newWindow)) { + return true; + } + } + } + + return false; + } + + private void cacheWindows(List<WindowInfo> windows) { + final int oldWindowCount = mCachedWindowInfos.size(); + for (int i = oldWindowCount - 1; i >= 0; i--) { + mCachedWindowInfos.remove(i).recycle(); + } + final int newWindowCount = windows.size(); + for (int i = 0; i < newWindowCount; i++) { + WindowInfo newWindow = windows.get(i); + mCachedWindowInfos.add(WindowInfo.obtain(newWindow)); + } + } + + private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) { + if (oldWindow == newWindow) { + return false; + } + if (oldWindow == null) { + return true; + } + if (newWindow == null) { + return true; + } + if (oldWindow.type != newWindow.type) { + return true; + } + if (oldWindow.focused != newWindow.focused) { + return true; + } + if (oldWindow.token == null) { + if (newWindow.token != null) { + return true; + } + } else if (!oldWindow.token.equals(newWindow.token)) { + return true; + } + if (oldWindow.parentToken == null) { + if (newWindow.parentToken != null) { + return true; + } + } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) { + return true; + } + if (oldWindow.activityToken == null) { + if (newWindow.activityToken != null) { + return true; + } + } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) { + return true; + } + if (!oldWindow.regionInScreen.equals(newWindow.regionInScreen)) { + return true; + } + if (oldWindow.childTokens != null && newWindow.childTokens != null + && !oldWindow.childTokens.equals(newWindow.childTokens)) { + return true; + } + if (!TextUtils.equals(oldWindow.title, newWindow.title)) { + return true; + } + if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) { + return true; + } + if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) { + return true; + } + if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) { + return true; + } + if (oldWindow.displayId != newWindow.displayId) { + return true; + } + return false; + } + + /** + * Clears all {@link AccessibilityWindowInfo}s and {@link WindowInfo}s. + */ + private void clearWindowsLocked() { + final List<WindowInfo> windows = Collections.emptyList(); + final int activeWindowId = mActiveWindowId; + // UserId is useless in updateWindowsLocked, when we update a empty window list. + // Just pass current userId here. + updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows); + // Do not reset mActiveWindowId here. mActiveWindowId will be clear after accessibility + // interaction connection removed. + mActiveWindowId = activeWindowId; + mWindows = null; + } + + /** + * Updates windows info according to specified userId and windows. + * + * @param userId The userId to update + * @param windows The windows to update + */ + private void updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows) { + if (mWindows == null) { + mWindows = new ArrayList<>(); + } + + final List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows); + final SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone(); + + mWindows.clear(); + mA11yWindowInfoById.clear(); + + for (int i = 0; i < mWindowInfoById.size(); i++) { + mWindowInfoById.valueAt(i).recycle(); + } + mWindowInfoById.clear(); + mHasWatchOutsideTouchWindow = false; + mFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + if (!mTouchInteractionInProgress) { + mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + } + + // If the active window goes away while the user is touch exploring we + // reset the active window id and wait for the next hover event from + // under the user's finger to determine which one is the new one. It + // is possible that the finger is not moving and the input system + // filters out such events. + boolean activeWindowGone = true; + + final int windowCount = windows.size(); + + // We'll clear accessibility focus if the window with focus is no longer visible to + // accessibility services + boolean shouldClearAccessibilityFocus = + mAccessibilityFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + if (windowCount > 0) { + for (int i = 0; i < windowCount; i++) { + final WindowInfo windowInfo = windows.get(i); + final AccessibilityWindowInfo window; + if (isTrackingWindowsLocked()) { + window = populateReportedWindowLocked(userId, windowInfo); + } else { + window = null; + } + if (window != null) { + + // Flip layers in list to be consistent with AccessibilityService#getWindows + window.setLayer(windowCount - 1 - window.getLayer()); + + final int windowId = window.getId(); + if (window.isFocused()) { + mFocusedWindowId = windowId; + if (!mTouchInteractionInProgress) { + mActiveWindowId = windowId; + window.setActive(true); + } else if (windowId == mActiveWindowId) { + activeWindowGone = false; + } + } + if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) { + mHasWatchOutsideTouchWindow = true; + } + mWindows.add(window); + mA11yWindowInfoById.put(windowId, window); + mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo)); + } + } + + if (mTouchInteractionInProgress && activeWindowGone) { + mActiveWindowId = mFocusedWindowId; + } + + // Focused window may change the active one, so set the + // active window once we decided which it is. + final int accessibilityWindowCount = mWindows.size(); + for (int i = 0; i < accessibilityWindowCount; i++) { + final AccessibilityWindowInfo window = mWindows.get(i); + if (window.getId() == mActiveWindowId) { + window.setActive(true); + } + if (window.getId() == mAccessibilityFocusedWindowId) { + window.setAccessibilityFocused(true); + shouldClearAccessibilityFocus = false; + } + } + } + + sendEventsForChangedWindowsLocked(oldWindowList, oldWindowsById); + + final int oldWindowCount = oldWindowList.size(); + for (int i = oldWindowCount - 1; i >= 0; i--) { + oldWindowList.remove(i).recycle(); + } + + if (shouldClearAccessibilityFocus) { + clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); + } + } + + private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows, + SparseArray<AccessibilityWindowInfo> oldWindowsById) { + List<AccessibilityEvent> events = new ArrayList<>(); + // Sends events for all removed windows. + final int oldWindowsCount = oldWindows.size(); + for (int i = 0; i < oldWindowsCount; i++) { + final AccessibilityWindowInfo window = oldWindows.get(i); + if (mA11yWindowInfoById.get(window.getId()) == null) { + events.add(AccessibilityEvent.obtainWindowsChangedEvent( + window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED)); + } + } + + // Looks for other changes. + final int newWindowCount = mWindows.size(); + for (int i = 0; i < newWindowCount; i++) { + final AccessibilityWindowInfo newWindow = mWindows.get(i); + final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId()); + if (oldWindow == null) { + events.add(AccessibilityEvent.obtainWindowsChangedEvent( + newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED)); + } else { + int changes = newWindow.differenceFrom(oldWindow); + if (changes != 0) { + events.add(AccessibilityEvent.obtainWindowsChangedEvent( + newWindow.getId(), changes)); + } + } + } + + final int numEvents = events.size(); + for (int i = 0; i < numEvents; i++) { + mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(events.get(i)); + } + } + + private AccessibilityWindowInfo populateReportedWindowLocked(int userId, + WindowInfo window) { + final int windowId = findWindowIdLocked(userId, window.token); + if (windowId < 0) { + return null; + } + + final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain(); + + reportedWindow.setId(windowId); + reportedWindow.setType(getTypeForWindowManagerWindowType(window.type)); + reportedWindow.setLayer(window.layer); + reportedWindow.setFocused(window.focused); + reportedWindow.setRegionInScreen(window.regionInScreen); + reportedWindow.setTitle(window.title); + reportedWindow.setAnchorId(window.accessibilityIdOfAnchor); + reportedWindow.setPictureInPicture(window.inPictureInPicture); + reportedWindow.setDisplayId(window.displayId); + + final int parentId = findWindowIdLocked(userId, window.parentToken); + if (parentId >= 0) { + reportedWindow.setParentId(parentId); + } + + if (window.childTokens != null) { + final int childCount = window.childTokens.size(); + for (int i = 0; i < childCount; i++) { + final IBinder childToken = window.childTokens.get(i); + final int childId = findWindowIdLocked(userId, childToken); + if (childId >= 0) { + reportedWindow.addChild(childId); + } + } + } + + return reportedWindow; + } + + private int getTypeForWindowManagerWindowType(int windowType) { + switch (windowType) { + case WindowManager.LayoutParams.TYPE_APPLICATION: + case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: + case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: + case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING: + case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: + case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL: + case WindowManager.LayoutParams.TYPE_BASE_APPLICATION: + case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION: + case WindowManager.LayoutParams.TYPE_PHONE: + case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: + case WindowManager.LayoutParams.TYPE_TOAST: + case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: { + return AccessibilityWindowInfo.TYPE_APPLICATION; + } + + case WindowManager.LayoutParams.TYPE_INPUT_METHOD: + case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: { + return AccessibilityWindowInfo.TYPE_INPUT_METHOD; + } + + case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: + case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: + case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: + case WindowManager.LayoutParams.TYPE_SEARCH_BAR: + case WindowManager.LayoutParams.TYPE_STATUS_BAR: + case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL: + case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL: + case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: + case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: + case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: + case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: + case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: + case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY: + case WindowManager.LayoutParams.TYPE_SCREENSHOT: { + return AccessibilityWindowInfo.TYPE_SYSTEM; + } + + case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { + return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER; + } + + case TYPE_ACCESSIBILITY_OVERLAY: { + return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY; + } + + default: { + return -1; + } + } + } + + /** + * Dumps all {@link AccessibilityWindowInfo}s here. + */ + void dumpLocked(FileDescriptor fd, final PrintWriter pw, String[] args) { + if (mWindows != null) { + final int windowCount = mWindows.size(); + for (int j = 0; j < windowCount; j++) { + if (j == 0) { + pw.append("Display["); + pw.append(Integer.toString(mDisplayId)); + pw.append("] : "); + pw.println(); + } + if (j > 0) { + pw.append(','); + pw.println(); + } + pw.append("Window["); + AccessibilityWindowInfo window = mWindows.get(j); + pw.append(window.toString()); + pw.append(']'); + } + pw.println(); + } + } + } /** * Interface to send {@link AccessibilityEvent}. */ public interface AccessibilityEventSender { /** - * Send {@link AccessibilityEvent} for current user. + * Sends {@link AccessibilityEvent} for current user. */ void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event); } @@ -171,166 +788,24 @@ public class AccessibilityWindowManager mAccessibilityEventSender = accessibilityEventSender; mSecurityPolicy = securityPolicy; mAccessibilityUserManager = accessibilityUserManager; - + mDisplayWindowsObserver = new DisplayWindowsObserver(Display.DEFAULT_DISPLAY); } /** - * Callbacks from window manager when there's an accessibility change in windows. - * - * @param forceSend Send the windows for accessibility even if they haven't changed. - * @param windows The windows of current display for accessibility. - */ - @Override - public void onWindowsForAccessibilityChanged(boolean forceSend, - @NonNull List<WindowInfo> windows) { - synchronized (mLock) { - if (DEBUG) { - Slog.i(LOG_TAG, "Windows changed: " + windows); - } - - if (shouldUpdateWindowsLocked(forceSend, windows)) { - cacheWindows(windows); - // Let the policy update the focused and active windows. - updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows); - // Someone may be waiting for the windows - advertise it. - mLock.notifyAll(); - } - } - } - - private boolean shouldUpdateWindowsLocked(boolean forceSend, - @NonNull List<WindowInfo> windows) { - if (forceSend) { - return true; - } - - final int windowCount = windows.size(); - // We computed the windows and if they changed notify the client. - if (mCachedWindowInfos.size() != windowCount) { - // Different size means something changed. - return true; - } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) { - // Since we always traverse windows from high to low layer - // the old and new windows at the same index should be the - // same, otherwise something changed. - for (int i = 0; i < windowCount; i++) { - WindowInfo oldWindow = mCachedWindowInfos.get(i); - WindowInfo newWindow = windows.get(i); - // We do not care for layer changes given the window - // order does not change. This brings no new information - // to the clients. - if (windowChangedNoLayer(oldWindow, newWindow)) { - return true; - } - } - } - - return false; - } - - private void cacheWindows(List<WindowInfo> windows) { - final int oldWindowCount = mCachedWindowInfos.size(); - for (int i = oldWindowCount - 1; i >= 0; i--) { - mCachedWindowInfos.remove(i).recycle(); - } - final int newWindowCount = windows.size(); - for (int i = 0; i < newWindowCount; i++) { - WindowInfo newWindow = windows.get(i); - mCachedWindowInfos.add(WindowInfo.obtain(newWindow)); - } - } - - private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) { - if (oldWindow == newWindow) { - return false; - } - if (oldWindow == null) { - return true; - } - if (newWindow == null) { - return true; - } - if (oldWindow.type != newWindow.type) { - return true; - } - if (oldWindow.focused != newWindow.focused) { - return true; - } - if (oldWindow.token == null) { - if (newWindow.token != null) { - return true; - } - } else if (!oldWindow.token.equals(newWindow.token)) { - return true; - } - if (oldWindow.parentToken == null) { - if (newWindow.parentToken != null) { - return true; - } - } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) { - return true; - } - if (oldWindow.activityToken == null) { - if (newWindow.activityToken != null) { - return true; - } - } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) { - return true; - } - if (!oldWindow.regionInScreen.equals(newWindow.regionInScreen)) { - return true; - } - if (oldWindow.childTokens != null && newWindow.childTokens != null - && !oldWindow.childTokens.equals(newWindow.childTokens)) { - return true; - } - if (!TextUtils.equals(oldWindow.title, newWindow.title)) { - return true; - } - if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) { - return true; - } - if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) { - return true; - } - if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) { - return true; - } - if (oldWindow.displayId != newWindow.displayId) { - return true; - } - return false; - } - - /** - * Start tracking windows changes from window manager. + * Starts tracking windows changes from window manager. */ public void startTrackingWindows() { synchronized (mLock) { - if (!mTrackingWindows) { - // Turn on the flag before setup the callback. - // In some cases, onWindowsForAccessibilityChanged will be called immediately in - // setWindowsForAccessibilityCallback. We'll lost windows if flag is false. - mTrackingWindows = true; - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY - mWindowManagerInternal.setWindowsForAccessibilityCallback(Display.DEFAULT_DISPLAY, - this); - } + mDisplayWindowsObserver.startTrackingWindowsLocked(); } } /** - * stop tracking windows changes from window manager, and clear all windows info. + * Stops tracking windows changes from window manager, and clear all windows info. */ public void stopTrackingWindows() { synchronized (mLock) { - if (mTrackingWindows) { - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY - mWindowManagerInternal.setWindowsForAccessibilityCallback(Display.DEFAULT_DISPLAY, - null); - mTrackingWindows = false; - clearWindowsLocked(); - } + mDisplayWindowsObserver.stopTrackingWindowsLocked(); } } @@ -340,127 +815,7 @@ public class AccessibilityWindowManager * @return true if windows changes tracking */ public boolean isTrackingWindowsLocked() { - return mTrackingWindows; - } - - /** - * Clears all {@link AccessibilityWindowInfo}s and {@link WindowInfo}s. - */ - private void clearWindowsLocked() { - final List<WindowInfo> windows = Collections.emptyList(); - final int activeWindowId = mActiveWindowId; - // userId is useless in updateWindowsLocked, when we update a empty window list. Just pass - // current userId here. - updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows); - // Do not reset mActiveWindowId here. mActiveWindowId will be clear after accessibility - // interaction connection removed. - mActiveWindowId = activeWindowId; - mWindows = null; - } - - /** - * Update windows info according to specified userId and windows. - * - * @param userId The userId to update - * @param windows The windows to update - */ - private void updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows) { - if (mWindows == null) { - mWindows = new ArrayList<>(); - } - - final List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows); - final SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone(); - - mWindows.clear(); - mA11yWindowInfoById.clear(); - - for (int i = 0; i < mWindowInfoById.size(); i++) { - mWindowInfoById.valueAt(i).recycle(); - } - mWindowInfoById.clear(); - mHasWatchOutsideTouchWindow = false; - - mFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; - if (!mTouchInteractionInProgress) { - mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; - } - - // If the active window goes away while the user is touch exploring we - // reset the active window id and wait for the next hover event from - // under the user's finger to determine which one is the new one. It - // is possible that the finger is not moving and the input system - // filters out such events. - boolean activeWindowGone = true; - - final int windowCount = windows.size(); - - // We'll clear accessibility focus if the window with focus is no longer visible to - // accessibility services - boolean shouldClearAccessibilityFocus = - mAccessibilityFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; - if (windowCount > 0) { - for (int i = 0; i < windowCount; i++) { - final WindowInfo windowInfo = windows.get(i); - final AccessibilityWindowInfo window; - if (isTrackingWindowsLocked()) { - window = populateReportedWindowLocked(userId, windowInfo); - } else { - window = null; - } - if (window != null) { - - // Flip layers in list to be consistent with AccessibilityService#getWindows - window.setLayer(windowCount - 1 - window.getLayer()); - - final int windowId = window.getId(); - if (window.isFocused()) { - mFocusedWindowId = windowId; - if (!mTouchInteractionInProgress) { - mActiveWindowId = windowId; - window.setActive(true); - } else if (windowId == mActiveWindowId) { - activeWindowGone = false; - } - } - if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) { - mHasWatchOutsideTouchWindow = true; - } - mWindows.add(window); - mA11yWindowInfoById.put(windowId, window); - mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo)); - } - } - - if (mTouchInteractionInProgress && activeWindowGone) { - mActiveWindowId = mFocusedWindowId; - } - - // Focused window may change the active one, so set the - // active window once we decided which it is. - final int accessibilityWindowCount = mWindows.size(); - for (int i = 0; i < accessibilityWindowCount; i++) { - final AccessibilityWindowInfo window = mWindows.get(i); - if (window.getId() == mActiveWindowId) { - window.setActive(true); - } - if (window.getId() == mAccessibilityFocusedWindowId) { - window.setAccessibilityFocused(true); - shouldClearAccessibilityFocus = false; - } - } - } - - sendEventsForChangedWindowsLocked(oldWindowList, oldWindowsById); - - final int oldWindowCount = oldWindowList.size(); - for (int i = oldWindowCount - 1; i >= 0; i--) { - oldWindowList.remove(i).recycle(); - } - - if (shouldClearAccessibilityFocus) { - clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); - } + return mDisplayWindowsObserver.isTrackingWindowsLocked(); } /** @@ -468,7 +823,7 @@ public class AccessibilityWindowManager */ @Nullable public List<AccessibilityWindowInfo> getWindowListLocked() { - return mWindows; + return mDisplayWindowsObserver.getWindowListLocked(); } /** @@ -494,7 +849,7 @@ public class AccessibilityWindowManager .resolveCallingUserIdEnforcingPermissionsLocked(userId); final int resolvedUid = UserHandle.getUid(resolvedUserId, UserHandle.getCallingAppId()); - // Make sure the reported package is one the caller has access to. + // Makes sure the reported package is one the caller has access to. packageName = mSecurityPolicy.resolveValidReportedPackageLocked( packageName, UserHandle.getCallingAppId(), resolvedUserId); @@ -576,7 +931,7 @@ public class AccessibilityWindowManager } /** - * Resolve a connection wrapper for a window id + * Resolves a connection wrapper for a window id. * * @param userId The user id for any user-specific windows * @param windowId The id of the window of interest @@ -672,7 +1027,7 @@ public class AccessibilityWindowManager } /** - * Return the userId that owns the given window token, {@link UserHandle#USER_NULL} + * Returns the userId that owns the given window token, {@link UserHandle#USER_NULL} * if not found. * * @param windowToken The winodw token @@ -703,42 +1058,6 @@ public class AccessibilityWindowManager return -1; } - private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows, - SparseArray<AccessibilityWindowInfo> oldWindowsById) { - List<AccessibilityEvent> events = new ArrayList<>(); - // Send events for all removed windows - final int oldWindowsCount = oldWindows.size(); - for (int i = 0; i < oldWindowsCount; i++) { - final AccessibilityWindowInfo window = oldWindows.get(i); - if (mA11yWindowInfoById.get(window.getId()) == null) { - events.add(AccessibilityEvent.obtainWindowsChangedEvent( - window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED)); - } - } - - // Look for other changes - final int newWindowCount = mWindows.size(); - for (int i = 0; i < newWindowCount; i++) { - final AccessibilityWindowInfo newWindow = mWindows.get(i); - final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId()); - if (oldWindow == null) { - events.add(AccessibilityEvent.obtainWindowsChangedEvent( - newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED)); - } else { - int changes = newWindow.differenceFrom(oldWindow); - if (changes != 0) { - events.add(AccessibilityEvent.obtainWindowsChangedEvent( - newWindow.getId(), changes)); - } - } - } - - final int numEvents = events.size(); - for (int i = 0; i < numEvents; i++) { - mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(events.get(i)); - } - } - /** * Computes partial interactive region of given windowId. * @@ -748,38 +1067,8 @@ public class AccessibilityWindowManager */ public boolean computePartialInteractiveRegionForWindowLocked(int windowId, @NonNull Region outRegion) { - if (mWindows == null) { - return false; - } - - // Windows are ordered in z order so start from the bottom and find - // the window of interest. After that all windows that cover it should - // be subtracted from the resulting region. Note that for accessibility - // we are returning only interactive windows. - Region windowInteractiveRegion = null; - boolean windowInteractiveRegionChanged = false; - - final int windowCount = mWindows.size(); - final Region currentWindowRegions = new Region(); - for (int i = windowCount - 1; i >= 0; i--) { - AccessibilityWindowInfo currentWindow = mWindows.get(i); - if (windowInteractiveRegion == null) { - if (currentWindow.getId() == windowId) { - currentWindow.getRegionInScreen(currentWindowRegions); - outRegion.set(currentWindowRegions); - windowInteractiveRegion = outRegion; - continue; - } - } else if (currentWindow.getType() - != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) { - currentWindow.getRegionInScreen(currentWindowRegions); - if (windowInteractiveRegion.op(currentWindowRegions, Region.Op.DIFFERENCE)) { - windowInteractiveRegionChanged = true; - } - } - } - - return windowInteractiveRegionChanged; + return mDisplayWindowsObserver.computePartialInteractiveRegionForWindowLocked(windowId, + outRegion); } /** @@ -846,7 +1135,7 @@ public class AccessibilityWindowManager mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; } // Clear the window with focus if it no longer has focus and we aren't - // just moving focus from one view to the other in the same window + // just moving focus from one view to the other in the same window. if ((mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) && (mAccessibilityFocusedWindowId == windowId) && (eventAction != AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)) { @@ -904,7 +1193,7 @@ public class AccessibilityWindowManager } /** - * Get the id of the current active window. + * Gets the id of the current active window. * * @return The userId */ @@ -923,20 +1212,7 @@ public class AccessibilityWindowManager mActiveWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)); mActiveWindowId = windowId; - if (mWindows != null) { - final int windowCount = mWindows.size(); - for (int i = 0; i < windowCount; i++) { - AccessibilityWindowInfo window = mWindows.get(i); - if (window.getId() == windowId) { - window.setActive(true); - mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( - AccessibilityEvent.obtainWindowsChangedEvent(windowId, - AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)); - } else { - window.setActive(false); - } - } - } + mDisplayWindowsObserver.setActiveWindowLocked(windowId); } } @@ -948,21 +1224,7 @@ public class AccessibilityWindowManager WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); mAccessibilityFocusedWindowId = windowId; - if (mWindows != null) { - final int windowCount = mWindows.size(); - for (int i = 0; i < windowCount; i++) { - AccessibilityWindowInfo window = mWindows.get(i); - if (window.getId() == windowId) { - window.setAccessibilityFocused(true); - mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( - AccessibilityEvent.obtainWindowsChangedEvent( - windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); - - } else { - window.setAccessibilityFocused(false); - } - } - } + mDisplayWindowsObserver.setAccessibilityFocusedWindowLocked(windowId); } } @@ -973,8 +1235,8 @@ public class AccessibilityWindowManager * @return The accessibility window info */ @Nullable - public AccessibilityWindowInfo findA11yWindowInfoById(int windowId) { - return mA11yWindowInfoById.get(windowId); + public AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) { + return mDisplayWindowsObserver.findA11yWindowInfoByIdLocked(windowId); } /** @@ -984,8 +1246,8 @@ public class AccessibilityWindowManager * @return The window info */ @Nullable - public WindowInfo findWindowInfoById(int windowId) { - return mWindowInfoById.get(windowId); + public WindowInfo findWindowInfoByIdLocked(int windowId) { + return mDisplayWindowsObserver.findWindowInfoByIdLocked(windowId); } /** @@ -1010,21 +1272,12 @@ public class AccessibilityWindowManager * @return PIP accessibility window info */ @Nullable - public AccessibilityWindowInfo getPictureInPictureWindow() { - if (mWindows != null) { - final int windowCount = mWindows.size(); - for (int i = 0; i < windowCount; i++) { - final AccessibilityWindowInfo window = mWindows.get(i); - if (window.isInPictureInPictureMode()) { - return window; - } - } - } - return null; + public AccessibilityWindowInfo getPictureInPictureWindowLocked() { + return mDisplayWindowsObserver.getPictureInPictureWindowLocked(); } /** - * Set an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture + * Sets an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture * window. */ public void setPictureInPictureActionReplacingConnection( @@ -1060,7 +1313,8 @@ public class AccessibilityWindowManager final List<Integer> outsideWindowsIds; final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>(); synchronized (mLock) { - outsideWindowsIds = getWatchOutsideTouchWindowIdLocked(targetWindowId); + outsideWindowsIds = + mDisplayWindowsObserver.getWatchOutsideTouchWindowIdLocked(targetWindowId); for (int i = 0; i < outsideWindowsIds.size(); i++) { connectionList.add(getConnectionLocked(userId, outsideWindowsIds.get(i))); } @@ -1079,22 +1333,6 @@ public class AccessibilityWindowManager } } - private List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) { - final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId); - if (targetWindow != null && mHasWatchOutsideTouchWindow) { - final List<Integer> outsideWindowsId = new ArrayList<>(); - for (int i = 0; i < mWindowInfoById.size(); i++) { - final WindowInfo window = mWindowInfoById.valueAt(i); - if (window != null && window.layer < targetWindow.layer - && window.hasFlagWatchOutsideTouch) { - outsideWindowsId.add(mWindowInfoById.keyAt(i)); - } - } - return outsideWindowsId; - } - return Collections.emptyList(); - } - /** * Gets current input focused window token from window manager, and returns its windowId. * @@ -1108,96 +1346,6 @@ public class AccessibilityWindowManager } } - private AccessibilityWindowInfo populateReportedWindowLocked(int userId, WindowInfo window) { - final int windowId = findWindowIdLocked(userId, window.token); - if (windowId < 0) { - return null; - } - - final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain(); - - reportedWindow.setId(windowId); - reportedWindow.setType(getTypeForWindowManagerWindowType(window.type)); - reportedWindow.setLayer(window.layer); - reportedWindow.setFocused(window.focused); - reportedWindow.setRegionInScreen(window.regionInScreen); - reportedWindow.setTitle(window.title); - reportedWindow.setAnchorId(window.accessibilityIdOfAnchor); - reportedWindow.setPictureInPicture(window.inPictureInPicture); - reportedWindow.setDisplayId(window.displayId); - - final int parentId = findWindowIdLocked(userId, window.parentToken); - if (parentId >= 0) { - reportedWindow.setParentId(parentId); - } - - if (window.childTokens != null) { - final int childCount = window.childTokens.size(); - for (int i = 0; i < childCount; i++) { - final IBinder childToken = window.childTokens.get(i); - final int childId = findWindowIdLocked(userId, childToken); - if (childId >= 0) { - reportedWindow.addChild(childId); - } - } - } - - return reportedWindow; - } - - private int getTypeForWindowManagerWindowType(int windowType) { - switch (windowType) { - case WindowManager.LayoutParams.TYPE_APPLICATION: - case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: - case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: - case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING: - case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: - case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL: - case WindowManager.LayoutParams.TYPE_BASE_APPLICATION: - case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION: - case WindowManager.LayoutParams.TYPE_PHONE: - case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: - case WindowManager.LayoutParams.TYPE_TOAST: - case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: { - return AccessibilityWindowInfo.TYPE_APPLICATION; - } - - case WindowManager.LayoutParams.TYPE_INPUT_METHOD: - case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: { - return AccessibilityWindowInfo.TYPE_INPUT_METHOD; - } - - case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: - case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: - case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: - case WindowManager.LayoutParams.TYPE_SEARCH_BAR: - case WindowManager.LayoutParams.TYPE_STATUS_BAR: - case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL: - case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL: - case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: - case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: - case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: - case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: - case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: - case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY: - case WindowManager.LayoutParams.TYPE_SCREENSHOT: { - return AccessibilityWindowInfo.TYPE_SYSTEM; - } - - case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { - return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER; - } - - case TYPE_ACCESSIBILITY_OVERLAY: { - return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY; - } - - default: { - return -1; - } - } - } - private boolean isValidUserForInteractionConnectionsLocked(int userId) { return mInteractionConnections.indexOfKey(userId) >= 0; } @@ -1251,22 +1399,9 @@ public class AccessibilityWindowManager } /** - * Dump all {@link AccessibilityWindowInfo}s here. + * Dumps all {@link AccessibilityWindowInfo}s here. */ public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { - if (mWindows != null) { - final int windowCount = mWindows.size(); - for (int j = 0; j < windowCount; j++) { - if (j > 0) { - pw.append(','); - pw.println(); - } - pw.append("Window["); - AccessibilityWindowInfo window = mWindows.get(j); - pw.append(window.toString()); - pw.append(']'); - } - pw.println(); - } + mDisplayWindowsObserver.dumpLocked(fd, pw, args); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 0dd719994de2..a0900b68111e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -528,12 +528,12 @@ final class ActivityManagerShellCommand extends ShellCommand { options.setLockTaskEnabled(true); } if (mWaitOption) { - result = mInternal.startActivityAndWait(null, null, intent, mimeType, + result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, intent, mimeType, null, null, 0, mStartFlags, profilerInfo, options != null ? options.toBundle() : null, mUserId); res = result.result; } else { - res = mInternal.startActivityAsUser(null, null, intent, mimeType, + res = mInternal.startActivityAsUser(null, SHELL_PACKAGE_NAME, intent, mimeType, null, null, 0, mStartFlags, profilerInfo, options != null ? options.toBundle() : null, mUserId); } diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 4957eed21c70..73d160d8c444 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -772,7 +772,6 @@ public class Tethering extends BaseNetworkObserver { case WifiManager.WIFI_AP_STATE_FAILED: default: disableWifiIpServingLocked(ifname, curState); - mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_WIFI); break; } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 09e93759196f..f20003a2ee04 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2551,7 +2551,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis); if (mStatusBar != null) { mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition, - needsToShowImeSwitcher); + needsToShowImeSwitcher, false /*isMultiClientImeEnabled*/); } final InputMethodInfo imi = mMethodMap.get(mCurMethodId); if (imi != null && needsToShowImeSwitcher) { diff --git a/core/java/android/view/inputmethod/InputMethodSystemProperty.java b/services/core/java/com/android/server/inputmethod/InputMethodSystemProperty.java index e20c2fdc8074..a6a68934accd 100644 --- a/core/java/android/view/inputmethod/InputMethodSystemProperty.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodSystemProperty.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.view.inputmethod; +package com.android.server.inputmethod; import android.annotation.Nullable; import android.content.ComponentName; @@ -23,8 +23,6 @@ import android.os.SystemProperties; /** * Various (pseudo) constants about IME behaviors. - * - * @hide */ public class InputMethodSystemProperty { /** @@ -58,23 +56,12 @@ public class InputMethodSystemProperty { /** * {@link ComponentName} of multi-client IME to be used. - * - * <p>TODO: Move this back to MultiClientInputMethodManagerService once - * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p> - * - * @hide */ @Nullable - public static final ComponentName sMultiClientImeComponentName = - getMultiClientImeComponentName(); + static final ComponentName sMultiClientImeComponentName = getMultiClientImeComponentName(); /** * {@code true} when multi-client IME is enabled. - * - * <p>TODO: Move this back to MultiClientInputMethodManagerService once - * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p> - * - * @hide */ public static final boolean MULTI_CLIENT_IME_ENABLED = (sMultiClientImeComponentName != null); } diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 3dd730471dca..02e29e0b2ab5 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -67,7 +67,6 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; -import android.view.inputmethod.InputMethodSystemProperty; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 984f22f01465..c7124314cae0 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -281,20 +281,7 @@ public class BackgroundDexOptService extends JobService { mAbortIdleOptimization.set(false); long lowStorageThreshold = getLowStorageThreshold(context); - // Optimize primary apks. - int result = optimizePackages(pm, pkgs, lowStorageThreshold, - /*isForPrimaryDex=*/ true); - if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { - return result; - } - if (supportSecondaryDex()) { - result = reconcileSecondaryDexFiles(pm.getDexManager()); - if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { - return result; - } - result = optimizePackages(pm, pkgs, lowStorageThreshold, - /*isForPrimaryDex=*/ false); - } + int result = idleOptimizePackages(pm, pkgs, lowStorageThreshold); return result; } @@ -342,11 +329,20 @@ public class BackgroundDexOptService extends JobService { return 0; } - private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs, - long lowStorageThreshold, boolean isForPrimaryDex) { + private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs, + long lowStorageThreshold) { ArraySet<String> updatedPackages = new ArraySet<>(); try { + final boolean supportSecondaryDex = supportSecondaryDex(); + + if (supportSecondaryDex) { + int result = reconcileSecondaryDexFiles(pm.getDexManager()); + if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { + return result; + } + } + // Only downgrade apps when space is low on device. // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean // up disk before user hits the actual lowStorageThreshold. @@ -359,43 +355,61 @@ public class BackgroundDexOptService extends JobService { pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis); Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages)); - for (String pkg : unusedPackages) { - int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1); - if (abortCode != OPTIMIZE_CONTINUE) { - // Should be aborted by the scheduler. - return abortCode; - } - if (downgradePackage(pm, pkg, isForPrimaryDex)) { - updatedPackages.add(pkg); + if (!unusedPackages.isEmpty()) { + for (String pkg : unusedPackages) { + int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1); + if (abortCode != OPTIMIZE_CONTINUE) { + // Should be aborted by the scheduler. + return abortCode; + } + if (downgradePackage(pm, pkg, /*isForPrimaryDex*/ true)) { + updatedPackages.add(pkg); + } + if (supportSecondaryDex) { + downgradePackage(pm, pkg, /*isForPrimaryDex*/ false); + } } - } - if (!unusedPackages.isEmpty()) { pkgs = new ArraySet<>(pkgs); pkgs.removeAll(unusedPackages); } } - for (String pkg : pkgs) { - int abortCode = abortIdleOptimizations(lowStorageThreshold); - if (abortCode != OPTIMIZE_CONTINUE) { - // Either aborted by the scheduler or no space left. - return abortCode; - } + int primaryResult = optimizePackages(pm, pkgs, lowStorageThreshold, + /*isForPrimaryDex*/ true, updatedPackages); + if (primaryResult != OPTIMIZE_PROCESSED) { + return primaryResult; + } - boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex); - if (dexOptPerformed) { - updatedPackages.add(pkg); - } + if (!supportSecondaryDex) { + return OPTIMIZE_PROCESSED; } - return OPTIMIZE_PROCESSED; + int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold, + /*isForPrimaryDex*/ false, updatedPackages); + return secondaryResult; } finally { // Always let the pinner service know about changes. notifyPinService(updatedPackages); } } + private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs, + long lowStorageThreshold, boolean isForPrimaryDex, ArraySet<String> updatedPackages) { + for (String pkg : pkgs) { + int abortCode = abortIdleOptimizations(lowStorageThreshold); + if (abortCode != OPTIMIZE_CONTINUE) { + // Either aborted by the scheduler or no space left. + return abortCode; + } + + boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex); + if (dexOptPerformed) { + updatedPackages.add(pkg); + } + } + return OPTIMIZE_PROCESSED; + } /** * Try to downgrade the package to a smaller compilation filter. diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java index a374e1484b28..231168e9c660 100644 --- a/services/core/java/com/android/server/pm/ProtectedPackages.java +++ b/services/core/java/com/android/server/pm/ProtectedPackages.java @@ -92,6 +92,9 @@ public class ProtectedPackages { if (mDeviceOwnerUserId == userId) { return mDeviceOwnerPackage; } + if (mProfileOwnerPackages == null) { + return null; + } return mProfileOwnerPackages.get(userId); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 828f79007b95..d67048fe548d 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -841,7 +841,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void setImeWindowStatus(int displayId, final IBinder token, final int vis, - final int backDisposition, final boolean showImeSwitcher) { + final int backDisposition, final boolean showImeSwitcher, + boolean isMultiClientImeEnabled) { enforceStatusBar(); if (SPEW) { @@ -858,7 +859,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D if (mBar == null) return; try { mBar.setImeWindowStatus( - displayId, token, vis, backDisposition, showImeSwitcher); + displayId, token, vis, backDisposition, showImeSwitcher, + isMultiClientImeEnabled); } catch (RemoteException ex) { } }); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index f231af9913f8..20ccfa81a6ac 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -225,7 +225,6 @@ import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationDefinition; import android.view.WindowManager; -import android.view.inputmethod.InputMethodSystemProperty; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -262,6 +261,7 @@ import com.android.server.am.PendingIntentRecord; import com.android.server.am.UserState; import com.android.server.appop.AppOpsService; import com.android.server.firewall.IntentFirewall; +import com.android.server.inputmethod.InputMethodSystemProperty; import com.android.server.pm.UserManagerService; import com.android.server.policy.PermissionPolicyInternal; import com.android.server.uri.UriGrantsManagerInternal; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 26e37d6e0d97..8fb23a41d16a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2006,6 +2006,7 @@ public class WindowManagerService extends IWindowManager.Stub int attrChanges = 0; int flagChanges = 0; + int privateFlagChanges = 0; if (attrs != null) { displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid); // if they don't have the permission, mask out the status bar bits @@ -2033,7 +2034,8 @@ public class WindowManagerService extends IWindowManager.Stub attrs.height = win.mAttrs.height; } - flagChanges = win.mAttrs.flags ^= attrs.flags; + flagChanges = win.mAttrs.flags ^ attrs.flags; + privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags; attrChanges = win.mAttrs.copyFrom(attrs); if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) { @@ -2050,7 +2052,7 @@ public class WindowManagerService extends IWindowManager.Stub win.getDisplayContent().getDisplayId()); } - if ((flagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) { + if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) { updateNonSystemOverlayWindowsVisibilityIfNeeded( win, win.mWinAnimator.getShown()); } @@ -7543,7 +7545,7 @@ public class WindowManagerService extends IWindowManager.Stub return; } final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty(); - if (surfaceShown) { + if (surfaceShown && win.hideNonSystemOverlayWindowsWhenVisible()) { if (!mHidingNonSystemOverlayWindows.contains(win)) { mHidingNonSystemOverlayWindows.add(win); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 16007d775283..6e0d83433559 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -67,7 +67,6 @@ import android.util.EventLog; import android.util.Slog; import android.view.WindowManager; import android.view.contentcapture.ContentCaptureManager; -import android.view.inputmethod.InputMethodSystemProperty; import com.android.internal.R; import com.android.internal.logging.MetricsLogger; @@ -101,6 +100,7 @@ import com.android.server.hdmi.HdmiControlService; import com.android.server.incident.IncidentCompanionService; import com.android.server.input.InputManagerService; import com.android.server.inputmethod.InputMethodManagerService; +import com.android.server.inputmethod.InputMethodSystemProperty; import com.android.server.inputmethod.MultiClientInputMethodManagerService; import com.android.server.lights.LightsService; import com.android.server.media.MediaResourceMonitorService; diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 328e8f41f5e2..1c88c40c3e2b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -400,22 +400,7 @@ public class ConnectivityControllerTest { } @Test - public void testEvaluateStateLocked_HeartbeatsOn() { - mConstants.USE_HEARTBEATS = true; - final ConnectivityController controller = new ConnectivityController(mService); - final JobStatus red = createJobStatus(createJob() - .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED), UID_RED); - - controller.evaluateStateLocked(red); - assertFalse(controller.isStandbyExceptionRequestedLocked(UID_RED)); - verify(mNetPolicyManagerInternal, never()) - .setAppIdleWhitelist(eq(UID_RED), anyBoolean()); - } - - @Test public void testEvaluateStateLocked_JobWithoutConnectivity() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = new ConnectivityController(mService); final JobStatus red = createJobStatus(createJob().setMinimumLatency(1)); @@ -427,7 +412,6 @@ public class ConnectivityControllerTest { @Test public void testEvaluateStateLocked_JobWouldBeReady() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = spy(new ConnectivityController(mService)); doReturn(true).when(controller).wouldBeReadyWithConnectivityLocked(any()); final JobStatus red = createJobStatus(createJob() @@ -466,7 +450,6 @@ public class ConnectivityControllerTest { @Test public void testEvaluateStateLocked_JobWouldNotBeReady() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = spy(new ConnectivityController(mService)); doReturn(false).when(controller).wouldBeReadyWithConnectivityLocked(any()); final JobStatus red = createJobStatus(createJob() @@ -502,7 +485,6 @@ public class ConnectivityControllerTest { @Test public void testReevaluateStateLocked() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = spy(new ConnectivityController(mService)); final JobStatus redOne = createJobStatus(createJob(1) .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0) @@ -625,7 +607,7 @@ public class ConnectivityControllerTest { private static JobStatus createJobStatus(JobInfo.Builder job, int uid, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) { - return new JobStatus(job.build(), uid, null, -1, 0, 0, null, + return new JobStatus(job.build(), uid, null, -1, 0, null, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0); } } 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 94e02d3b2648..64da6f6b8590 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 @@ -573,7 +573,7 @@ public class JobStatusTest { long latestRunTimeElapsedMillis) { final JobInfo job = new JobInfo.Builder(101, new ComponentName("foo", "bar")) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build(); - return new JobStatus(job, 0, null, -1, 0, 0, null, earliestRunTimeElapsedMillis, + return new JobStatus(job, 0, null, -1, 0, null, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0); } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index 2d702312a62b..8863d5abeca3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -107,7 +107,6 @@ public class QuotaControllerTest { private static final int SOURCE_USER_ID = 0; private BroadcastReceiver mChargingReceiver; - private Constants mJsConstants; private QuotaController mQuotaController; private QuotaController.QcConstants mQcConstants; private int mSourceUid; @@ -134,14 +133,11 @@ public class QuotaControllerTest { .strictness(Strictness.LENIENT) .mockStatic(LocalServices.class) .startMocking(); - // Make sure constants turn on QuotaController. - mJsConstants = new Constants(); - mJsConstants.USE_HEARTBEATS = false; // Called in StateController constructor. when(mJobSchedulerService.getTestableContext()).thenReturn(mContext); when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService); - when(mJobSchedulerService.getConstants()).thenReturn(mJsConstants); + when(mJobSchedulerService.getConstants()).thenReturn(mock(Constants.class)); // Called in QuotaController constructor. IActivityManager activityManager = ActivityManager.getService(); spyOn(activityManager); @@ -1809,30 +1805,6 @@ public class QuotaControllerTest { .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } - /** Tests that QuotaController doesn't throttle if throttling is turned off. */ - @Test - public void testThrottleToggling() throws Exception { - setDischarging(); - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession( - JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS, - 10 * MINUTE_IN_MILLIS, 4)); - JobStatus jobStatus = createJobStatus("testThrottleToggling", 1); - setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - - mJsConstants.USE_HEARTBEATS = true; - mQuotaController.onConstantsUpdatedLocked(); - Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background. - assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - - mJsConstants.USE_HEARTBEATS = false; - mQuotaController.onConstantsUpdatedLocked(); - Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background. - assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - } - @Test public void testConstantsUpdating_ValidValues() { mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS; 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 a4267b86b359..1084d625f8a3 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java @@ -179,9 +179,9 @@ public class AbstractAccessibilityServiceConnectionTest { addA11yWindowInfo(mA11yWindowInfos, WINDOWID, false); addA11yWindowInfo(mA11yWindowInfos, PIP_WINDOWID, true); when(mMockA11yWindowManager.getWindowListLocked()).thenReturn(mA11yWindowInfos); - when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID)) + when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID)) .thenReturn(mA11yWindowInfos.get(0)); - when(mMockA11yWindowManager.findA11yWindowInfoById(PIP_WINDOWID)) + when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(PIP_WINDOWID)) .thenReturn(mA11yWindowInfos.get(1)); final RemoteAccessibilityConnection conn = getRemoteA11yConnection( WINDOWID, mMockIA11yInteractionConnection, PACKAGE_NAME1); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java index bb35776ffcd6..04ac7fe91008 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java @@ -166,7 +166,7 @@ public class AccessibilitySecurityPolicyTest { public void canDispatchAccessibilityEvent_otherEvents_windowIdExist_returnTrue() { when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM)) .thenReturn(WINDOWID2); - when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID)) + when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID)) .thenReturn(AccessibilityWindowInfo.obtain()); for (int i = 0; i < OTHER_EVENTS.length; i++) { final AccessibilityEvent event = AccessibilityEvent.obtain(OTHER_EVENTS[i]); @@ -287,7 +287,7 @@ public class AccessibilitySecurityPolicyTest { .thenReturn(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT); when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM)) .thenReturn(WINDOWID2); - when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID)) + when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID)) .thenReturn(AccessibilityWindowInfo.obtain()); assertTrue(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(UserHandle.USER_SYSTEM, diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java index 7e64cafaf7a2..7887d5b76bca 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java @@ -34,6 +34,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -53,6 +54,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection; import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection; import com.android.server.wm.WindowManagerInternal; +import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; @@ -75,9 +77,12 @@ public class AccessibilityWindowManagerTest { private static final boolean FORCE_SEND = true; private static final boolean SEND_ON_WINDOW_CHANGES = false; private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM; + // TO-DO [Multi-Display] : change the display count to 2 + private static final int DISPLAY_COUNT = 1; private static final int NUM_GLOBAL_WINDOWS = 4; private static final int NUM_APP_WINDOWS = 4; - private static final int NUM_OF_WINDOWS = NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS; + private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS) + * DISPLAY_COUNT; private static final int DEFAULT_FOCUSED_INDEX = 1; private static final int SCREEN_WIDTH = 1080; private static final int SCREEN_HEIGHT = 1920; @@ -86,7 +91,13 @@ public class AccessibilityWindowManagerTest { // List of window token, mapping from windowId -> window token. private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>(); - private final ArrayList<WindowInfo> mWindowInfos = new ArrayList<>(); + // List of window info lists, mapping from displayId -> window info lists. + private final SparseArray<ArrayList<WindowInfo>> mWindowInfos = + new SparseArray<>(); + // List of callback, mapping from displayId -> callback. + private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows = + new SparseArray<>(); + private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null); @Mock private WindowManagerInternal mMockWindowManagerInternal; @@ -109,29 +120,14 @@ public class AccessibilityWindowManagerTest { mMockA11ySecurityPolicy, mMockA11yUserManager); - // Add RemoteAccessibilityConnection into AccessibilityWindowManager, and copy - // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos - // for the test. - int layer = 0; - for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) { - final IWindow token = addAccessibilityInteractionConnection(true); - addWindowInfo(token, layer++); - - } - for (int i = 0; i < NUM_APP_WINDOWS; i++) { - final IWindow token = addAccessibilityInteractionConnection(false); - addWindowInfo(token, layer++); + for (int i = 0; i < DISPLAY_COUNT; i++) { + when(mMockWindowManagerInternal.setWindowsForAccessibilityCallback(eq(i), any())) + .thenReturn(true); + startTrackingPerDisplay(i); } - // setup default focus - mWindowInfos.get(DEFAULT_FOCUSED_INDEX).focused = true; - // Turn on windows tracking, and update window info - mA11yWindowManager.startTrackingWindows(); - mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos); - assertEquals(mA11yWindowManager.getWindowListLocked().size(), - mWindowInfos.size()); // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged. - // Reset it for mockito verify of further test case. + // Resets it for mockito verify of further test case. Mockito.reset(mMockA11yEventSender); } @@ -142,11 +138,12 @@ public class AccessibilityWindowManagerTest { @Test public void startTrackingWindows_shouldEnableWindowManagerCallback() { - // AccessibilityWindowManager#startTrackingWindows already invoked in setup + // AccessibilityWindowManager#startTrackingWindows already invoked in setup. assertTrue(mA11yWindowManager.isTrackingWindowsLocked()); - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY + final WindowsForAccessibilityCallback callbacks = + mCallbackOfWindows.get(Display.DEFAULT_DISPLAY); verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback( - eq(Display.DEFAULT_DISPLAY), any()); + eq(Display.DEFAULT_DISPLAY), eq(callbacks)); } @Test @@ -156,9 +153,9 @@ public class AccessibilityWindowManagerTest { mA11yWindowManager.stopTrackingWindows(); assertFalse(mA11yWindowManager.isTrackingWindowsLocked()); - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback( - eq(Display.DEFAULT_DISPLAY), any()); + eq(Display.DEFAULT_DISPLAY), isNull()); + } @Test @@ -177,87 +174,102 @@ public class AccessibilityWindowManagerTest { @Test public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() { final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); - WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX); + WindowInfo focusedWindowInfo = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX); assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked( USER_SYSTEM_ID, focusedWindowInfo.token)); focusedWindowInfo.focused = false; - focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1); + focusedWindowInfo = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1); focusedWindowInfo.focused = true; mA11yWindowManager.onTouchInteractionStart(); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID)); } @Test public void onWindowsChanged_shouldReportCorrectLayer() { - // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup - List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup. + List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); for (int i = 0; i < a11yWindows.size(); i++) { final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i); - final WindowInfo windowInfo = mWindowInfos.get(i); - assertThat(mWindowInfos.size() - windowInfo.layer - 1, + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i); + assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1, is(a11yWindow.getLayer())); } } @Test public void onWindowsChanged_shouldReportCorrectOrder() { - // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup - List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup. + List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); for (int i = 0; i < a11yWindows.size(); i++) { final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i); final IBinder windowToken = mA11yWindowManager .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId()); - final WindowInfo windowInfo = mWindowInfos.get(i); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i); assertThat(windowToken, is(windowInfo.token)); } } @Test public void onWindowsChangedAndForceSend_shouldUpdateWindows() { - final WindowInfo windowInfo = mWindowInfos.get(0); - final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer(); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + final int correctLayer = + mA11yWindowManager.getWindowListLocked().get(0).getLayer(); windowInfo.layer += 1; - mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos); - assertNotEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer()); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND); + assertNotEquals(correctLayer, + mA11yWindowManager.getWindowListLocked().get(0).getLayer()); } @Test public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() { - final WindowInfo windowInfo = mWindowInfos.get(0); - final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer(); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + final int correctLayer = + mA11yWindowManager.getWindowListLocked().get(0).getLayer(); windowInfo.layer += 1; - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); - assertEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer()); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + assertEquals(correctLayer, + mA11yWindowManager.getWindowListLocked().get(0).getLayer()); } @Test public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows() throws RemoteException { - final AccessibilityWindowInfo oldWindow = mA11yWindowManager.getWindowListLocked().get(0); - final IWindow token = addAccessibilityInteractionConnection(true); + final AccessibilityWindowInfo oldWindow = + mA11yWindowManager.getWindowListLocked().get(0); + final IWindow token = + addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, true); final WindowInfo windowInfo = WindowInfo.obtain(); windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION; windowInfo.token = token.asBinder(); windowInfo.layer = 0; windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - mWindowInfos.set(0, windowInfo); + mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); - assertNotEquals(oldWindow, mA11yWindowManager.getWindowListLocked().get(0)); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + assertNotEquals(oldWindow, + mA11yWindowManager.getWindowListLocked().get(0)); } @Test public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() { - final WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX); - final WindowInfo windowInfo = mWindowInfos.get(0); + final WindowInfo focusedWindowInfo = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); focusedWindowInfo.focused = false; windowInfo.focused = true; - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); assertTrue(mA11yWindowManager.getWindowListLocked().get(0).isFocused()); } @@ -288,7 +300,8 @@ public class AccessibilityWindowManagerTest { @Test public void getWindowTokenForUserAndWindowId_shouldNotNull() { - final List<AccessibilityWindowInfo> windows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> windows = + mA11yWindowManager.getWindowListLocked(); for (int i = 0; i < windows.size(); i++) { final int windowId = windows.get(i).getId(); @@ -299,7 +312,8 @@ public class AccessibilityWindowManagerTest { @Test public void findWindowId() { - final List<AccessibilityWindowInfo> windows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> windows = + mA11yWindowManager.getWindowListLocked(); for (int i = 0; i < windows.size(); i++) { final int windowId = windows.get(i).getId(); final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked( @@ -313,13 +327,15 @@ public class AccessibilityWindowManagerTest { @Test public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() { // Updates top 2 z-order WindowInfo are whole visible. - WindowInfo windowInfo = mWindowInfos.get(0); + WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2); - windowInfo = mWindowInfos.get(1); - windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1); + windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2, + SCREEN_WIDTH, SCREEN_HEIGHT); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); - final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); final Region outBounds = new Region(); int windowId = a11yWindows.get(0).getId(); @@ -336,12 +352,13 @@ public class AccessibilityWindowManagerTest { @Test public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() { - // Updates z-order #1 WindowInfo is half visible - WindowInfo windowInfo = mWindowInfos.get(0); + // Updates z-order #1 WindowInfo is half visible. + WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); - final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); final Region outBounds = new Region(); int windowId = a11yWindows.get(1).getId(); @@ -353,7 +370,8 @@ public class AccessibilityWindowManagerTest { @Test public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() { // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible. - final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); final Region outBounds = new Region(); int windowId = a11yWindows.get(1).getId(); @@ -366,11 +384,12 @@ public class AccessibilityWindowManagerTest { // Updates z-order #0 WindowInfo to have two interact-able areas. Region region = new Region(0, 0, SCREEN_WIDTH, 200); region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION); - WindowInfo windowInfo = mWindowInfos.get(0); + WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); windowInfo.regionInScreen.set(region); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); - final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); final Region outBounds = new Region(); int windowId = a11yWindows.get(1).getId(); @@ -382,7 +401,8 @@ public class AccessibilityWindowManagerTest { @Test public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() { - final IBinder eventWindowToken = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1).token; + final IBinder eventWindowToken = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token; final int eventWindowId = mA11yWindowManager.findWindowIdLocked( USER_SYSTEM_ID, eventWindowToken); when(mMockWindowManagerInternal.getFocusedWindowToken()) @@ -402,7 +422,8 @@ public class AccessibilityWindowManagerTest { @Test public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() { - final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1); + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX + 1); final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); assertThat(currentActiveWindowId, is(not(eventWindowId))); @@ -428,7 +449,8 @@ public class AccessibilityWindowManagerTest { @Test public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() { - final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX); + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX); final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId( AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); assertThat(currentA11yFocusedWindowId, is(not(eventWindowId))); @@ -457,7 +479,8 @@ public class AccessibilityWindowManagerTest { @Test public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() { - final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX); + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX); final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId( AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); assertThat(currentA11yFocusedWindowId, is(not(eventWindowId))); @@ -482,7 +505,8 @@ public class AccessibilityWindowManagerTest { @Test public void onTouchInteractionEnd_shouldRollbackActiveWindow() { - final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1); + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX + 1); final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); assertThat(currentActiveWindowId, is(not(eventWindowId))); @@ -513,12 +537,14 @@ public class AccessibilityWindowManagerTest { @Test public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus() throws RemoteException { - final IBinder defaultFocusWinToken = mWindowInfos.get(DEFAULT_FOCUSED_INDEX).token; + final IBinder defaultFocusWinToken = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token; final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked( USER_SYSTEM_ID, defaultFocusWinToken); when(mMockWindowManagerInternal.getFocusedWindowToken()) .thenReturn(defaultFocusWinToken); - final int newFocusWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1); + final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX + 1); final IAccessibilityInteractionConnection mockNewFocusConnection = mA11yWindowManager.getConnectionLocked( USER_SYSTEM_ID, newFocusWindowId).getRemote(); @@ -556,28 +582,72 @@ public class AccessibilityWindowManagerTest { @Test public void getPictureInPictureWindow_shouldNotNull() { - assertNull(mA11yWindowManager.getPictureInPictureWindow()); - mWindowInfos.get(1).inPictureInPicture = true; - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + assertNull(mA11yWindowManager.getPictureInPictureWindowLocked()); + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true; + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); - assertNotNull(mA11yWindowManager.getPictureInPictureWindow()); + assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked()); } @Test public void notifyOutsideTouch() throws RemoteException { - final int targetWindowId = getWindowIdFromWindowInfos(1); - final int outsideWindowId = getWindowIdFromWindowInfos(0); + final int targetWindowId = + getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1); + final int outsideWindowId = + getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0); final IAccessibilityInteractionConnection mockRemoteConnection = mA11yWindowManager.getConnectionLocked( USER_SYSTEM_ID, outsideWindowId).getRemote(); - mWindowInfos.get(0).hasFlagWatchOutsideTouch = true; - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true; + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId); verify(mockRemoteConnection).notifyOutsideTouch(); } - private IWindow addAccessibilityInteractionConnection(boolean bGlobal) + private void startTrackingPerDisplay(int displayId) throws RemoteException { + ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>(); + // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy + // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos + // for the test. + int layer = 0; + for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) { + final IWindow token = addAccessibilityInteractionConnection(displayId, true); + addWindowInfo(windowInfosForDisplay, token, layer++); + + } + for (int i = 0; i < NUM_APP_WINDOWS; i++) { + final IWindow token = addAccessibilityInteractionConnection(displayId, false); + addWindowInfo(windowInfosForDisplay, token, layer++); + } + // Setups default focus. + windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true; + // Turns on windows tracking, and update window info. + mA11yWindowManager.startTrackingWindows(); + // Puts window lists into array. + mWindowInfos.put(displayId, windowInfosForDisplay); + // Sets the default display as the top focused display. + if (displayId == Display.DEFAULT_DISPLAY) { + setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX); + } + // Invokes callback for sending window lists to A11y framework. + onWindowsForAccessibilityChanged(displayId, FORCE_SEND); + + assertEquals(mA11yWindowManager.getWindowListLocked().size(), + windowInfosForDisplay.size()); + } + + private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) { + ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor = + ArgumentCaptor.forClass( + WindowManagerInternal.WindowsForAccessibilityCallback.class); + verify(mMockWindowManagerInternal) + .setWindowsForAccessibilityCallback(eq(displayId), + windowsForAccessibilityCallbacksCaptor.capture()); + return windowsForAccessibilityCallbacksCaptor.getValue(); + } + + private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal) throws RemoteException { final IWindow mockWindowToken = Mockito.mock(IWindow.class); final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock( @@ -588,6 +658,8 @@ public class AccessibilityWindowManagerTest { when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder); when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(USER_SYSTEM_ID)) .thenReturn(bGlobal); + when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowToken.asBinder())) + .thenReturn(displayId); int windowId = mA11yWindowManager.addAccessibilityInteractionConnection( mockWindowToken, mockA11yConnection, PACKAGE_NAME, USER_SYSTEM_ID); @@ -595,21 +667,40 @@ public class AccessibilityWindowManagerTest { return mockWindowToken; } - private void addWindowInfo(IWindow windowToken, int layer) { + private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) { final WindowInfo windowInfo = WindowInfo.obtain(); windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION; windowInfo.token = windowToken.asBinder(); windowInfo.layer = layer; windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - mWindowInfos.add(windowInfo); + windowInfos.add(windowInfo); } - private int getWindowIdFromWindowInfos(int index) { - final IBinder windowToken = mWindowInfos.get(index).token; + private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) { + final IBinder windowToken = mWindowInfos.get(displayId).get(index).token; return mA11yWindowManager.findWindowIdLocked( USER_SYSTEM_ID, windowToken); } + private void setTopFocusedWindowAndDisplay(int displayId, int index) { + // Sets the top focus window. + final IBinder eventWindowToken = mWindowInfos.get(displayId).get(index).token; + when(mMockWindowManagerInternal.getFocusedWindowToken()) + .thenReturn(eventWindowToken); + // Sets the top focused display. + when(mMockWindowManagerInternal.getDisplayIdForWindow(eventWindowToken)) + .thenReturn(displayId); + } + + private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) { + WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId); + if (callbacks == null) { + callbacks = getWindowsForAccessibilityCallbacks(displayId); + mCallbackOfWindows.put(displayId, callbacks); + } + callbacks.onWindowsForAccessibilityChanged(forceSend, mWindowInfos.get(displayId)); + } + static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> { private int mWindowId; diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java index 0309dbeea2ca..cae7b57580bb 100644 --- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java @@ -273,7 +273,7 @@ public class JobStoreTest { invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period). final Pair<Long, Long> persistedExecutionTimesUTC = new Pair<>(rtcNow, rtcNow + ONE_HOUR); final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage", - 0 /* sourceUserId */, 0, 0, "someTag", + 0 /* sourceUserId */, 0, "someTag", invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, persistedExecutionTimesUTC, 0 /* innerFlagg */); diff --git a/startop/scripts/app_startup/app_startup_runner.py b/startop/scripts/app_startup/app_startup_runner.py index 7b3bf3387452..eb582f946958 100755 --- a/startop/scripts/app_startup/app_startup_runner.py +++ b/startop/scripts/app_startup/app_startup_runner.py @@ -32,21 +32,25 @@ import itertools import os import sys import tempfile +from datetime import timedelta from typing import Any, Callable, Iterable, List, NamedTuple, TextIO, Tuple, \ TypeVar, Union, Optional # local import DIR = os.path.abspath(os.path.dirname(__file__)) sys.path.append(os.path.dirname(DIR)) +import lib.cmd_utils as cmd_utils +import lib.print_utils as print_utils +import iorap.compiler as compiler from app_startup.run_app_with_prefetch import PrefetchAppRunner import app_startup.lib.args_utils as args_utils from app_startup.lib.data_frame import DataFrame -import lib.cmd_utils as cmd_utils -import lib.print_utils as print_utils +from app_startup.lib.perfetto_trace_collector import PerfettoTraceCollector # The following command line options participate in the combinatorial generation. # All other arguments have a global effect. -_COMBINATORIAL_OPTIONS = ['package', 'readahead', 'compiler_filter', 'activity'] +_COMBINATORIAL_OPTIONS = ['package', 'readahead', 'compiler_filter', + 'activity', 'trace_duration'] _TRACING_READAHEADS = ['mlock', 'fadvise'] _FORWARD_OPTIONS = {'loop_count': '--count'} _RUN_SCRIPT = os.path.join(os.path.dirname(os.path.realpath(__file__)), @@ -54,9 +58,8 @@ _RUN_SCRIPT = os.path.join(os.path.dirname(os.path.realpath(__file__)), CollectorPackageInfo = NamedTuple('CollectorPackageInfo', [('package', str), ('compiler_filter', str)]) -_COLLECTOR_SCRIPT = os.path.join(os.path.dirname(os.path.realpath(__file__)), - '../iorap/collector') -_COLLECTOR_TIMEOUT_MULTIPLIER = 10 # take the regular --timeout and multiply +_COMPILER_SCRIPT = os.path.join(os.path.dirname(os.path.dirname( + os.path.realpath(__file__))), 'iorap/compiler.py') # by 2; systrace starts up slowly. _UNLOCK_SCREEN_SCRIPT = os.path.join( @@ -70,11 +73,14 @@ RunCommandArgs = NamedTuple('RunCommandArgs', ('timeout', Optional[int]), ('debug', bool), ('simulate', bool), - ('input', Optional[str])]) + ('input', Optional[str]), + ('trace_duration', Optional[timedelta])]) # This must be the only mutable global variable. All other global variables are constants to avoid magic literals. _debug = False # See -d/--debug flag. _DEBUG_FORCE = None # Ignore -d/--debug if this is not none. +_PERFETTO_TRACE_DURATION_MS = 5000 # milliseconds +_PERFETTO_TRACE_DURATION = timedelta(milliseconds=_PERFETTO_TRACE_DURATION_MS) # Type hinting names. T = TypeVar('T') @@ -123,26 +129,15 @@ def parse_options(argv: List[str] = None): optional_named.add_argument('-in', '--inodes', dest='inodes', type=str, action='store', help='Path to inodes file (system/extras/pagecache/pagecache.py -d inodes)') + optional_named.add_argument('--compiler-trace-duration-ms', + dest='trace_duration', + type=lambda ms_str: timedelta(milliseconds=int(ms_str)), + action='append', + help='The trace duration (milliseconds) in ' + 'compilation') return parser.parse_args(argv) -def make_script_command_with_temp_output(script: str, - args: List[str], - **kwargs) -> Tuple[str, TextIO]: - """ - Create a command to run a script given the args. - Appends --count <loop_count> --output <tmp-file-name>. - Returns a tuple (cmd, tmp_file) - """ - tmp_output_file = tempfile.NamedTemporaryFile(mode='r') - cmd = [script] + args - for key, value in kwargs.items(): - cmd += ['--%s' % (key), "%s" % (value)] - if _debug: - cmd += ['--verbose'] - cmd = cmd + ["--output", tmp_output_file.name] - return cmd, tmp_output_file - def key_to_cmdline_flag(key: str) -> str: """Convert key into a command line flag, e.g. 'foo-bars' -> '--foo-bar' """ if key.endswith("s"): @@ -163,26 +158,26 @@ def as_run_command(tpl: NamedTuple) -> List[Union[str, Any]]: args.append(value) return args -def run_collector_script(collector_info: CollectorPackageInfo, - inodes_path: str, - timeout: int, - simulate: bool) -> Tuple[bool, TextIO]: - """Run collector to collect prefetching trace. """ - # collector_args = ["--package", package_name] - collector_args = as_run_command(collector_info) - # TODO: forward --wait_time for how long systrace runs? - # TODO: forward --trace_buffer_size for size of systrace buffer size? - collector_cmd, collector_tmp_output_file = make_script_command_with_temp_output( - _COLLECTOR_SCRIPT, collector_args, inodes=inodes_path) - - collector_timeout = timeout and _COLLECTOR_TIMEOUT_MULTIPLIER * timeout - (collector_passed, collector_script_output) = \ - cmd_utils.execute_arbitrary_command(collector_cmd, - collector_timeout, - shell=False, - simulate=simulate) - - return collector_passed, collector_tmp_output_file +def run_perfetto_collector(collector_info: CollectorPackageInfo, + timeout: int, + simulate: bool) -> Tuple[bool, TextIO]: + """Run collector to collect prefetching trace. + + Returns: + A tuple of whether the collection succeeds and the generated trace file. + """ + tmp_output_file = tempfile.NamedTemporaryFile() + + collector = PerfettoTraceCollector(package=collector_info.package, + activity=None, + compiler_filter=collector_info.compiler_filter, + timeout=timeout, + simulate=simulate, + trace_duration=_PERFETTO_TRACE_DURATION, + save_destination_file_path=tmp_output_file.name) + result = collector.run() + + return result is not None, tmp_output_file def parse_run_script_csv_file(csv_file: TextIO) -> DataFrame: """Parse a CSV file full of integers into a DataFrame.""" @@ -216,6 +211,52 @@ def parse_run_script_csv_file(csv_file: TextIO) -> DataFrame: return DataFrame(d) +def compile_perfetto_trace(inodes_path: str, + perfetto_trace_file: str, + trace_duration: Optional[timedelta]) -> TextIO: + compiler_trace_file = tempfile.NamedTemporaryFile() + argv = [_COMPILER_SCRIPT, '-i', inodes_path, '--perfetto-trace', + perfetto_trace_file, '-o', compiler_trace_file.name] + + if trace_duration is not None: + argv += ['--duration', str(int(trace_duration.total_seconds() + * PerfettoTraceCollector.MS_PER_SEC))] + + print_utils.debug_print(argv) + compiler.main(argv) + return compiler_trace_file + +def execute_run_using_perfetto_trace(collector_info, + run_combos: Iterable[RunCommandArgs], + simulate: bool, + inodes_path: str, + timeout: int) -> DataFrame: + """ Executes run based on perfetto trace. """ + passed, perfetto_trace_file = run_perfetto_collector(collector_info, + timeout, + simulate) + if not passed: + raise RuntimeError('Cannot run perfetto collector!') + + with perfetto_trace_file: + for combos in run_combos: + if combos.readahead in _TRACING_READAHEADS: + if simulate: + compiler_trace_file = tempfile.NamedTemporaryFile() + else: + compiler_trace_file = compile_perfetto_trace(inodes_path, + perfetto_trace_file.name, + combos.trace_duration) + with compiler_trace_file: + combos = combos._replace(input=compiler_trace_file.name) + print_utils.debug_print(combos) + output = PrefetchAppRunner(**combos._asdict()).run() + else: + print_utils.debug_print(combos) + output = PrefetchAppRunner(**combos._asdict()).run() + + yield DataFrame(dict((x, [y]) for x, y in output)) if output else None + def execute_run_combos( grouped_run_combos: Iterable[Tuple[CollectorPackageInfo, Iterable[RunCommandArgs]]], simulate: bool, @@ -228,19 +269,11 @@ def execute_run_combos( shell=False) for collector_info, run_combos in grouped_run_combos: - for combos in run_combos: - args = as_run_command(combos) - if combos.readahead in _TRACING_READAHEADS: - passed, collector_tmp_output_file = run_collector_script(collector_info, - inodes_path, - timeout, - simulate) - combos = combos._replace(input=collector_tmp_output_file.name) - - print_utils.debug_print(combos) - output = PrefetchAppRunner(**combos._asdict()).run() - - yield DataFrame(dict((x, [y]) for x, y in output)) if output else None + yield from execute_run_using_perfetto_trace(collector_info, + run_combos, + simulate, + inodes_path, + timeout) def gather_results(commands: Iterable[Tuple[DataFrame]], key_list: List[str], value_list: List[Tuple[str, ...]]): diff --git a/startop/scripts/app_startup/app_startup_runner_test.py b/startop/scripts/app_startup/app_startup_runner_test.py index 9aa7014d1912..42ea5f0e4bb9 100755 --- a/startop/scripts/app_startup/app_startup_runner_test.py +++ b/startop/scripts/app_startup/app_startup_runner_test.py @@ -91,7 +91,8 @@ def default_dict_for_parsed_args(**kwargs): # Combine it with all of the "optional" parameters' default values. """ d = {'compiler_filters': None, 'simulate': False, 'debug': False, - 'output': None, 'timeout': 10, 'loop_count': 1, 'inodes': None} + 'output': None, 'timeout': 10, 'loop_count': 1, 'inodes': None, + 'trace_duration': None} d.update(kwargs) return d @@ -159,19 +160,6 @@ def test_key_to_cmdline_flag(): assert asr.key_to_cmdline_flag("ba_r") == "--ba-r" assert asr.key_to_cmdline_flag("ba_zs") == "--ba-z" -def test_make_script_command_with_temp_output(): - cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", - args=[], count=1) - with tmp_file: - assert cmd_str == ["fake_script", "--count", "1", "--output", tmp_file.name] - - cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", - args=['a', 'b'], - count=2) - with tmp_file: - assert cmd_str == ["fake_script", "a", "b", "--count", "2", "--output", - tmp_file.name] - def test_parse_run_script_csv_file(): # empty file -> empty list f = io.StringIO("") diff --git a/startop/scripts/app_startup/lib/app_runner.py b/startop/scripts/app_startup/lib/app_runner.py index a8afd6a22e38..78873fa51ab5 100644 --- a/startop/scripts/app_startup/lib/app_runner.py +++ b/startop/scripts/app_startup/lib/app_runner.py @@ -51,6 +51,7 @@ class AppRunnerListener(object): returns: a string in the format of "<metric>=<value>\n<metric>=<value>\n..." for further parsing. For example "TotalTime=123\nDisplayedTime=121". + Return an empty string if no metrics need to be parsed further. """ pass @@ -61,7 +62,7 @@ class AppRunner(object): APP_STARTUP_DIR = os.path.dirname(DIR) IORAP_COMMON_BASH_SCRIPT = os.path.realpath(os.path.join(DIR, '../../iorap/common')) - DEFAULT_TIMEOUT = 30 + DEFAULT_TIMEOUT = 30 # seconds def __init__(self, package: str, diff --git a/startop/scripts/app_startup/lib/perfetto_trace_collector.py b/startop/scripts/app_startup/lib/perfetto_trace_collector.py index 20a6c5280c81..9ffb3494da49 100644 --- a/startop/scripts/app_startup/lib/perfetto_trace_collector.py +++ b/startop/scripts/app_startup/lib/perfetto_trace_collector.py @@ -14,11 +14,11 @@ """Class to collector perfetto trace.""" import datetime -from datetime import timedelta import os import re import sys import time +from datetime import timedelta from typing import Optional, List, Tuple # global variables @@ -40,7 +40,9 @@ class PerfettoTraceCollector(AppRunnerListener): """ TRACE_FILE_SUFFIX = 'perfetto_trace.pb' TRACE_DURATION_PROP = 'iorapd.perfetto.trace_duration_ms' - SECONDS_TO_MILLISECONDS = 1000 + MS_PER_SEC = 1000 + DEFAULT_TRACE_DURATION = timedelta(milliseconds=5000) # 5 seconds + _COLLECTOR_TIMEOUT_MULTIPLIER = 10 # take the regular timeout and multiply def __init__(self, package: str, @@ -48,7 +50,7 @@ class PerfettoTraceCollector(AppRunnerListener): compiler_filter: Optional[str], timeout: Optional[int], simulate: bool, - trace_duration: timedelta = timedelta(milliseconds=5000), + trace_duration: timedelta = DEFAULT_TRACE_DURATION, save_destination_file_path: Optional[str] = None): """ Initialize the perfetto trace collector. """ self.app_runner = AppRunner(package, @@ -89,7 +91,7 @@ class PerfettoTraceCollector(AppRunnerListener): # Set perfetto trace duration prop to milliseconds. adb_utils.set_prop(PerfettoTraceCollector.TRACE_DURATION_PROP, int(self.trace_duration.total_seconds()* - PerfettoTraceCollector.SECONDS_TO_MILLISECONDS)) + PerfettoTraceCollector.MS_PER_SEC)) if not iorapd_utils.stop_iorapd(): raise RuntimeError('Cannot stop iorapd!') @@ -122,7 +124,7 @@ class PerfettoTraceCollector(AppRunnerListener): manner until all metrics have been found". Returns: - An empty string. + An empty string because the metric needs no further parsing. """ if not self._wait_for_perfetto_trace(pre_launch_timestamp): raise RuntimeError('Could not save perfetto app trace file!') @@ -143,14 +145,19 @@ class PerfettoTraceCollector(AppRunnerListener): format(self._get_remote_path())) # The pre_launch_timestamp is longer than what the datetime can parse. Trim - # last three digits to make them align. + # last three digits to make them align. For example: + # 2019-07-02 23:20:06.972674825999 -> 2019-07-02 23:20:06.972674825 + assert len(pre_launch_timestamp) == len('2019-07-02 23:20:06.972674825') timestamp = datetime.datetime.strptime(pre_launch_timestamp[:-3], '%Y-%m-%d %H:%M:%S.%f') - timeout_dt = timestamp + datetime.timedelta(0, self.app_runner.timeout) + + # The timeout of perfetto trace is longer than the normal app run timeout. + timeout_dt = self.app_runner.timeout * PerfettoTraceCollector._COLLECTOR_TIMEOUT_MULTIPLIER + timeout_end = timestamp + datetime.timedelta(seconds=timeout_dt) return logcat_utils.blocking_wait_for_logcat_pattern(timestamp, pattern, - timeout_dt) + timeout_end) def _get_remote_path(self): # For example: android.music%2Fmusic.TopLevelActivity.perfetto_trace.pb diff --git a/startop/scripts/iorap/compiler.py b/startop/scripts/iorap/compiler.py index 9527e28c94fe..ef9b870b8113 100755 --- a/startop/scripts/iorap/compiler.py +++ b/startop/scripts/iorap/compiler.py @@ -31,8 +31,10 @@ import tempfile from pathlib import Path from typing import Iterable, Optional, List -from generated.TraceFile_pb2 import * -from lib.inode2filename import Inode2Filename +DIR = os.path.abspath(os.path.dirname(__file__)) +sys.path.append(os.path.dirname(DIR)) +from iorap.generated.TraceFile_pb2 import * +from iorap.lib.inode2filename import Inode2Filename parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) sys.path.append(parent_dir_name) diff --git a/startop/view_compiler/dex_layout_compiler.cc b/startop/view_compiler/dex_layout_compiler.cc index c68793d10399..8febfb71ecd1 100644 --- a/startop/view_compiler/dex_layout_compiler.cc +++ b/startop/view_compiler/dex_layout_compiler.cc @@ -23,25 +23,6 @@ namespace startop { using android::base::StringPrintf; -void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) { - if (0 == name.compare(u"merge")) { - message_ = "Merge tags are not supported"; - can_compile_ = false; - } - if (0 == name.compare(u"include")) { - message_ = "Include tags are not supported"; - can_compile_ = false; - } - if (0 == name.compare(u"view")) { - message_ = "View tags are not supported"; - can_compile_ = false; - } - if (0 == name.compare(u"fragment")) { - message_ = "Fragment tags are not supported"; - can_compile_ = false; - } -} - DexViewBuilder::DexViewBuilder(dex::MethodBuilder* method) : method_{method}, context_{dex::Value::Parameter(0)}, diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index cd79f37bb2ce..ce211120cf09 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2328,6 +2328,13 @@ public class CarrierConfigManager { public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool"; /** + * Indicates if the TTY HCO and VCO options should be hidden in the accessibility menu + * if the device is capable of RTT. + * @hide + */ + public static final String KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL = "hide_tty_hco_vco_with_rtt"; + + /** * The flag to disable the popup dialog which warns the user of data charges. * @hide */ @@ -3406,6 +3413,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false); sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false); sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true); + sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false); sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true); sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null); diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index cdf4c935f84b..aa7e21a82500 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -340,6 +340,19 @@ public final class DisconnectCause { */ public static final int MEDIA_TIMEOUT = 77; + /** + * Indicates that an emergency call cannot be placed over WFC because the service is not + * available in the current location. + * @hide + */ + public static final int EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 78; + + /** + * Indicates that WiFi calling service is not available in the current location. + * @hide + */ + public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79; + //********************************************************************************************* // When adding a disconnect type: // 1) Update toString() with the newly added disconnect type. @@ -510,6 +523,10 @@ public final class DisconnectCause { return "OTASP_PROVISIONING_IN_PROCESS"; case MEDIA_TIMEOUT: return "MEDIA_TIMEOUT"; + case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE: + return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE"; + case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION: + return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION"; default: return "INVALID: " + cause; } diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java index a478606da22a..20aba4d97849 100644 --- a/telephony/java/android/telephony/ims/ImsReasonInfo.java +++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java @@ -871,6 +871,19 @@ public final class ImsReasonInfo implements Parcelable { */ public static final int CODE_REJECT_ONGOING_CS_CALL = 1621; + /** + * An attempt was made to place an emergency call over WFC when emergency services is not + * currently available in the current location. + * @hide + */ + public static final int CODE_EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 1622; + + /** + * Indicates that WiFi calling service is not available in the current location. + * @hide + */ + public static final int CODE_WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 1623; + /* * OEM specific error codes. To be used by OEMs when they don't want to reveal error code which * would be replaced by ERROR_UNSPECIFIED. diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java index 98f52cbf93da..6df54571a5c6 100644 --- a/telephony/java/com/android/internal/telephony/SmsApplication.java +++ b/telephony/java/com/android/internal/telephony/SmsApplication.java @@ -158,7 +158,7 @@ public final class SmsApplication { ApplicationInfo appInfo; try { appInfo = pm.getApplicationInfoAsUser(mPackageName, 0, - UserHandle.getUserId(mUid)); + UserHandle.getUserHandleForUid(mUid)); } catch (NameNotFoundException e) { return null; } @@ -300,7 +300,7 @@ public final class SmsApplication { Uri.fromParts(SCHEME_SMSTO, "", null)); List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - userId); + UserHandle.getUserHandleForUid(userId)); for (ResolveInfo resolveInfo : respondServices) { final ServiceInfo serviceInfo = resolveInfo.serviceInfo; if (serviceInfo == null) { diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index 72a6c9dcf169..67103bfddce1 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -367,7 +367,7 @@ public final class TelephonyPermissions { ApplicationInfo callingPackageInfo = null; try { callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser( - callingPackage, 0, UserHandle.getUserId(uid)); + callingPackage, 0, UserHandle.getUserHandleForUid(uid)); if (callingPackageInfo != null) { if (callingPackageInfo.isSystemApp()) { isPreinstalled = true; |