Merge "Use new GX overlay for new AOD/lockscreen transitions." into sc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 18856f7..edf2ce3 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -16,33 +16,43 @@
package com.android.server.job;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.UserSwitchObserver;
import android.app.job.JobInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.UserInfo;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseIntArray;
+import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.util.StatLogger;
import com.android.server.JobSchedulerBackgroundThread;
+import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.StateController;
+import com.android.server.pm.UserManagerInternal;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -66,12 +76,14 @@
static final int WORK_TYPE_NONE = 0;
static final int WORK_TYPE_TOP = 1 << 0;
static final int WORK_TYPE_BG = 1 << 1;
- private static final int NUM_WORK_TYPES = 2;
+ static final int WORK_TYPE_BGUSER = 1 << 2;
+ private static final int NUM_WORK_TYPES = 3;
@IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = {
WORK_TYPE_NONE,
WORK_TYPE_TOP,
- WORK_TYPE_BG
+ WORK_TYPE_BG,
+ WORK_TYPE_BGUSER
})
@Retention(RetentionPolicy.SOURCE)
public @interface WorkType {
@@ -98,22 +110,26 @@
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 2)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 6))),
+ List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
+ ),
new WorkTypeConfig("screen_on_moderate", 8,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 4))),
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
+ ),
new WorkTypeConfig("screen_on_low", 5,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1))),
+ List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ ),
new WorkTypeConfig("screen_on_critical", 5,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1)))
+ List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ )
);
private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF =
new WorkConfigLimitsPerMemoryTrimLevel(
@@ -121,22 +137,26 @@
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 6))),
+ List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
+ ),
new WorkTypeConfig("screen_off_moderate", 10,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 4))),
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
+ ),
new WorkTypeConfig("screen_off_low", 5,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1))),
+ List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ ),
new WorkTypeConfig("screen_off_critical", 5,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1)))
+ List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ )
);
/**
@@ -171,6 +191,10 @@
"assignJobsToContexts",
"refreshSystemState",
});
+ @VisibleForTesting
+ GracePeriodObserver mGracePeriodObserver;
+ @VisibleForTesting
+ boolean mShouldRestrictBgUser;
interface Stats {
int ASSIGN_JOBS_TO_CONTEXTS = 0;
@@ -182,9 +206,13 @@
JobConcurrencyManager(JobSchedulerService service) {
mService = service;
mLock = mService.mLock;
- mContext = service.getContext();
+ mContext = service.getTestableContext();
mHandler = JobSchedulerBackgroundThread.getHandler();
+
+ mGracePeriodObserver = new GracePeriodObserver(mContext);
+ mShouldRestrictBgUser = mContext.getResources().getBoolean(
+ R.bool.config_jobSchedulerRestrictBackgroundUser);
}
public void onSystemReady() {
@@ -193,10 +221,18 @@
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(mReceiver, filter);
+ try {
+ ActivityManager.getService().registerUserSwitchObserver(mGracePeriodObserver, TAG);
+ } catch (RemoteException e) {
+ }
onInteractiveStateChanged(mPowerManager.isInteractive());
}
+ void onUserRemoved(int userId) {
+ mGracePeriodObserver.onUserRemoved(userId);
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -224,7 +260,7 @@
Slog.d(TAG, "Interactive: " + interactive);
}
- final long nowRealtime = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final long nowRealtime = sElapsedRealtimeClock.millis();
if (interactive) {
mLastScreenOnRealtime = nowRealtime;
mEffectiveInteractiveState = true;
@@ -261,7 +297,7 @@
if (mLastScreenOnRealtime > mLastScreenOffRealtime) {
return;
}
- final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final long now = sElapsedRealtimeClock.millis();
if ((mLastScreenOffRealtime + mScreenOffAdjustmentDelayMs) > now) {
return;
}
@@ -723,6 +759,10 @@
pw.print(mLastMemoryTrimLevel);
pw.println();
+ pw.print("User Grace Period: ");
+ pw.print(mGracePeriodObserver.mGracePeriodExpiration);
+ pw.println();
+
mStatLogger.dump(pw);
} finally {
pw.decreaseIndent();
@@ -748,14 +788,44 @@
proto.end(token);
}
+ /**
+ * Decides whether a job is from the current foreground user or the equivalent.
+ */
+ @VisibleForTesting
+ boolean shouldRunAsFgUserJob(JobStatus job) {
+ if (!mShouldRestrictBgUser) return true;
+ int userId = job.getSourceUserId();
+ UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
+ UserInfo userInfo = um.getUserInfo(userId);
+
+ // If the user has a parent user (e.g. a work profile of another user), the user should be
+ // treated equivalent as its parent user.
+ if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+ && userInfo.profileGroupId != userId) {
+ userId = userInfo.profileGroupId;
+ userInfo = um.getUserInfo(userId);
+ }
+
+ int currentUser = LocalServices.getService(ActivityManagerInternal.class)
+ .getCurrentUserId();
+ // A user is treated as foreground user if any of the followings is true:
+ // 1. The user is current user
+ // 2. The user is primary user
+ // 3. The user's grace period has not expired
+ return currentUser == userId || userInfo.isPrimary()
+ || mGracePeriodObserver.isWithinGracePeriodForUser(userId);
+ }
+
int getJobWorkTypes(@NonNull JobStatus js) {
int classification = 0;
// TODO(171305774): create dedicated work type for EJ and FGS
if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP
|| js.shouldTreatAsExpeditedJob()) {
classification |= WORK_TYPE_TOP;
- } else {
+ } else if (shouldRunAsFgUserJob(js)) {
classification |= WORK_TYPE_BG;
+ } else {
+ classification |= WORK_TYPE_BGUSER;
}
return classification;
}
@@ -766,8 +836,12 @@
CONFIG_KEY_PREFIX_CONCURRENCY + "max_total_";
private static final String KEY_PREFIX_MAX_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "max_top_";
private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_";
+ private static final String KEY_PREFIX_MAX_BGUSER =
+ CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_";
private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_";
private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_";
+ private static final String KEY_PREFIX_MIN_BGUSER =
+ CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_";
private final String mConfigIdentifier;
private int mMaxTotal;
@@ -815,6 +889,10 @@
properties.getInt(KEY_PREFIX_MAX_BG + mConfigIdentifier,
mDefaultMaxAllowedSlots.get(WORK_TYPE_BG, mMaxTotal))));
mMaxAllowedSlots.put(WORK_TYPE_BG, maxBg);
+ final int maxBgUser = Math.max(1, Math.min(mMaxTotal,
+ properties.getInt(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
+ mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER, mMaxTotal))));
+ mMaxAllowedSlots.put(WORK_TYPE_BGUSER, maxBgUser);
int remaining = mMaxTotal;
mMinReservedSlots.clear();
@@ -829,6 +907,12 @@
properties.getInt(KEY_PREFIX_MIN_BG + mConfigIdentifier,
mDefaultMinReservedSlots.get(WORK_TYPE_BG))));
mMinReservedSlots.put(WORK_TYPE_BG, minBg);
+ remaining -= minBg;
+ // Ensure bg user is in the range [0, min(maxBgUser, remaining)]
+ final int minBgUser = Math.max(0, Math.min(Math.min(maxBgUser, remaining),
+ properties.getInt(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
+ mDefaultMinReservedSlots.get(WORK_TYPE_BGUSER, 0))));
+ mMinReservedSlots.put(WORK_TYPE_BGUSER, minBgUser);
}
int getMaxTotal() {
@@ -853,6 +937,10 @@
.println();
pw.print(KEY_PREFIX_MAX_BG + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BG))
.println();
+ pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
+ mMinReservedSlots.get(WORK_TYPE_BGUSER)).println();
+ pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
+ mMaxAllowedSlots.get(WORK_TYPE_BGUSER)).println();
}
}
@@ -873,6 +961,58 @@
}
/**
+ * This class keeps the track of when a user's grace period expires.
+ */
+ @VisibleForTesting
+ static class GracePeriodObserver extends UserSwitchObserver {
+ // Key is UserId and Value is the time when grace period expires
+ @VisibleForTesting
+ final SparseLongArray mGracePeriodExpiration = new SparseLongArray();
+ private int mCurrentUserId;
+ @VisibleForTesting
+ int mGracePeriod;
+ private final UserManagerInternal mUserManagerInternal;
+ final Object mLock = new Object();
+
+
+ GracePeriodObserver(Context context) {
+ mCurrentUserId = LocalServices.getService(ActivityManagerInternal.class)
+ .getCurrentUserId();
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ mGracePeriod = Math.max(0, context.getResources().getInteger(
+ R.integer.config_jobSchedulerUserGracePeriod));
+ }
+
+ @Override
+ public void onUserSwitchComplete(int newUserId) {
+ final long expiration = sElapsedRealtimeClock.millis() + mGracePeriod;
+ synchronized (mLock) {
+ if (mCurrentUserId != UserHandle.USER_NULL
+ && mUserManagerInternal.exists(mCurrentUserId)) {
+ mGracePeriodExpiration.append(mCurrentUserId, expiration);
+ }
+ mGracePeriodExpiration.delete(newUserId);
+ mCurrentUserId = newUserId;
+ }
+ }
+
+ void onUserRemoved(int userId) {
+ synchronized (mLock) {
+ mGracePeriodExpiration.delete(userId);
+ }
+ }
+
+ @VisibleForTesting
+ public boolean isWithinGracePeriodForUser(int userId) {
+ synchronized (mLock) {
+ return userId == mCurrentUserId
+ || sElapsedRealtimeClock.millis()
+ < mGracePeriodExpiration.get(userId, Long.MAX_VALUE);
+ }
+ }
+ }
+
+ /**
* This class decides, taking into account the current {@link WorkTypeConfig} and how many jobs
* are running/pending, how many more job can start.
*
@@ -900,12 +1040,16 @@
mConfigNumReservedSlots.put(WORK_TYPE_TOP,
workTypeConfig.getMinReserved(WORK_TYPE_TOP));
mConfigNumReservedSlots.put(WORK_TYPE_BG, workTypeConfig.getMinReserved(WORK_TYPE_BG));
+ mConfigNumReservedSlots.put(WORK_TYPE_BGUSER,
+ workTypeConfig.getMinReserved(WORK_TYPE_BGUSER));
mConfigAbsoluteMaxSlots.put(WORK_TYPE_TOP, workTypeConfig.getMax(WORK_TYPE_TOP));
mConfigAbsoluteMaxSlots.put(WORK_TYPE_BG, workTypeConfig.getMax(WORK_TYPE_BG));
+ mConfigAbsoluteMaxSlots.put(WORK_TYPE_BGUSER, workTypeConfig.getMax(WORK_TYPE_BGUSER));
mNumUnspecialized = mConfigMaxTotal;
mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_TOP);
mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_BG);
+ mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_BGUSER);
mNumUnspecializedRemaining = mConfigMaxTotal;
for (int i = mNumRunningJobs.size() - 1; i >= 0; --i) {
mNumUnspecializedRemaining -= Math.max(mNumRunningJobs.valueAt(i),
@@ -937,6 +1081,9 @@
if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
mNumPendingJobs.put(WORK_TYPE_BG, mNumPendingJobs.get(WORK_TYPE_BG) + 1);
}
+ if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
+ mNumPendingJobs.put(WORK_TYPE_BGUSER, mNumPendingJobs.get(WORK_TYPE_BGUSER) + 1);
+ }
}
void stageJob(@WorkType int workType) {
@@ -1029,6 +1176,11 @@
int resBg = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_BG), numBg);
mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg);
mNumUnspecialized -= resBg;
+ final int numBgUser = mNumRunningJobs.get(WORK_TYPE_BGUSER)
+ + mNumPendingJobs.get(WORK_TYPE_BGUSER);
+ int resBgUser = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_BGUSER), numBgUser);
+ mNumActuallyReservedSlots.put(WORK_TYPE_BGUSER, resBgUser);
+ mNumUnspecialized -= resBgUser;
mNumUnspecializedRemaining = mNumUnspecialized;
// Account for already running jobs after we've assigned the minimum number of slots.
@@ -1048,6 +1200,14 @@
resBg += unspecializedAssigned;
mNumUnspecializedRemaining -= extraRunning;
}
+ extraRunning = (mNumRunningJobs.get(WORK_TYPE_BGUSER) - resBgUser);
+ if (extraRunning > 0) {
+ unspecializedAssigned = Math.max(0,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER) - resBgUser,
+ extraRunning));
+ resBgUser += unspecializedAssigned;
+ mNumUnspecializedRemaining -= extraRunning;
+ }
// Assign remaining unspecialized based on ranking.
unspecializedAssigned = Math.max(0,
@@ -1060,6 +1220,12 @@
Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG), numBg) - resBg));
mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg + unspecializedAssigned);
mNumUnspecializedRemaining -= unspecializedAssigned;
+ unspecializedAssigned = Math.max(0,
+ Math.min(mNumUnspecializedRemaining,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER), numBgUser)
+ - resBgUser));
+ mNumActuallyReservedSlots.put(WORK_TYPE_BGUSER, resBgUser + unspecializedAssigned);
+ mNumUnspecializedRemaining -= unspecializedAssigned;
}
int canJobStart(int workTypes) {
@@ -1081,6 +1247,16 @@
return WORK_TYPE_BG;
}
}
+ if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
+ final int maxAllowed = Math.min(
+ mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER),
+ mNumActuallyReservedSlots.get(WORK_TYPE_BGUSER)
+ + mNumUnspecializedRemaining);
+ if (mNumRunningJobs.get(WORK_TYPE_BGUSER) + mNumStartingJobs.get(WORK_TYPE_BGUSER)
+ < maxAllowed) {
+ return WORK_TYPE_BGUSER;
+ }
+ }
return WORK_TYPE_NONE;
}
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 7ce867c..bfc153f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -743,6 +743,7 @@
mControllers.get(c).onUserRemovedLocked(userId);
}
}
+ mConcurrencyManager.onUserRemoved(userId);
} else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
// Has this package scheduled any jobs, such that we will take action
// if it were to be force-stopped?
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index a7396fa..be82b22 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -43,7 +43,7 @@
#include <android-base/properties.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -65,6 +65,8 @@
namespace android {
+using ui::DisplayMode;
+
static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
static const char PRODUCT_BOOTANIMATION_DARK_FILE[] = "/product/media/bootanimation-dark.zip";
static const char PRODUCT_BOOTANIMATION_FILE[] = "/product/media/bootanimation.zip";
@@ -345,14 +347,14 @@
continue;
}
- DisplayConfig displayConfig;
- const status_t error = SurfaceComposerClient::getActiveDisplayConfig(
- mBootAnimation->mDisplayToken, &displayConfig);
+ DisplayMode displayMode;
+ const status_t error = SurfaceComposerClient::getActiveDisplayMode(
+ mBootAnimation->mDisplayToken, &displayMode);
if (error != NO_ERROR) {
- SLOGE("Can't get active display configuration.");
+ SLOGE("Can't get active display mode.");
}
- mBootAnimation->resizeSurface(displayConfig.resolution.getWidth(),
- displayConfig.resolution.getHeight());
+ mBootAnimation->resizeSurface(displayMode.resolution.getWidth(),
+ displayMode.resolution.getHeight());
}
}
} while (numEvents > 0);
@@ -401,15 +403,15 @@
if (mDisplayToken == nullptr)
return NAME_NOT_FOUND;
- DisplayConfig displayConfig;
+ DisplayMode displayMode;
const status_t error =
- SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &displayConfig);
+ SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &displayMode);
if (error != NO_ERROR)
return error;
mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
- ui::Size resolution = displayConfig.resolution;
+ ui::Size resolution = displayMode.resolution;
resolution = limitSurfaceSize(resolution.width, resolution.height);
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
diff --git a/core/api/current.txt b/core/api/current.txt
index 28b7f9b..77829fb 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -20478,6 +20478,7 @@
field public static final int QUALITY_480P = 4; // 0x4
field public static final int QUALITY_4KDCI = 10; // 0xa
field public static final int QUALITY_720P = 5; // 0x5
+ field public static final int QUALITY_8KUHD = 13; // 0xd
field public static final int QUALITY_CIF = 3; // 0x3
field public static final int QUALITY_HIGH = 1; // 0x1
field public static final int QUALITY_HIGH_SPEED_1080P = 2004; // 0x7d4
@@ -20499,6 +20500,7 @@
field public static final int QUALITY_TIME_LAPSE_480P = 1004; // 0x3ec
field public static final int QUALITY_TIME_LAPSE_4KDCI = 1010; // 0x3f2
field public static final int QUALITY_TIME_LAPSE_720P = 1005; // 0x3ed
+ field public static final int QUALITY_TIME_LAPSE_8KUHD = 1013; // 0x3f5
field public static final int QUALITY_TIME_LAPSE_CIF = 1003; // 0x3eb
field public static final int QUALITY_TIME_LAPSE_HIGH = 1001; // 0x3e9
field public static final int QUALITY_TIME_LAPSE_LOW = 1000; // 0x3e8
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 6fec309..5bb3e05 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1990,6 +1990,7 @@
field public static final int UUID_BYTES_128_BIT = 16; // 0x10
field public static final int UUID_BYTES_16_BIT = 2; // 0x2
field public static final int UUID_BYTES_32_BIT = 4; // 0x4
+ field @NonNull public static final android.os.ParcelUuid VOLUME_CONTROL;
}
public final class BufferConstraint implements android.os.Parcelable {
@@ -4666,6 +4667,7 @@
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String);
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerProviderRequestListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.Listener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
@@ -4674,6 +4676,7 @@
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void unregisterProviderRequestListener(@NonNull android.location.provider.ProviderRequest.Listener);
}
public final class LocationRequest implements android.os.Parcelable {
@@ -4823,6 +4826,10 @@
method @NonNull public android.location.provider.ProviderRequest.Builder setWorkSource(@NonNull android.os.WorkSource);
}
+ public static interface ProviderRequest.Listener {
+ method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest);
+ }
+
}
package android.media {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index fb27f74..af5df76 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -7,3 +7,8 @@
name: "IDropBoxManagerService.aidl",
srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"],
}
+
+filegroup {
+ name: "ITracingServiceProxy.aidl",
+ srcs: ["android/tracing/ITracingServiceProxy.aidl"],
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 7eda50e..ea7e5ea 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3198,6 +3198,61 @@
}
/**
+ * Register a callback to receive events whenever the bluetooth stack goes down and back up,
+ * e.g. in the event the bluetooth is turned off/on via settings.
+ *
+ * If the bluetooth stack is currently up, there will not be an initial callback call.
+ * You can use the return value as an indication of this being the case.
+ *
+ * Callbacks will be delivered on a binder thread.
+ *
+ * @return whether bluetooth is already up currently
+ *
+ * @hide
+ */
+ public boolean registerServiceLifecycleCallback(ServiceLifecycleCallback callback) {
+ return getBluetoothService(callback.mRemote) != null;
+ }
+
+ /**
+ * Unregister a callback registered via {@link #registerServiceLifecycleCallback}
+ *
+ * @hide
+ */
+ public void unregisterServiceLifecycleCallback(ServiceLifecycleCallback callback) {
+ removeServiceStateCallback(callback.mRemote);
+ }
+
+ /**
+ * A callback for {@link #registerServiceLifecycleCallback}
+ *
+ * @hide
+ */
+ public abstract static class ServiceLifecycleCallback {
+
+ /** Called when the bluetooth stack is up */
+ public abstract void onBluetoothServiceUp();
+
+ /** Called when the bluetooth stack is down */
+ public abstract void onBluetoothServiceDown();
+
+ IBluetoothManagerCallback mRemote = new IBluetoothManagerCallback.Stub() {
+ @Override
+ public void onBluetoothServiceUp(IBluetooth bluetoothService) {
+ ServiceLifecycleCallback.this.onBluetoothServiceUp();
+ }
+
+ @Override
+ public void onBluetoothServiceDown() {
+ ServiceLifecycleCallback.this.onBluetoothServiceDown();
+ }
+
+ @Override
+ public void onBrEdrDown() {}
+ };
+ }
+
+ /**
* Starts a scan for Bluetooth LE devices.
*
* <p>Results of the scan are reported using the
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index c0736a6..d82cf19 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -167,6 +167,11 @@
/** @hide */
@NonNull
@SystemApi
+ public static final ParcelUuid VOLUME_CONTROL =
+ ParcelUuid.fromString("00001844-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/companion/Association.java b/core/java/android/companion/Association.java
index 17bf11b..960a087 100644
--- a/core/java/android/companion/Association.java
+++ b/core/java/android/companion/Association.java
@@ -38,7 +38,7 @@
private final @NonNull String mDeviceMacAddress;
private final @NonNull String mPackageName;
private final @Nullable String mDeviceProfile;
- private final boolean mKeepProfilePrivilegesWhenDeviceAway;
+ private final boolean mNotifyOnDeviceNearby;
/** @hide */
public int getUserId() {
@@ -47,7 +47,7 @@
- // Code below generated by codegen v1.0.21.
+ // Code below generated by codegen v1.0.22.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -71,7 +71,7 @@
@NonNull String deviceMacAddress,
@NonNull String packageName,
@Nullable String deviceProfile,
- boolean keepProfilePrivilegesWhenDeviceAway) {
+ boolean notifyOnDeviceNearby) {
this.mUserId = userId;
com.android.internal.util.AnnotationValidations.validate(
UserIdInt.class, null, mUserId);
@@ -82,7 +82,7 @@
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
this.mDeviceProfile = deviceProfile;
- this.mKeepProfilePrivilegesWhenDeviceAway = keepProfilePrivilegesWhenDeviceAway;
+ this.mNotifyOnDeviceNearby = notifyOnDeviceNearby;
// onConstructed(); // You can define this method to get a callback
}
@@ -103,8 +103,8 @@
}
@DataClass.Generated.Member
- public boolean isKeepProfilePrivilegesWhenDeviceAway() {
- return mKeepProfilePrivilegesWhenDeviceAway;
+ public boolean isNotifyOnDeviceNearby() {
+ return mNotifyOnDeviceNearby;
}
@Override
@@ -118,7 +118,7 @@
"deviceMacAddress = " + mDeviceMacAddress + ", " +
"packageName = " + mPackageName + ", " +
"deviceProfile = " + mDeviceProfile + ", " +
- "keepProfilePrivilegesWhenDeviceAway = " + mKeepProfilePrivilegesWhenDeviceAway +
+ "notifyOnDeviceNearby = " + mNotifyOnDeviceNearby +
" }";
}
@@ -139,7 +139,7 @@
&& Objects.equals(mDeviceMacAddress, that.mDeviceMacAddress)
&& Objects.equals(mPackageName, that.mPackageName)
&& Objects.equals(mDeviceProfile, that.mDeviceProfile)
- && mKeepProfilePrivilegesWhenDeviceAway == that.mKeepProfilePrivilegesWhenDeviceAway;
+ && mNotifyOnDeviceNearby == that.mNotifyOnDeviceNearby;
}
@Override
@@ -153,7 +153,7 @@
_hash = 31 * _hash + Objects.hashCode(mDeviceMacAddress);
_hash = 31 * _hash + Objects.hashCode(mPackageName);
_hash = 31 * _hash + Objects.hashCode(mDeviceProfile);
- _hash = 31 * _hash + Boolean.hashCode(mKeepProfilePrivilegesWhenDeviceAway);
+ _hash = 31 * _hash + Boolean.hashCode(mNotifyOnDeviceNearby);
return _hash;
}
@@ -164,7 +164,7 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (mKeepProfilePrivilegesWhenDeviceAway) flg |= 0x10;
+ if (mNotifyOnDeviceNearby) flg |= 0x10;
if (mDeviceProfile != null) flg |= 0x8;
dest.writeByte(flg);
dest.writeInt(mUserId);
@@ -185,7 +185,7 @@
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
- boolean keepProfilePrivilegesWhenDeviceAway = (flg & 0x10) != 0;
+ boolean notifyOnDeviceNearby = (flg & 0x10) != 0;
int userId = in.readInt();
String deviceMacAddress = in.readString();
String packageName = in.readString();
@@ -201,7 +201,7 @@
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
this.mDeviceProfile = deviceProfile;
- this.mKeepProfilePrivilegesWhenDeviceAway = keepProfilePrivilegesWhenDeviceAway;
+ this.mNotifyOnDeviceNearby = notifyOnDeviceNearby;
// onConstructed(); // You can define this method to get a callback
}
@@ -221,10 +221,10 @@
};
@DataClass.Generated(
- time = 1606940835778L,
- codegenVersion = "1.0.21",
+ time = 1610482674799L,
+ codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/companion/Association.java",
- inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate final boolean mKeepProfilePrivilegesWhenDeviceAway\npublic int getUserId()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate final boolean mNotifyOnDeviceNearby\npublic int getUserId()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/rotationresolver/RotationResolverInternal.java b/core/java/android/rotationresolver/RotationResolverInternal.java
index db879a7..1f1a66c 100644
--- a/core/java/android/rotationresolver/RotationResolverInternal.java
+++ b/core/java/android/rotationresolver/RotationResolverInternal.java
@@ -46,7 +46,6 @@
* error is captured. {@link RotationResolverCallbackInternal}
* @param proposedRotation the screen rotation that is proposed by the system.
* @param currentRotation the current screen rotation.
- * @param packageName the package name of the current activity that is running in foreground.
* @param timeoutMillis the timeout in millisecond for the query. If the query doesn't get
* fulfilled within this amount of time. It will be discarded and the
* callback will receive a failure result code {@link
@@ -55,8 +54,7 @@
*/
public abstract void resolveRotation(@NonNull RotationResolverCallbackInternal callback,
@Surface.Rotation int proposedRotation, @Surface.Rotation int currentRotation,
- String packageName, @DurationMillisLong long timeoutMillis,
- @NonNull CancellationSignal cancellationSignal);
+ @DurationMillisLong long timeoutMillis, @NonNull CancellationSignal cancellationSignal);
/**
* Internal interfaces for the rotation resolver callback.
diff --git a/core/java/android/tracing/ITracingServiceProxy.aidl b/core/java/android/tracing/ITracingServiceProxy.aidl
new file mode 100644
index 0000000..4520db3
--- /dev/null
+++ b/core/java/android/tracing/ITracingServiceProxy.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tracing;
+
+/**
+ * Binder interface for the TracingServiceProxy running in system_server.
+ *
+ * {@hide}
+ */
+interface ITracingServiceProxy
+{
+ /**
+ * Notifies system tracing app that a tracing session has ended. If a session is repurposed
+ * for use in a bugreport, sessionStolen can be set to indicate that tracing has ended but
+ * there is no buffer available to dump.
+ */
+ oneway void notifyTraceSessionEnded(boolean sessionStolen);
+}
diff --git a/core/java/android/tracing/OWNERS b/core/java/android/tracing/OWNERS
new file mode 100644
index 0000000..f5de4eb
--- /dev/null
+++ b/core/java/android/tracing/OWNERS
@@ -0,0 +1,2 @@
+cfijalkovich@google.com
+carmenjackson@google.com
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 790773f..b229212 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -65,7 +65,7 @@
DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true");
DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
- DEFAULT_FLAGS.put("settings_silky_home", "true");
+ DEFAULT_FLAGS.put("settings_silky_home", "false");
DEFAULT_FLAGS.put("settings_contextual_home", "false");
DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false");
}
diff --git a/core/java/android/uwb/SessionHandle.java b/core/java/android/uwb/SessionHandle.java
index 928fcbdc..b23f5ad 100644
--- a/core/java/android/uwb/SessionHandle.java
+++ b/core/java/android/uwb/SessionHandle.java
@@ -19,6 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* @hide
*/
@@ -73,6 +75,11 @@
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(mId);
+ }
+
+ @Override
public String toString() {
return "SessionHandle [id=" + mId + "]";
}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 5d4a4e5..e6cd252 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -58,11 +58,11 @@
public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;
/**
- * Specifies to generate config changed events from Surface Flinger.
+ * Specifies to generate mode changed events from Surface Flinger.
* <p>
* Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
*/
- public static final int EVENT_REGISTRATION_CONFIG_CHANGED_FLAG = 0x1;
+ public static final int EVENT_REGISTRATION_MODE_CHANGED_FLAG = 0x1;
/**
* Specifies to generate frame rate override events from Surface Flinger.
@@ -197,14 +197,14 @@
}
/**
- * Called when a display config changed event is received.
+ * Called when a display mode changed event is received.
*
* @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
* timebase.
* @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
- * @param configId The new config Id
+ * @param modeId The new mode Id
*/
- public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
}
/**
@@ -273,8 +273,8 @@
// Called from native code.
@SuppressWarnings("unused")
- private void dispatchConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
- onConfigChanged(timestampNanos, physicalDisplayId, configId);
+ private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
+ onModeChanged(timestampNanos, physicalDisplayId, modeId);
}
// Called from native code.
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 24bc308..f8c4d15 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -928,7 +928,9 @@
* seamless transition is one that doesn't have any visual interruptions, such as a black
* screen for a second or two. True indicates that any frame rate changes caused by this
* request should be seamless. False indicates that non-seamless refresh rates are also
- * acceptable.
+ * acceptable. Non-seamless switches might be used when the benefit of matching the content's
+ * frame rate outweighs the cost of the transition, for example when displaying
+ * long-running video content.
*
* @throws IllegalArgumentException If frameRate or compatibility are invalid.
*/
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 98b4acd..6a629ca 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -161,8 +161,8 @@
int L, int T, int R, int B);
private static native void nativeSetDisplaySize(long transactionObj, IBinder displayToken,
int width, int height);
- private static native SurfaceControl.DisplayInfo nativeGetDisplayInfo(IBinder displayToken);
- private static native SurfaceControl.DisplayConfig[] nativeGetDisplayConfigs(
+ private static native DisplayInfo nativeGetDisplayInfo(IBinder displayToken);
+ private static native DisplayMode[] nativeGetDisplayModes(
IBinder displayToken);
private static native DisplayedContentSamplingAttributes
nativeGetDisplayedContentSamplingAttributes(IBinder displayToken);
@@ -170,13 +170,13 @@
boolean enable, int componentMask, int maxFrames);
private static native DisplayedContentSample nativeGetDisplayedContentSample(
IBinder displayToken, long numFrames, long timestamp);
- private static native int nativeGetActiveConfig(IBinder displayToken);
- private static native boolean nativeSetDesiredDisplayConfigSpecs(IBinder displayToken,
- SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs);
- private static native SurfaceControl.DesiredDisplayConfigSpecs
- nativeGetDesiredDisplayConfigSpecs(IBinder displayToken);
+ private static native int nativeGetActiveDisplayMode(IBinder displayToken);
+ private static native boolean nativeSetDesiredDisplayModeSpecs(IBinder displayToken,
+ DesiredDisplayModeSpecs desiredDisplayModeSpecs);
+ private static native DesiredDisplayModeSpecs
+ nativeGetDesiredDisplayModeSpecs(IBinder displayToken);
private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
- private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
+ private static native DisplayPrimaries nativeGetDisplayNativePrimaries(
IBinder displayToken);
private static native int[] nativeGetCompositionDataspaces();
private static native int nativeGetActiveColorMode(IBinder displayToken);
@@ -1743,11 +1743,11 @@
*
* @hide
*/
- public static final class DisplayConfig {
+ public static final class DisplayMode {
/**
* Invalid display config id.
*/
- public static final int INVALID_DISPLAY_CONFIG_ID = -1;
+ public static final int INVALID_DISPLAY_MODE_ID = -1;
public int width;
public int height;
@@ -1764,7 +1764,7 @@
* configs within the same group can be done seamlessly in most cases.
* @see: android.hardware.graphics.composer@2.4::IComposerClient::Attribute::CONFIG_GROUP
*/
- public int configGroup;
+ public int group;
@Override
public String toString() {
@@ -1775,7 +1775,7 @@
+ ", refreshRate=" + refreshRate
+ ", appVsyncOffsetNanos=" + appVsyncOffsetNanos
+ ", presentationDeadlineNanos=" + presentationDeadlineNanos
- + ", configGroup=" + configGroup + "}";
+ + ", group=" + group + "}";
}
}
@@ -1802,21 +1802,21 @@
/**
* @hide
*/
- public static SurfaceControl.DisplayConfig[] getDisplayConfigs(IBinder displayToken) {
+ public static DisplayMode[] getDisplayModes(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetDisplayConfigs(displayToken);
+ return nativeGetDisplayModes(displayToken);
}
/**
* @hide
*/
- public static int getActiveConfig(IBinder displayToken) {
+ public static int getActiveDisplayMode(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetActiveConfig(displayToken);
+ return nativeGetActiveDisplayMode(displayToken);
}
/**
@@ -1863,8 +1863,8 @@
*
* @hide
*/
- public static final class DesiredDisplayConfigSpecs {
- public int defaultConfig;
+ public static final class DesiredDisplayModeSpecs {
+ public int defaultMode;
/**
* The primary refresh rate range represents display manager's general guidance on the
* display configs surface flinger will consider when switching refresh rates. Unless
@@ -1889,16 +1889,16 @@
*/
public boolean allowGroupSwitching;
- public DesiredDisplayConfigSpecs() {}
+ public DesiredDisplayModeSpecs() {}
- public DesiredDisplayConfigSpecs(DesiredDisplayConfigSpecs other) {
+ public DesiredDisplayModeSpecs(DesiredDisplayModeSpecs other) {
copyFrom(other);
}
- public DesiredDisplayConfigSpecs(int defaultConfig, boolean allowGroupSwitching,
+ public DesiredDisplayModeSpecs(int defaultMode, boolean allowGroupSwitching,
float primaryRefreshRateMin, float primaryRefreshRateMax,
float appRequestRefreshRateMin, float appRequestRefreshRateMax) {
- this.defaultConfig = defaultConfig;
+ this.defaultMode = defaultMode;
this.allowGroupSwitching = allowGroupSwitching;
this.primaryRefreshRateMin = primaryRefreshRateMin;
this.primaryRefreshRateMax = primaryRefreshRateMax;
@@ -1908,14 +1908,14 @@
@Override
public boolean equals(@Nullable Object o) {
- return o instanceof DesiredDisplayConfigSpecs && equals((DesiredDisplayConfigSpecs) o);
+ return o instanceof DesiredDisplayModeSpecs && equals((DesiredDisplayModeSpecs) o);
}
/**
* Tests for equality.
*/
- public boolean equals(DesiredDisplayConfigSpecs other) {
- return other != null && defaultConfig == other.defaultConfig
+ public boolean equals(DesiredDisplayModeSpecs other) {
+ return other != null && defaultMode == other.defaultMode
&& primaryRefreshRateMin == other.primaryRefreshRateMin
&& primaryRefreshRateMax == other.primaryRefreshRateMax
&& appRequestRefreshRateMin == other.appRequestRefreshRateMin
@@ -1930,8 +1930,8 @@
/**
* Copies the supplied object's values to this object.
*/
- public void copyFrom(DesiredDisplayConfigSpecs other) {
- defaultConfig = other.defaultConfig;
+ public void copyFrom(DesiredDisplayModeSpecs other) {
+ defaultMode = other.defaultMode;
primaryRefreshRateMin = other.primaryRefreshRateMin;
primaryRefreshRateMax = other.primaryRefreshRateMax;
appRequestRefreshRateMin = other.appRequestRefreshRateMin;
@@ -1942,7 +1942,7 @@
public String toString() {
return String.format("defaultConfig=%d primaryRefreshRateRange=[%.0f %.0f]"
+ " appRequestRefreshRateRange=[%.0f %.0f]",
- defaultConfig, primaryRefreshRateMin, primaryRefreshRateMax,
+ defaultMode, primaryRefreshRateMin, primaryRefreshRateMax,
appRequestRefreshRateMin, appRequestRefreshRateMax);
}
}
@@ -1950,25 +1950,31 @@
/**
* @hide
*/
- public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
- SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs) {
+ public static boolean setDesiredDisplayModeSpecs(IBinder displayToken,
+ DesiredDisplayModeSpecs desiredDisplayModeSpecs) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
+ if (desiredDisplayModeSpecs == null) {
+ throw new IllegalArgumentException("desiredDisplayModeSpecs must not be null");
+ }
+ if (desiredDisplayModeSpecs.defaultMode < 0) {
+ throw new IllegalArgumentException("defaultMode must be non-negative");
+ }
- return nativeSetDesiredDisplayConfigSpecs(displayToken, desiredDisplayConfigSpecs);
+ return nativeSetDesiredDisplayModeSpecs(displayToken, desiredDisplayModeSpecs);
}
/**
* @hide
*/
- public static SurfaceControl.DesiredDisplayConfigSpecs getDesiredDisplayConfigSpecs(
+ public static DesiredDisplayModeSpecs getDesiredDisplayModeSpecs(
IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetDesiredDisplayConfigSpecs(displayToken);
+ return nativeGetDesiredDisplayModeSpecs(displayToken);
}
/**
@@ -2039,7 +2045,7 @@
/**
* @hide
*/
- public static SurfaceControl.DisplayPrimaries getDisplayNativePrimaries(
+ public static DisplayPrimaries getDisplayNativePrimaries(
IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -3241,7 +3247,10 @@
* interruptions, such as a black screen for a second or two. True
* indicates that any frame rate changes caused by this request
* should be seamless. False indicates that non-seamless refresh
- * rates are also acceptable.
+ * rates are also acceptable. Non-seamless switches might be
+ * used when the benefit of matching the content's frame rate
+ * outweighs the cost of the transition, for example when
+ * displaying long-running video content.
* @return This transaction object.
*/
@NonNull
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index f019648..18029af 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -162,7 +162,6 @@
@NonNull WindowlessWindowManager wwm, boolean useSfChoreographer) {
mWm = wwm;
mViewRoot = new ViewRootImpl(c, d, mWm, useSfChoreographer);
- mViewRoot.forceDisableBLAST();
mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
}
@@ -188,7 +187,6 @@
mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
mSurfaceControl, hostToken);
mViewRoot = new ViewRootImpl(context, display, mWm);
- mViewRoot.forceDisableBLAST();
mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
}
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index b10370a..acbcbfa 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -85,12 +85,13 @@
for (int i = params.length - 1; i >= 0; i--) {
SurfaceParams surfaceParams = params[i];
SurfaceControl surface = surfaceParams.surface;
- if (frame > 0) {
- t.deferTransactionUntil(surface, mTargetSc, frame);
- }
applyParams(t, surfaceParams, mTmpFloat9);
}
- t.apply();
+ if (mTargetViewRootImpl != null) {
+ mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
+ } else {
+ t.apply();
+ }
}
public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 036a703..56d98e7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10137,9 +10137,11 @@
* Merges the transaction passed in with the next transaction in BLASTBufferQueue. This ensures
* you can add transactions to the upcoming frame.
*/
- void mergeWithNextTransaction(Transaction t, long frameNumber) {
+ public void mergeWithNextTransaction(Transaction t, long frameNumber) {
if (mBlastBufferQueue != null) {
mBlastBufferQueue.mergeWithNextTransaction(t, frameNumber);
+ } else {
+ t.apply();
}
}
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index bededa0..3aedda1 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -71,7 +71,7 @@
new HashMap<IBinder, ResizeCompleteCallback>();
private final SurfaceSession mSurfaceSession = new SurfaceSession();
- private final SurfaceControl mRootSurface;
+ protected final SurfaceControl mRootSurface;
private final Configuration mConfiguration;
private final IWindowSession mRealWm;
private final IBinder mHostInputToken;
@@ -126,7 +126,7 @@
}
}
- protected void attachToParentSurface(SurfaceControl.Builder b) {
+ protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
b.setParent(mRootSurface);
}
@@ -140,10 +140,10 @@
InsetsSourceControl[] outActiveControls) {
final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
.setFormat(attrs.format)
- .setBufferSize(getSurfaceWidth(attrs), getSurfaceHeight(attrs))
+ .setBLASTLayer()
.setName(attrs.getTitle().toString())
.setCallsite("WindowlessWindowManager.addToDisplay");
- attachToParentSurface(b);
+ attachToParentSurface(window, b);
final SurfaceControl sc = b.build();
if (((attrs.inputFeatures &
@@ -162,7 +162,8 @@
mStateForWindow.put(window.asBinder(), state);
}
- final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
+ final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE |
+ WindowManagerGlobal.ADD_FLAG_USE_BLAST;
// Include whether the window is in touch mode.
return isInTouchMode() ? res | WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE : res;
@@ -222,6 +223,17 @@
return false;
}
+ /** Access to package members for SystemWindow leashing
+ * @hide
+ */
+ protected IBinder getWindowBinder(View rootView) {
+ final ViewRootImpl root = rootView.getViewRootImpl();
+ if (root == null) {
+ return null;
+ }
+ return root.mWindow.asBinder();
+ }
+
/** @hide */
@Nullable
protected SurfaceControl getSurfaceControl(View rootView) {
@@ -266,8 +278,8 @@
WindowManager.LayoutParams attrs = state.mParams;
if (viewFlags == View.VISIBLE) {
- t.setBufferSize(sc, getSurfaceWidth(attrs), getSurfaceHeight(attrs))
- .setOpaque(sc, isOpaque(attrs)).show(sc).apply();
+ outSurfaceSize.set(getSurfaceWidth(attrs), getSurfaceHeight(attrs));
+ t.setOpaque(sc, isOpaque(attrs)).show(sc).apply();
outSurfaceControl.copyFrom(sc, "WindowlessWindowManager.relayout");
} else {
t.hide(sc).apply();
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index fc95275..af21f81 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -726,4 +726,43 @@
}
}
}
+
+ /**
+ * A {@link ServiceConnector} that doesn't connect to anything.
+ *
+ * @param <T> the type of the {@link IInterface ipc interface} for the remote service
+ */
+ class NoOp<T extends IInterface> extends AndroidFuture<Object> implements ServiceConnector<T> {
+ {
+ completeExceptionally(new IllegalStateException("ServiceConnector is a no-op"));
+ }
+
+ @Override
+ public boolean run(@NonNull VoidJob<T> job) {
+ return false;
+ }
+
+ @Override
+ public AndroidFuture<Void> post(@NonNull VoidJob<T> job) {
+ return (AndroidFuture) this;
+ }
+
+ @Override
+ public <R> AndroidFuture<R> postForResult(@NonNull Job<T, R> job) {
+ return (AndroidFuture) this;
+ }
+
+ @Override
+ public <R> AndroidFuture<R> postAsync(@NonNull Job<T, CompletableFuture<R>> job) {
+ return (AndroidFuture) this;
+ }
+
+ @Override
+ public AndroidFuture<T> connect() {
+ return (AndroidFuture) this;
+ }
+
+ @Override
+ public void unbind() {}
+ }
}
diff --git a/core/java/com/android/internal/os/CPU_OWNERS b/core/java/com/android/internal/os/CPU_OWNERS
new file mode 100644
index 0000000..5d3473c
--- /dev/null
+++ b/core/java/com/android/internal/os/CPU_OWNERS
@@ -0,0 +1,3 @@
+connoro@google.com
+dplotnikov@google.com
+rslawik@google.com # Android Telemetry
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 1b07aa0..0aa54f5 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -1,5 +1,6 @@
per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
per-file *Zygote* = file:/ZYGOTE_OWNERS
+per-file *Cpu* = file:CPU_OWNERS
# BatteryStats
per-file BatterySipper.java = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index d196d4a..c8afea9 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -1091,4 +1091,11 @@
* fully-feature Memory Tagging, rather than the static Tagged Pointers.
*/
public static native boolean nativeSupportsTaggedPointers();
+
+ /**
+ * Returns the current native tagging level, as one of the
+ * MEMORY_TAG_LEVEL_* constants. Returns zero if no tagging is present, or
+ * we failed to determine the level.
+ */
+ public static native int nativeCurrentTaggingLevel();
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 94e21e5..f2ed50e 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -787,9 +787,19 @@
Zygote.applyInvokeWithSystemProperty(parsedArgs);
if (Zygote.nativeSupportsMemoryTagging()) {
- /* The system server is more privileged than regular app processes, so it has async
- * tag checks enabled on hardware that supports memory tagging. */
- parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
+ /* The system server has ASYNC MTE by default, in order to allow
+ * system services to specify their own MTE level later, as you
+ * can't re-enable MTE once it's disabled. */
+ String mode = SystemProperties.get("arm64.memtag.process.system_server", "async");
+ if (mode.equals("async")) {
+ parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
+ } else if (mode.equals("sync")) {
+ parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
+ } else if (!mode.equals("off")) {
+ /* When we have an invalid memory tag level, keep the current level. */
+ parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
+ Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
+ }
} else if (Zygote.nativeSupportsTaggedPointers()) {
/* Enable pointer tagging in the system server. Hardware support for this is present
* in all ARMv8 CPUs. */
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 2279d57..35d1d7b 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -5,6 +5,9 @@
# Connectivity
per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
+# CPU
+per-file *Cpu* = file:/core/java/com/android/internal/os/CPU_OWNERS
+
# Display
per-file android_hardware_display_* = file:/services/core/java/com/android/server/display/OWNERS
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 6337680..8977b97 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -40,7 +40,7 @@
jmethodID dispatchVsync;
jmethodID dispatchHotplug;
- jmethodID dispatchConfigChanged;
+ jmethodID dispatchModeChanged;
jmethodID dispatchFrameRateOverrides;
struct {
@@ -69,8 +69,8 @@
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
VsyncEventData vsyncEventData) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
- void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
- int32_t configId, nsecs_t vsyncPeriod) override;
+ void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
+ nsecs_t vsyncPeriod) override;
void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
std::vector<FrameRateOverride> overrides) override;
void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
@@ -129,20 +129,19 @@
mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
}
-void NativeDisplayEventReceiver::dispatchConfigChanged(
- nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId, nsecs_t) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
+void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
+ int32_t modeId, nsecs_t) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
- ScopedLocalRef<jobject> receiverObj(env,
- jniGetReferent(env, mReceiverWeakGlobal));
- if (receiverObj.get()) {
- ALOGV("receiver %p ~ Invoking config changed handler.", this);
- env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchConfigChanged,
- timestamp, displayId.value, configId);
- ALOGV("receiver %p ~ Returned from config changed handler.", this);
- }
+ ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
+ if (receiverObj.get()) {
+ ALOGV("receiver %p ~ Invoking mode changed handler.", this);
+ env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeChanged,
+ timestamp, displayId.value, modeId);
+ ALOGV("receiver %p ~ Returned from mode changed handler.", this);
+ }
- mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
+ mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
}
void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
@@ -173,7 +172,7 @@
ALOGV("receiver %p ~ Returned from FrameRateOverride handler.", this);
}
- mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
+ mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
}
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
@@ -243,8 +242,9 @@
"(JJIJJ)V");
gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
- gDisplayEventReceiverClassInfo.dispatchConfigChanged = GetMethodIDOrDie(env,
- gDisplayEventReceiverClassInfo.clazz, "dispatchConfigChanged", "(JJI)V");
+ gDisplayEventReceiverClassInfo.dispatchModeChanged =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
+ "(JJI)V");
gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
"dispatchFrameRateOverrides",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8597308..7a3366a 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -44,8 +44,8 @@
#include <ui/BlurRegion.h>
#include <ui/ConfigStoreTypes.h>
#include <ui/DeviceProductInfo.h>
-#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
+#include <ui/DisplayMode.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/FrameStats.h>
#include <ui/GraphicTypes.h>
@@ -98,8 +98,8 @@
jfieldID refreshRate;
jfieldID appVsyncOffsetNanos;
jfieldID presentationDeadlineNanos;
- jfieldID configGroup;
-} gDisplayConfigClassInfo;
+ jfieldID group;
+} gDisplayModeClassInfo;
static struct {
jfieldID bottom;
@@ -202,13 +202,13 @@
static struct {
jclass clazz;
jmethodID ctor;
- jfieldID defaultConfig;
+ jfieldID defaultMode;
jfieldID allowGroupSwitching;
jfieldID primaryRefreshRateMin;
jfieldID primaryRefreshRateMax;
jfieldID appRequestRefreshRateMin;
jfieldID appRequestRefreshRateMax;
-} gDesiredDisplayConfigSpecsClassInfo;
+} gDesiredDisplayModeSpecsClassInfo;
static struct {
jclass clazz;
@@ -1028,101 +1028,97 @@
return object;
}
-static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz, jobject tokenObj) {
- Vector<DisplayConfig> configs;
+static jobjectArray nativeGetDisplayModes(JNIEnv* env, jclass clazz, jobject tokenObj) {
+ Vector<ui::DisplayMode> modes;
if (const auto token = ibinderForJavaObject(env, tokenObj); !token ||
- SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
- configs.isEmpty()) {
+ SurfaceComposerClient::getDisplayModes(token, &modes) != NO_ERROR || modes.isEmpty()) {
return nullptr;
}
- jobjectArray configArray =
- env->NewObjectArray(configs.size(), gDisplayConfigClassInfo.clazz, nullptr);
+ jobjectArray modesArray =
+ env->NewObjectArray(modes.size(), gDisplayModeClassInfo.clazz, nullptr);
- for (size_t c = 0; c < configs.size(); ++c) {
- const DisplayConfig& config = configs[c];
- jobject object =
- env->NewObject(gDisplayConfigClassInfo.clazz, gDisplayConfigClassInfo.ctor);
- env->SetIntField(object, gDisplayConfigClassInfo.width, config.resolution.getWidth());
- env->SetIntField(object, gDisplayConfigClassInfo.height, config.resolution.getHeight());
- env->SetFloatField(object, gDisplayConfigClassInfo.xDpi, config.xDpi);
- env->SetFloatField(object, gDisplayConfigClassInfo.yDpi, config.yDpi);
+ for (size_t c = 0; c < modes.size(); ++c) {
+ const ui::DisplayMode& mode = modes[c];
+ jobject object = env->NewObject(gDisplayModeClassInfo.clazz, gDisplayModeClassInfo.ctor);
+ env->SetIntField(object, gDisplayModeClassInfo.width, mode.resolution.getWidth());
+ env->SetIntField(object, gDisplayModeClassInfo.height, mode.resolution.getHeight());
+ env->SetFloatField(object, gDisplayModeClassInfo.xDpi, mode.xDpi);
+ env->SetFloatField(object, gDisplayModeClassInfo.yDpi, mode.yDpi);
- env->SetFloatField(object, gDisplayConfigClassInfo.refreshRate, config.refreshRate);
- env->SetLongField(object, gDisplayConfigClassInfo.appVsyncOffsetNanos,
- config.appVsyncOffset);
- env->SetLongField(object, gDisplayConfigClassInfo.presentationDeadlineNanos,
- config.presentationDeadline);
- env->SetIntField(object, gDisplayConfigClassInfo.configGroup, config.configGroup);
- env->SetObjectArrayElement(configArray, static_cast<jsize>(c), object);
+ env->SetFloatField(object, gDisplayModeClassInfo.refreshRate, mode.refreshRate);
+ env->SetLongField(object, gDisplayModeClassInfo.appVsyncOffsetNanos, mode.appVsyncOffset);
+ env->SetLongField(object, gDisplayModeClassInfo.presentationDeadlineNanos,
+ mode.presentationDeadline);
+ env->SetIntField(object, gDisplayModeClassInfo.group, mode.group);
+ env->SetObjectArrayElement(modesArray, static_cast<jsize>(c), object);
env->DeleteLocalRef(object);
}
- return configArray;
+ return modesArray;
}
-static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
- jobject desiredDisplayConfigSpecs) {
+static jboolean nativeSetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
+ jobject DesiredDisplayModeSpecs) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return JNI_FALSE;
- jint defaultConfig = env->GetIntField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.defaultConfig);
+ size_t defaultMode =
+ static_cast<size_t>(env->GetIntField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.defaultMode));
jboolean allowGroupSwitching =
- env->GetBooleanField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.allowGroupSwitching);
+ env->GetBooleanField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.allowGroupSwitching);
jfloat primaryRefreshRateMin =
- env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin);
+ env->GetFloatField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMin);
jfloat primaryRefreshRateMax =
- env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax);
+ env->GetFloatField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMax);
jfloat appRequestRefreshRateMin =
- env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin);
+ env->GetFloatField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMin);
jfloat appRequestRefreshRateMax =
- env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax);
+ env->GetFloatField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMax);
- size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(token, defaultConfig,
- allowGroupSwitching,
- primaryRefreshRateMin,
- primaryRefreshRateMax,
- appRequestRefreshRateMin,
- appRequestRefreshRateMax);
+ size_t result = SurfaceComposerClient::setDesiredDisplayModeSpecs(token, defaultMode,
+ allowGroupSwitching,
+ primaryRefreshRateMin,
+ primaryRefreshRateMax,
+ appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
-static jobject nativeGetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jobject tokenObj) {
+static jobject nativeGetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return nullptr;
- int32_t defaultConfig;
+ size_t defaultMode;
bool allowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
float appRequestRefreshRateMin;
float appRequestRefreshRateMax;
- if (SurfaceComposerClient::getDesiredDisplayConfigSpecs(token, &defaultConfig,
- &allowGroupSwitching,
- &primaryRefreshRateMin,
- &primaryRefreshRateMax,
- &appRequestRefreshRateMin,
- &appRequestRefreshRateMax) !=
- NO_ERROR) {
+ if (SurfaceComposerClient::getDesiredDisplayModeSpecs(token, &defaultMode, &allowGroupSwitching,
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax) != NO_ERROR) {
return nullptr;
}
- return env->NewObject(gDesiredDisplayConfigSpecsClassInfo.clazz,
- gDesiredDisplayConfigSpecsClassInfo.ctor, defaultConfig,
- allowGroupSwitching, primaryRefreshRateMin, primaryRefreshRateMax,
- appRequestRefreshRateMin, appRequestRefreshRateMax);
+ return env->NewObject(gDesiredDisplayModeSpecsClassInfo.clazz,
+ gDesiredDisplayModeSpecsClassInfo.ctor, defaultMode, allowGroupSwitching,
+ primaryRefreshRateMin, primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
}
-static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
+static jint nativeGetActiveDisplayMode(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return -1;
- return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
+ return static_cast<jint>(SurfaceComposerClient::getActiveDisplayModeId(token));
}
static jintArray nativeGetDisplayColorModes(JNIEnv* env, jclass, jobject tokenObj) {
@@ -1784,16 +1780,16 @@
(void*)nativeSetDisplaySize },
{"nativeGetDisplayInfo", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayInfo;",
(void*)nativeGetDisplayInfo },
- {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$DisplayConfig;",
- (void*)nativeGetDisplayConfigs },
- {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
- (void*)nativeGetActiveConfig },
- {"nativeSetDesiredDisplayConfigSpecs",
- "(Landroid/os/IBinder;Landroid/view/SurfaceControl$DesiredDisplayConfigSpecs;)Z",
- (void*)nativeSetDesiredDisplayConfigSpecs },
- {"nativeGetDesiredDisplayConfigSpecs",
- "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DesiredDisplayConfigSpecs;",
- (void*)nativeGetDesiredDisplayConfigSpecs },
+ {"nativeGetDisplayModes", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$DisplayMode;",
+ (void*)nativeGetDisplayModes },
+ {"nativeGetActiveDisplayMode", "(Landroid/os/IBinder;)I",
+ (void*)nativeGetActiveDisplayMode },
+ {"nativeSetDesiredDisplayModeSpecs",
+ "(Landroid/os/IBinder;Landroid/view/SurfaceControl$DesiredDisplayModeSpecs;)Z",
+ (void*)nativeSetDesiredDisplayModeSpecs },
+ {"nativeGetDesiredDisplayModeSpecs",
+ "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DesiredDisplayModeSpecs;",
+ (void*)nativeGetDesiredDisplayModeSpecs },
{"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
(void*)nativeGetDisplayColorModes},
{"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
@@ -1902,19 +1898,19 @@
GetFieldIDOrDie(env, infoClazz, "deviceProductInfo",
"Landroid/hardware/display/DeviceProductInfo;");
- jclass configClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayConfig");
- gDisplayConfigClassInfo.clazz = MakeGlobalRefOrDie(env, configClazz);
- gDisplayConfigClassInfo.ctor = GetMethodIDOrDie(env, configClazz, "<init>", "()V");
- gDisplayConfigClassInfo.width = GetFieldIDOrDie(env, configClazz, "width", "I");
- gDisplayConfigClassInfo.height = GetFieldIDOrDie(env, configClazz, "height", "I");
- gDisplayConfigClassInfo.xDpi = GetFieldIDOrDie(env, configClazz, "xDpi", "F");
- gDisplayConfigClassInfo.yDpi = GetFieldIDOrDie(env, configClazz, "yDpi", "F");
- gDisplayConfigClassInfo.refreshRate = GetFieldIDOrDie(env, configClazz, "refreshRate", "F");
- gDisplayConfigClassInfo.appVsyncOffsetNanos =
- GetFieldIDOrDie(env, configClazz, "appVsyncOffsetNanos", "J");
- gDisplayConfigClassInfo.presentationDeadlineNanos =
- GetFieldIDOrDie(env, configClazz, "presentationDeadlineNanos", "J");
- gDisplayConfigClassInfo.configGroup = GetFieldIDOrDie(env, configClazz, "configGroup", "I");
+ jclass modeClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayMode");
+ gDisplayModeClassInfo.clazz = MakeGlobalRefOrDie(env, modeClazz);
+ gDisplayModeClassInfo.ctor = GetMethodIDOrDie(env, modeClazz, "<init>", "()V");
+ gDisplayModeClassInfo.width = GetFieldIDOrDie(env, modeClazz, "width", "I");
+ gDisplayModeClassInfo.height = GetFieldIDOrDie(env, modeClazz, "height", "I");
+ gDisplayModeClassInfo.xDpi = GetFieldIDOrDie(env, modeClazz, "xDpi", "F");
+ gDisplayModeClassInfo.yDpi = GetFieldIDOrDie(env, modeClazz, "yDpi", "F");
+ gDisplayModeClassInfo.refreshRate = GetFieldIDOrDie(env, modeClazz, "refreshRate", "F");
+ gDisplayModeClassInfo.appVsyncOffsetNanos =
+ GetFieldIDOrDie(env, modeClazz, "appVsyncOffsetNanos", "J");
+ gDisplayModeClassInfo.presentationDeadlineNanos =
+ GetFieldIDOrDie(env, modeClazz, "presentationDeadlineNanos", "J");
+ gDisplayModeClassInfo.group = GetFieldIDOrDie(env, modeClazz, "group", "I");
jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
@@ -2005,24 +2001,23 @@
gDisplayPrimariesClassInfo.white = GetFieldIDOrDie(env, displayPrimariesClazz, "white",
"Landroid/view/SurfaceControl$CieXyz;");
- jclass desiredDisplayConfigSpecsClazz =
- FindClassOrDie(env, "android/view/SurfaceControl$DesiredDisplayConfigSpecs");
- gDesiredDisplayConfigSpecsClassInfo.clazz =
- MakeGlobalRefOrDie(env, desiredDisplayConfigSpecsClazz);
- gDesiredDisplayConfigSpecsClassInfo.ctor =
- GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IZFFFF)V");
- gDesiredDisplayConfigSpecsClassInfo.defaultConfig =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "defaultConfig", "I");
- gDesiredDisplayConfigSpecsClassInfo.allowGroupSwitching =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "allowGroupSwitching", "Z");
- gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMin", "F");
- gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMax", "F");
- gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMin", "F");
- gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMax", "F");
+ jclass DesiredDisplayModeSpecsClazz =
+ FindClassOrDie(env, "android/view/SurfaceControl$DesiredDisplayModeSpecs");
+ gDesiredDisplayModeSpecsClassInfo.clazz = MakeGlobalRefOrDie(env, DesiredDisplayModeSpecsClazz);
+ gDesiredDisplayModeSpecsClassInfo.ctor =
+ GetMethodIDOrDie(env, gDesiredDisplayModeSpecsClassInfo.clazz, "<init>", "(IZFFFF)V");
+ gDesiredDisplayModeSpecsClassInfo.defaultMode =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "defaultMode", "I");
+ gDesiredDisplayModeSpecsClassInfo.allowGroupSwitching =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "allowGroupSwitching", "Z");
+ gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMin =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "primaryRefreshRateMin", "F");
+ gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMax =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "primaryRefreshRateMax", "F");
+ gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMin =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRefreshRateMin", "F");
+ gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMax =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRefreshRateMax", "F");
jclass captureArgsClazz = FindClassOrDie(env, "android/view/SurfaceControl$CaptureArgs");
gCaptureArgsClassInfo.pixelFormat = GetFieldIDOrDie(env, captureArgsClazz, "mPixelFormat", "I");
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 3d1c38d..e801725 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -2506,6 +2506,36 @@
#endif
}
+static jint com_android_internal_os_Zygote_nativeCurrentTaggingLevel(JNIEnv* env, jclass) {
+#if defined(__aarch64__)
+ int level = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+ if (level < 0) {
+ ALOGE("Failed to get memory tag level: %s", strerror(errno));
+ return 0;
+ } else if (!(level & PR_TAGGED_ADDR_ENABLE)) {
+ return 0;
+ }
+ // TBI is only possible on non-MTE hardware.
+ if (!mte_supported()) {
+ return MEMORY_TAG_LEVEL_TBI;
+ }
+
+ switch (level & PR_MTE_TCF_MASK) {
+ case PR_MTE_TCF_NONE:
+ return 0;
+ case PR_MTE_TCF_SYNC:
+ return MEMORY_TAG_LEVEL_SYNC;
+ case PR_MTE_TCF_ASYNC:
+ return MEMORY_TAG_LEVEL_ASYNC;
+ default:
+ ALOGE("Unknown memory tagging level: %i", level);
+ return 0;
+ }
+#else // defined(__aarch64__)
+ return 0;
+#endif // defined(__aarch64__)
+}
+
static const JNINativeMethod gMethods[] = {
{"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
@@ -2545,6 +2575,8 @@
(void*)com_android_internal_os_Zygote_nativeSupportsMemoryTagging},
{"nativeSupportsTaggedPointers", "()Z",
(void*)com_android_internal_os_Zygote_nativeSupportsTaggedPointers},
+ {"nativeCurrentTaggingLevel", "()I",
+ (void*)com_android_internal_os_Zygote_nativeCurrentTaggingLevel},
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/res/res/layout/notification_template_part_chronometer.xml b/core/res/res/layout/notification_template_part_chronometer.xml
index c5ffbea..e4ebc76 100644
--- a/core/res/res/layout/notification_template_part_chronometer.xml
+++ b/core/res/res/layout/notification_template_part_chronometer.xml
@@ -15,7 +15,7 @@
-->
<Chronometer android:id="@+id/chronometer" xmlns:android="http://schemas.android.com/apk/res/android"
- android:textAppearance="@style/TextAppearance.Material.Notification.Time"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 25e7951..8c5f454 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3477,6 +3477,11 @@
<!-- The alarm window (in milliseconds) that JobScheduler uses to enter the idle state -->
<integer name="config_jobSchedulerIdleWindowSlop">300000</integer>
+ <!-- If true, jobs from background user will be restricted -->
+ <bool name="config_jobSchedulerRestrictBackgroundUser">false</bool>
+ <!-- The length of grace period after user becomes background user -->
+ <integer name="config_jobSchedulerUserGracePeriod">60000</integer>
+
<!-- If true, all guest users created on the device will be ephemeral. -->
<bool name="config_guestUserEphemeral">false</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f6d1b7d..9b5f670 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4532,9 +4532,8 @@
shown in the warning dialog about the accessibility shortcut. -->
<string name="color_correction_feature_name">Color Correction</string>
- <!-- TODO(b/170970602): remove translatable=false when RBC has official name and strings -->
- <!-- Title of Reduce Bright Colors feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] -->
- <string name="reduce_bright_colors_feature_name" translatable="false">Reduce Bright Colors</string>
+ <!-- Title of Reduce Brightness feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] -->
+ <string name="reduce_bright_colors_feature_name">Reduce Brightness</string>
<!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility service. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_enabling_service">Held volume keys. <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> turned on.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9a165bb..c41b78e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2680,6 +2680,8 @@
<java-symbol type="integer" name="config_jobSchedulerInactivityIdleThreshold" />
<java-symbol type="integer" name="config_jobSchedulerIdleWindowSlop" />
+ <java-symbol type="bool" name="config_jobSchedulerRestrictBackgroundUser" />
+ <java-symbol type="integer" name="config_jobSchedulerUserGracePeriod" />
<java-symbol type="style" name="Animation.ImmersiveModeConfirmation" />
diff --git a/core/tests/coretests/src/com/android/internal/os/OWNERS b/core/tests/coretests/src/com/android/internal/os/OWNERS
index 4068e2b..3f8f9e2 100644
--- a/core/tests/coretests/src/com/android/internal/os/OWNERS
+++ b/core/tests/coretests/src/com/android/internal/os/OWNERS
@@ -1 +1,4 @@
include /BATTERY_STATS_OWNERS
+
+# CPU
+per-file *Cpu* = file:/core/java/com/android/internal/os/CPU_OWNERS
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 1ed5490..0484a9a 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -487,6 +487,8 @@
<permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/>
<!-- Permissions required for quick settings tile -->
<permission name="android.permission.STATUS_BAR"/>
+ <!-- Permissions required to query Betterbug -->
+ <permission name="android.permission.QUERY_ALL_PACKAGES"/>
</privapp-permissions>
<privapp-permissions package="com.android.tv">
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 9214ff1..b153c99 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -26,8 +26,7 @@
import android.graphics.RectF;
import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
-import android.util.Log;
-import android.util.LongSparseArray;
+import android.text.TextUtils;
import android.util.LongSparseLongArray;
import android.util.TypedValue;
@@ -44,7 +43,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
@@ -61,14 +59,9 @@
private static final int STYLE_ITALIC = 1;
private static final int STYLE_NORMAL = 0;
- private static final Object MAP_LOCK = new Object();
- // We need to have mapping from native ptr to Font object for later accessing from TextShape
- // result since Typeface doesn't have reference to Font object and it is not always created from
- // Font object. Sometimes Typeface is created in native layer only and there might not be Font
- // object in Java layer. So, if not found in this cache, create new Font object for API user.
- @GuardedBy("MAP_LOCK")
- private static final LongSparseArray<WeakReference<Font>> FONT_PTR_MAP =
- new LongSparseArray<>();
+ private static final NativeAllocationRegistry BUFFER_REGISTRY =
+ NativeAllocationRegistry.createMalloced(
+ ByteBuffer.class.getClassLoader(), nGetReleaseNativeFont());
private static final Object SOURCE_ID_LOCK = new Object();
@GuardedBy("SOURCE_ID_LOCK")
@@ -79,9 +72,7 @@
* A builder class for creating new Font.
*/
public static final class Builder {
- private static final NativeAllocationRegistry sFontRegistry =
- NativeAllocationRegistry.createMalloced(Font.class.getClassLoader(),
- nGetReleaseNativeFont());
+
private @Nullable ByteBuffer mBuffer;
private @Nullable File mFile;
@@ -484,26 +475,15 @@
final String filePath = mFile == null ? "" : mFile.getAbsolutePath();
long ptr;
- int fontIdentifier;
+ final Font font;
if (mFont == null) {
ptr = nBuild(builderPtr, readonlyBuffer, filePath, mLocaleList, mWeight, italic,
mTtcIndex);
- long fontBufferPtr = nGetFontBufferAddress(ptr);
- synchronized (SOURCE_ID_LOCK) {
- long id = FONT_SOURCE_ID_MAP.get(fontBufferPtr, -1);
- if (id == -1) {
- id = FONT_SOURCE_ID_MAP.size();
- FONT_SOURCE_ID_MAP.put(fontBufferPtr, id);
- }
- fontIdentifier = (int) id;
- }
+ font = new Font(ptr);
} else {
ptr = nClone(mFont.getNativePtr(), builderPtr, mWeight, italic, mTtcIndex);
- fontIdentifier = mFont.mSourceIdentifier;
+ font = new Font(ptr);
}
- final Font font = new Font(ptr, readonlyBuffer, mFile,
- new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList, fontIdentifier);
- sFontRegistry.registerNativeAllocation(font, ptr);
return font;
}
@@ -525,33 +505,32 @@
}
private final long mNativePtr; // address of the shared ptr of minikin::Font
- private final @NonNull ByteBuffer mBuffer;
- private final @Nullable File mFile;
- private final FontStyle mFontStyle;
- private final @IntRange(from = 0) int mTtcIndex;
- private final @Nullable FontVariationAxis[] mAxes;
- private final @NonNull String mLocaleList;
- private final int mSourceIdentifier; // An identifier of font source data.
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private @NonNull ByteBuffer mBuffer = null;
+ @GuardedBy("mLock")
+ private boolean mIsFileInitialized = false;
+ @GuardedBy("mLock")
+ private @Nullable File mFile = null;
+ @GuardedBy("mLock")
+ private FontStyle mFontStyle = null;
+ @GuardedBy("mLock")
+ private @Nullable FontVariationAxis[] mAxes = null;
+ @GuardedBy("mLock")
+ private @NonNull LocaleList mLocaleList = null;
+ @GuardedBy("mLock")
+ private int mSourceIdentifier = -1;
/**
* Use Builder instead
+ *
+ * Caller must increment underlying minikin::Font ref count.
+ *
+ * @hide
*/
- private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file,
- @NonNull FontStyle fontStyle, @IntRange(from = 0) int ttcIndex,
- @Nullable FontVariationAxis[] axes, @NonNull String localeList,
- int sourceIdentifier) {
- mBuffer = buffer;
- mFile = file;
- mFontStyle = fontStyle;
+ public Font(long nativePtr) {
mNativePtr = nativePtr;
- mTtcIndex = ttcIndex;
- mAxes = axes;
- mLocaleList = localeList;
- mSourceIdentifier = sourceIdentifier;
-
- synchronized (MAP_LOCK) {
- FONT_PTR_MAP.append(nGetNativeFontPtr(mNativePtr), new WeakReference<>(this));
- }
}
/**
@@ -563,7 +542,22 @@
* @return a font buffer
*/
public @NonNull ByteBuffer getBuffer() {
- return mBuffer;
+ synchronized (mLock) {
+ if (mBuffer == null) {
+ // Create new instance of native FontWrapper, i.e. incrementing ref count of
+ // minikin Font instance for keeping buffer fo ByteBuffer reference which may live
+ // longer than this object.
+ long ref = nCloneFont(mNativePtr);
+ ByteBuffer fromNative = nNewByteBuffer(mNativePtr);
+
+ // Bind ByteBuffer's lifecycle with underlying font object.
+ BUFFER_REGISTRY.registerNativeAllocation(fromNative, ref);
+
+ // JNI NewDirectBuffer creates writable ByteBuffer even if it is mmaped readonly.
+ mBuffer = fromNative.asReadOnlyBuffer();
+ }
+ return mBuffer;
+ }
}
/**
@@ -574,7 +568,16 @@
* @return a file path of the font
*/
public @Nullable File getFile() {
- return mFile;
+ synchronized (mLock) {
+ if (!mIsFileInitialized) {
+ String path = nGetFontPath(mNativePtr);
+ if (!TextUtils.isEmpty(path)) {
+ mFile = new File(path);
+ }
+ mIsFileInitialized = true;
+ }
+ return mFile;
+ }
}
/**
@@ -585,7 +588,16 @@
* @return a font style
*/
public @NonNull FontStyle getStyle() {
- return mFontStyle;
+ synchronized (mLock) {
+ if (mFontStyle == null) {
+ int packedStyle = nGetPackedStyle(mNativePtr);
+ mFontStyle = new FontStyle(
+ FontFileUtil.unpackWeight(packedStyle),
+ FontFileUtil.unpackItalic(packedStyle)
+ ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
+ }
+ return mFontStyle;
+ }
}
/**
@@ -597,7 +609,7 @@
* @return a TTC index value
*/
public @IntRange(from = 0) int getTtcIndex() {
- return mTtcIndex;
+ return nGetIndex(mNativePtr);
}
/**
@@ -608,7 +620,23 @@
* @return font variation settings
*/
public @Nullable FontVariationAxis[] getAxes() {
- return mAxes == null ? null : mAxes.clone();
+ synchronized (mLock) {
+ if (mAxes == null) {
+ int axisCount = nGetAxisCount(mNativePtr);
+ mAxes = new FontVariationAxis[axisCount];
+ char[] charBuffer = new char[4];
+ for (int i = 0; i < axisCount; ++i) {
+ long packedAxis = nGetAxisInfo(mNativePtr, i);
+ float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
+ charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >>> 56);
+ charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >>> 48);
+ charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >>> 40);
+ charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >>> 32);
+ mAxes[i] = new FontVariationAxis(new String(charBuffer), value);
+ }
+ }
+ }
+ return mAxes;
}
/**
@@ -618,7 +646,17 @@
* @return a locale list
*/
public @NonNull LocaleList getLocaleList() {
- return LocaleList.forLanguageTags(mLocaleList);
+ synchronized (mLock) {
+ if (mLocaleList == null) {
+ String langTags = nGetLocaleList(mNativePtr);
+ if (TextUtils.isEmpty(langTags)) {
+ mLocaleList = LocaleList.getEmptyLocaleList();
+ } else {
+ mLocaleList = LocaleList.forLanguageTags(langTags);
+ }
+ }
+ return mLocaleList;
+ }
}
/**
@@ -713,7 +751,20 @@
* @return an unique identifier for the font source data.
*/
public int getSourceIdentifier() {
- return mSourceIdentifier;
+ synchronized (mLock) {
+ if (mSourceIdentifier == -1) {
+ long bufferAddress = nGetBufferAddress(mNativePtr);
+ synchronized (SOURCE_ID_LOCK) {
+ long id = FONT_SOURCE_ID_MAP.get(bufferAddress, -1);
+ if (id == -1) {
+ id = FONT_SOURCE_ID_MAP.size();
+ FONT_SOURCE_ID_MAP.append(bufferAddress, id);
+ }
+ mSourceIdentifier = (int) id;
+ }
+ }
+ return mSourceIdentifier;
+ }
}
/**
@@ -736,13 +787,16 @@
private boolean isSameSource(@NonNull Font other) {
Objects.requireNonNull(other);
+ ByteBuffer myBuffer = getBuffer();
+ ByteBuffer otherBuffer = other.getBuffer();
+
// Shortcut for the same instance.
- if (mBuffer == other.mBuffer) {
+ if (myBuffer == otherBuffer) {
return true;
}
// Shortcut for different font buffer check by comparing size.
- if (mBuffer.capacity() != other.mBuffer.capacity()) {
+ if (myBuffer.capacity() != otherBuffer.capacity()) {
return false;
}
@@ -750,15 +804,15 @@
// underlying native font object holds buffer address, check if this buffer points exactly
// the same address as a shortcut of equality. For being compatible with of API30 or before,
// check buffer position even if the buffer points the same address.
- if (mSourceIdentifier == other.mSourceIdentifier
- && mBuffer.position() == other.mBuffer.position()) {
+ if (getSourceIdentifier() == other.getSourceIdentifier()
+ && myBuffer.position() == otherBuffer.position()) {
return true;
}
// Unfortunately, need to compare bytes one-by-one since the buffer may be different font
// file but has the same file size, or two font has same content but they are allocated
// differently. For being compatible with API30 ore before, compare with ByteBuffer#equals.
- return mBuffer.equals(other.mBuffer);
+ return myBuffer.equals(otherBuffer);
}
@Override
@@ -769,10 +823,20 @@
if (!(o instanceof Font)) {
return false;
}
+
Font f = (Font) o;
- boolean paramEqual = mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex
- && Arrays.equals(f.mAxes, mAxes) && Objects.equals(f.mLocaleList, mLocaleList)
- && Objects.equals(mFile, f.mFile);
+
+ // The underlying minikin::Font object is the source of the truth of font information. Thus,
+ // Pointer equality is the object equality.
+ if (nGetMinikinFontPtr(mNativePtr) == nGetMinikinFontPtr(f.mNativePtr)) {
+ return true;
+ }
+
+ boolean paramEqual = f.getStyle().equals(getStyle())
+ && f.getTtcIndex() == getTtcIndex()
+ && Arrays.equals(f.getAxes(), getAxes())
+ && Objects.equals(f.getLocaleList(), getLocaleList())
+ && Objects.equals(getFile(), f.getFile());
if (!paramEqual) {
return false;
@@ -784,64 +848,42 @@
@Override
public int hashCode() {
return Objects.hash(
- mFontStyle,
- mTtcIndex,
- Arrays.hashCode(mAxes),
+ getStyle(),
+ getTtcIndex(),
+ Arrays.hashCode(getAxes()),
// Use Buffer size instead of ByteBuffer#hashCode since ByteBuffer#hashCode traverse
// data which is not performant e.g. for HashMap. The hash collision are less likely
// happens because it is unlikely happens the different font files has exactly the
// same size.
- mLocaleList);
+ getLocaleList());
}
@Override
public String toString() {
return "Font {"
- + "path=" + mFile
- + ", style=" + mFontStyle
- + ", ttcIndex=" + mTtcIndex
- + ", axes=" + FontVariationAxis.toFontVariationSettings(mAxes)
- + ", localeList=" + mLocaleList
- + ", buffer=" + mBuffer
+ + "path=" + getFile()
+ + ", style=" + getStyle()
+ + ", ttcIndex=" + getTtcIndex()
+ + ", axes=" + FontVariationAxis.toFontVariationSettings(getAxes())
+ + ", localeList=" + getLocaleList()
+ + ", buffer=" + getBuffer()
+ "}";
}
- /**
- * Lookup Font object from native pointer or create new one if not found.
- * @hide
- */
- public static Font findOrCreateFontFromNativePtr(long ptr) {
- // First, lookup from known mapps.
- synchronized (MAP_LOCK) {
- WeakReference<Font> fontRef = FONT_PTR_MAP.get(ptr);
- if (fontRef != null) {
- Font font = fontRef.get();
- if (font != null) {
- return font;
- }
- }
+ @CriticalNative
+ private static native long nGetMinikinFontPtr(long font);
- // If not found, create Font object from native object for Java API users.
- ByteBuffer buffer = NativeFontBufferHelper.refByteBuffer(ptr);
- NativeFont.Font font = NativeFont.readNativeFont(ptr);
+ @CriticalNative
+ private static native long nCloneFont(long font);
- Font.Builder builder = new Font.Builder(buffer, font.getFile(), "")
- .setWeight(font.getStyle().getWeight())
- .setSlant(font.getStyle().getSlant())
- .setTtcIndex(font.getIndex())
- .setFontVariationSettings(font.getAxes());
+ @FastNative
+ private static native ByteBuffer nNewByteBuffer(long font);
- Font newFont = null;
- try {
- newFont = builder.build();
- FONT_PTR_MAP.append(ptr, new WeakReference<>(newFont));
- } catch (IOException e) {
- // This must not happen since the buffer was already created once.
- Log.e("Font", "Failed to create font object from existing buffer.", e);
- }
- return newFont;
- }
- }
+ @CriticalNative
+ private static native long nGetBufferAddress(long font);
+
+ @CriticalNative
+ private static native long nGetReleaseNativeFont();
@FastNative
private static native float nGetGlyphBounds(long font, int glyphId, long paint, RectF rect);
@@ -849,9 +891,21 @@
@FastNative
private static native float nGetFontMetrics(long font, long paint, Paint.FontMetrics metrics);
- @CriticalNative
- private static native long nGetNativeFontPtr(long ptr);
+ @FastNative
+ private static native String nGetFontPath(long fontPtr);
+
+ @FastNative
+ private static native String nGetLocaleList(long familyPtr);
@CriticalNative
- private static native long nGetFontBufferAddress(long font);
+ private static native int nGetPackedStyle(long fontPtr);
+
+ @CriticalNative
+ private static native int nGetIndex(long fontPtr);
+
+ @CriticalNative
+ private static native int nGetAxisCount(long fontPtr);
+
+ @CriticalNative
+ private static native long nGetAxisInfo(long fontPtr, int i);
}
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 77f86fe..8c13d3e 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -143,12 +143,10 @@
private static native long nGetReleaseNativeFamily();
}
- private final ArrayList<Font> mFonts;
private final long mNativePtr;
// Use Builder instead.
private FontFamily(@NonNull ArrayList<Font> fonts, long ptr) {
- mFonts = fonts;
mNativePtr = ptr;
}
@@ -176,7 +174,10 @@
* @return a registered font
*/
public @NonNull Font getFont(@IntRange(from = 0) int index) {
- return mFonts.get(index);
+ if (index < 0 || getSize() <= index) {
+ throw new IndexOutOfBoundsException();
+ }
+ return new Font(nGetFont(mNativePtr, index));
}
/**
@@ -185,7 +186,7 @@
* @return the number of fonts registered in this family.
*/
public @IntRange(from = 1) int getSize() {
- return mFonts.size();
+ return nGetFontSize(mNativePtr);
}
/** @hide */
@@ -193,6 +194,12 @@
return mNativePtr;
}
+ @CriticalNative
+ private static native int nGetFontSize(long family);
+
+ @CriticalNative
+ private static native long nGetFont(long family, int i);
+
@FastNative
private static native String nGetLangTags(long family);
diff --git a/graphics/java/android/graphics/fonts/NativeFont.java b/graphics/java/android/graphics/fonts/NativeFont.java
deleted file mode 100644
index 9e9d76a..0000000
--- a/graphics/java/android/graphics/fonts/NativeFont.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics.fonts;
-
-import android.graphics.Typeface;
-
-import dalvik.annotation.optimization.CriticalNative;
-import dalvik.annotation.optimization.FastNative;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Read native font objects.
- *
- * @hide
- */
-public class NativeFont {
-
- /**
- * Represents native font object.
- */
- public static final class Font {
- private final File mFile;
- private final int mIndex;
- private final FontVariationAxis[] mAxes;
- private final FontStyle mStyle;
-
- public Font(File file, int index, FontVariationAxis[] axes, FontStyle style) {
- mFile = file;
- mIndex = index;
- mAxes = axes;
- mStyle = style;
- }
-
- public File getFile() {
- return mFile;
- }
-
- public FontVariationAxis[] getAxes() {
- return mAxes;
- }
-
- public FontStyle getStyle() {
- return mStyle;
- }
-
- public int getIndex() {
- return mIndex;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Font font = (Font) o;
- return mIndex == font.mIndex && mFile.equals(font.mFile)
- && Arrays.equals(mAxes, font.mAxes) && mStyle.equals(font.mStyle);
- }
-
- @Override
- public int hashCode() {
- int result = Objects.hash(mFile, mIndex, mStyle);
- result = 31 * result + Arrays.hashCode(mAxes);
- return result;
- }
- }
-
- /**
- * Represents native font family object.
- */
- public static final class Family {
- private final List<Font> mFonts;
- private final String mLocale;
-
- public Family(List<Font> fonts, String locale) {
- mFonts = fonts;
- mLocale = locale;
- }
-
- public List<Font> getFonts() {
- return mFonts;
- }
-
- public String getLocale() {
- return mLocale;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Family family = (Family) o;
- return mFonts.equals(family.mFonts) && mLocale.equals(family.mLocale);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mFonts, mLocale);
- }
- }
-
- /**
- * Get underlying font families from Typeface
- *
- * @param typeface a typeface
- * @return list of family
- */
- public static List<Family> readTypeface(Typeface typeface) {
- int familyCount = nGetFamilyCount(typeface.native_instance);
- List<Family> result = new ArrayList<>(familyCount);
- for (int i = 0; i < familyCount; ++i) {
- result.add(readNativeFamily(nGetFamily(typeface.native_instance, i)));
- }
- return result;
- }
-
- /**
- * Read family object from native pointer
- *
- * @param familyPtr a font family pointer
- * @return a family
- */
- public static Family readNativeFamily(long familyPtr) {
- int fontCount = nGetFontCount(familyPtr);
- List<Font> result = new ArrayList<>(fontCount);
- for (int i = 0; i < fontCount; ++i) {
- result.add(readNativeFont(nGetFont(familyPtr, i)));
- }
- String localeList = nGetLocaleList(familyPtr);
- return new Family(result, localeList);
- }
-
- /**
- * Read font object from native pointer.
- *
- * @param ptr a font pointer
- * @return a font
- */
- public static Font readNativeFont(long ptr) {
- long packed = nGetFontInfo(ptr);
- int weight = (int) (packed & 0x0000_0000_0000_FFFFL);
- boolean italic = (packed & 0x0000_0000_0001_0000L) != 0;
- int ttcIndex = (int) ((packed & 0x0000_FFFF_0000_0000L) >> 32);
- int axisCount = (int) ((packed & 0xFFFF_0000_0000_0000L) >> 48);
- FontVariationAxis[] axes = new FontVariationAxis[axisCount];
- char[] charBuffer = new char[4];
- for (int i = 0; i < axisCount; ++i) {
- long packedAxis = nGetAxisInfo(ptr, i);
- float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
- charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >> 56);
- charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >> 48);
- charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >> 40);
- charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >> 32);
- axes[i] = new FontVariationAxis(new String(charBuffer), value);
- }
- String path = nGetFontPath(ptr);
- File file = (path == null) ? null : new File(path);
- FontStyle style = new FontStyle(weight,
- italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
-
- return new Font(file, ttcIndex, axes, style);
- }
-
- @CriticalNative
- private static native int nGetFamilyCount(long ptr);
-
- @CriticalNative
- private static native long nGetFamily(long ptr, int index);
-
- @FastNative
- private static native String nGetLocaleList(long familyPtr);
-
- @CriticalNative
- private static native long nGetFont(long familyPtr, int fontIndex);
-
- @CriticalNative
- private static native int nGetFontCount(long familyPtr);
-
- @CriticalNative
- private static native long nGetFontInfo(long fontPtr);
-
- @CriticalNative
- private static native long nGetAxisInfo(long fontPtr, int i);
-
- @FastNative
- private static native String nGetFontPath(long fontPtr);
-}
diff --git a/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java b/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java
deleted file mode 100644
index 5655e7f..0000000
--- a/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics.fonts;
-
-import android.annotation.NonNull;
-
-import dalvik.annotation.optimization.CriticalNative;
-import dalvik.annotation.optimization.FastNative;
-
-import libcore.util.NativeAllocationRegistry;
-
-import java.nio.ByteBuffer;
-
-/**
- * This is a helper class for showing native allocated buffer in Java API.
- *
- * @hide
- */
-public class NativeFontBufferHelper {
- private NativeFontBufferHelper() {}
-
- private static final NativeAllocationRegistry REGISTRY =
- NativeAllocationRegistry.createMalloced(
- ByteBuffer.class.getClassLoader(), nGetReleaseFunc());
-
- /**
- * Wrap native buffer with ByteBuffer with adding reference to it.
- */
- public static @NonNull ByteBuffer refByteBuffer(long fontPtr) {
- long refPtr = nRefFontBuffer(fontPtr);
- ByteBuffer buffer = nWrapByteBuffer(refPtr);
-
- // Releasing native object so that decreasing shared pointer ref count when the byte buffer
- // is GCed.
- REGISTRY.registerNativeAllocation(buffer, refPtr);
-
- return buffer;
- }
-
- @CriticalNative
- private static native long nRefFontBuffer(long fontPtr);
-
- @FastNative
- private static native ByteBuffer nWrapByteBuffer(long refPtr);
-
- @CriticalNative
- private static native long nGetReleaseFunc();
-}
diff --git a/graphics/java/android/graphics/text/PositionedGlyphs.java b/graphics/java/android/graphics/text/PositionedGlyphs.java
index c2de0ac..8d20e9c 100644
--- a/graphics/java/android/graphics/text/PositionedGlyphs.java
+++ b/graphics/java/android/graphics/text/PositionedGlyphs.java
@@ -184,7 +184,7 @@
long ptr = nGetFont(layoutPtr, i);
if (prevPtr != ptr) {
prevPtr = ptr;
- prevFont = Font.findOrCreateFontFromNativePtr(ptr);
+ prevFont = new Font(ptr);
}
mFonts.add(prevFont);
}
@@ -224,9 +224,7 @@
if (getGlyphId(i) != that.getGlyphId(i)) return false;
if (getGlyphX(i) != that.getGlyphX(i)) return false;
if (getGlyphY(i) != that.getGlyphY(i)) return false;
- // Intentionally using reference equality since font equality is heavy due to buffer
- // compare.
- if (getFont(i) != that.getFont(i)) return false;
+ if (!getFont(i).equals(that.getFont(i))) return false;
}
return true;
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml
index 93a6e7b..b581f55 100644
--- a/libs/WindowManager/Shell/res/layout/pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/pip_menu.xml
@@ -97,14 +97,4 @@
android:padding="@dimen/pip_resize_handle_padding"
android:src="@drawable/pip_resize_handle"
android:background="?android:selectableItemBackgroundBorderless" />
-
- <!-- invisible layer to trap the focus, b/169372603 -->
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- android:defaultFocusHighlightEnabled="false"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:focusedByDefault="true" />
-t </FrameLayout>
+</FrameLayout>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 616f24a..fb70cbe5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -40,9 +40,11 @@
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.view.SurfaceControlViewHost;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
import android.window.ClientWindowFrames;
@@ -251,6 +253,8 @@
public class SysUiWindowManager extends WindowlessWindowManager {
final int mDisplayId;
ContainerWindow mContainerWindow;
+ final HashMap<IBinder, SurfaceControl> mLeashForWindow =
+ new HashMap<IBinder, SurfaceControl>();
public SysUiWindowManager(int displayId, Context ctx, SurfaceControl rootSurface,
ContainerWindow container) {
super(ctx.getResources().getConfiguration(), rootSurface, null /* hostInputToken */);
@@ -263,7 +267,33 @@
}
SurfaceControl getSurfaceControlForWindow(View rootView) {
- return getSurfaceControl(rootView);
+ synchronized (this) {
+ return mLeashForWindow.get(getWindowBinder(rootView));
+ }
+ }
+
+ protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+ SurfaceControl leash = new SurfaceControl.Builder(new SurfaceSession())
+ .setContainerLayer()
+ .setName("SystemWindowLeash")
+ .setHidden(false)
+ .setParent(mRootSurface)
+ .setCallsite("SysUiWIndowManager#attachToParentSurface").build();
+ synchronized (this) {
+ mLeashForWindow.put(window.asBinder(), leash);
+ }
+ b.setParent(leash);
+ }
+
+ @Override
+ public void remove(android.view.IWindow window) throws RemoteException {
+ super.remove(window);
+ synchronized(this) {
+ IBinder token = window.asBinder();
+ new SurfaceControl.Transaction().remove(mLeashForWindow.get(token))
+ .apply();
+ mLeashForWindow.remove(token);
+ }
}
void setTouchableRegionForWindow(View rootView, Region region) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 7f9c34f..728f60d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -87,7 +87,7 @@
}
@Override
- protected void attachToParentSurface(SurfaceControl.Builder b) {
+ protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
mParentContainerCallbacks.attachToParentSurface(b);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
index e13a1db..a18d106 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
@@ -862,14 +862,6 @@
* assigned to it.
*/
private SurfaceControl getWindowSurfaceControl() {
- final ViewRootImpl root = getViewRootImpl();
- if (root == null) {
- return null;
- }
- SurfaceControl out = root.getSurfaceControl();
- if (out != null && out.isValid()) {
- return out;
- }
return mWindowManager.mSystemWindows.getViewSurface(this);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index a57eee8..ae53005 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -198,8 +198,7 @@
* {@code null}), it will get the leash that the WindowlessWM has assigned to it.
*/
public SurfaceControl getSurfaceControl() {
- SurfaceControl sf = mPipMenuView.getWindowSurfaceControl();
- return sf != null ? sf : mSystemWindows.getViewSurface(mPipMenuView);
+ return mSystemWindows.getViewSurface(mPipMenuView);
}
/**
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index 8258630..f06d57c 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -25,8 +25,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.wm.shell.flicker"/>
- <option name="include-annotation" value="androidx.test.filters.RequiresDevice" />
- <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6000s" />
<option name="hidden-api-checks" value="false" />
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index ce1d96c..f481228 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -335,7 +335,6 @@
"jni/YuvToJpegEncoder.cpp",
"jni/fonts/Font.cpp",
"jni/fonts/FontFamily.cpp",
- "jni/fonts/NativeFont.cpp",
"jni/text/LineBreaker.cpp",
"jni/text/MeasuredText.cpp",
"jni/text/TextShaper.cpp",
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index 0fad2d5..e1f5abd7 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -69,7 +69,6 @@
extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
extern int register_android_graphics_fonts_Font(JNIEnv* env);
extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
-extern int register_android_graphics_fonts_NativeFont(JNIEnv* env);
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
@@ -136,7 +135,6 @@
REG_JNI(register_android_graphics_drawable_VectorDrawable),
REG_JNI(register_android_graphics_fonts_Font),
REG_JNI(register_android_graphics_fonts_FontFamily),
- REG_JNI(register_android_graphics_fonts_NativeFont),
REG_JNI(register_android_graphics_pdf_PdfDocument),
REG_JNI(register_android_graphics_pdf_PdfEditor),
REG_JNI(register_android_graphics_pdf_PdfRenderer),
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index b769d40..3392dac 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -34,6 +34,7 @@
#include <hwui/Typeface.h>
#include <minikin/FontFamily.h>
#include <minikin/FontFileParser.h>
+#include <minikin/LocaleList.h>
#include <ui/FatVector.h>
#include <memory>
@@ -149,12 +150,8 @@
return reinterpret_cast<jlong>(new FontWrapper(std::move(newFont)));
}
-// Critical Native
-static jlong Font_Builder_getReleaseNativeFont(CRITICAL_JNI_PARAMS) {
- return reinterpret_cast<jlong>(releaseFont);
-}
-
///////////////////////////////////////////////////////////////////////////////
+// Font JNI functions
// Fast Native
static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
@@ -195,51 +192,92 @@
}
// Critical Native
-static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- return reinterpret_cast<jlong>(font->font.get());
+static jlong Font_getMinikinFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ return reinterpret_cast<jlong>(font->font->typeface().get());
}
// Critical Native
-static jlong Font_GetBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- const void* bufferPtr = font->font->typeface()->GetFontData();
- return reinterpret_cast<jlong>(bufferPtr);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-struct FontBufferWrapper {
- FontBufferWrapper(const std::shared_ptr<minikin::MinikinFont>& font) : minikinFont(font) {}
- // MinikinFont holds a shared pointer of SkTypeface which has reference to font data.
- std::shared_ptr<minikin::MinikinFont> minikinFont;
-};
-
-static void unrefBuffer(jlong nativePtr) {
- FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
- delete wrapper;
-}
-
-// Critical Native
-static jlong FontBufferHelper_refFontBuffer(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
- return reinterpret_cast<jlong>(new FontBufferWrapper(font->typeface()));
+static jlong Font_cloneFont(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ std::shared_ptr<minikin::Font> ref = font->font;
+ return reinterpret_cast<jlong>(new FontWrapper(std::move(ref)));
}
// Fast Native
-static jobject FontBufferHelper_wrapByteBuffer(JNIEnv* env, jobject, jlong nativePtr) {
- FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
- return env->NewDirectByteBuffer(
- const_cast<void*>(wrapper->minikinFont->GetFontData()),
- wrapper->minikinFont->GetFontSize());
+static jobject Font_newByteBuffer(JNIEnv* env, jobject, jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ return env->NewDirectByteBuffer(const_cast<void*>(minikinFont->GetFontData()),
+ minikinFont->GetFontSize());
}
// Critical Native
-static jlong FontBufferHelper_getReleaseFunc(CRITICAL_JNI_PARAMS) {
- return reinterpret_cast<jlong>(unrefBuffer);
+static jlong Font_getBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ return reinterpret_cast<jlong>(font->font->typeface()->GetFontData());
}
-///////////////////////////////////////////////////////////////////////////////
+// Critical Native
+static jlong Font_getReleaseNativeFontFunc() {
+ return reinterpret_cast<jlong>(releaseFont);
+}
+
+// Fast Native
+static jstring Font_getFontPath(JNIEnv* env, jobject, jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ const std::string& path = minikinFont->GetFontPath();
+ if (path.empty()) {
+ return nullptr;
+ }
+ return env->NewStringUTF(path.c_str());
+}
+
+// Fast Native
+static jstring Font_getLocaleList(JNIEnv* env, jobject, jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ uint32_t localeListId = font->font->getLocaleListId();
+ if (localeListId == 0) {
+ return nullptr;
+ }
+ std::string langTags = minikin::getLocaleString(localeListId);
+ if (langTags.empty()) {
+ return nullptr;
+ }
+ return env->NewStringUTF(langTags.c_str());
+}
+
+// Critical Native
+static jint Font_getPackedStyle(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ uint32_t weight = font->font->style().weight();
+ uint32_t isItalic = font->font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 1 : 0;
+ return (isItalic << 16) | weight;
+}
+
+// Critical Native
+static jint Font_getIndex(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ return minikinFont->GetFontIndex();
+}
+
+// Critical Native
+static jint Font_getAxisCount(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ return minikinFont->GetAxes().size();
+}
+
+// Critical Native
+static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr, jint index) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ minikin::FontVariation var = minikinFont->GetAxes().at(index);
+ uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
+ return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
+}
// Fast Native
static jlong FontFileUtil_getFontRevision(JNIEnv* env, jobject, jobject buffer, jint index) {
@@ -314,20 +352,23 @@
{"nBuild", "(JLjava/nio/ByteBuffer;Ljava/lang/String;Ljava/lang/String;IZI)J",
(void*)Font_Builder_build},
{"nClone", "(JJIZI)J", (void*)Font_Builder_clone},
- {"nGetReleaseNativeFont", "()J", (void*)Font_Builder_getReleaseNativeFont},
};
static const JNINativeMethod gFontMethods[] = {
- { "nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*) Font_getGlyphBounds },
- { "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
- { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
- { "nGetFontBufferAddress", "(J)J", (void*) Font_GetBufferAddress },
-};
-
-static const JNINativeMethod gFontBufferHelperMethods[] = {
- { "nRefFontBuffer", "(J)J", (void*) FontBufferHelper_refFontBuffer },
- { "nWrapByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*) FontBufferHelper_wrapByteBuffer },
- { "nGetReleaseFunc", "()J", (void*) FontBufferHelper_getReleaseFunc },
+ {"nGetMinikinFontPtr", "(J)J", (void*)Font_getMinikinFontPtr},
+ {"nCloneFont", "(J)J", (void*)Font_cloneFont},
+ {"nNewByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*)Font_newByteBuffer},
+ {"nGetBufferAddress", "(J)J", (void*)Font_getBufferAddress},
+ {"nGetReleaseNativeFont", "()J", (void*)Font_getReleaseNativeFontFunc},
+ {"nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*)Font_getGlyphBounds},
+ {"nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F",
+ (void*)Font_getFontMetrics},
+ {"nGetFontPath", "(J)Ljava/lang/String;", (void*)Font_getFontPath},
+ {"nGetLocaleList", "(J)Ljava/lang/String;", (void*)Font_getLocaleList},
+ {"nGetPackedStyle", "(J)I", (void*)Font_getPackedStyle},
+ {"nGetIndex", "(J)I", (void*)Font_getIndex},
+ {"nGetAxisCount", "(J)I", (void*)Font_getAxisCount},
+ {"nGetAxisInfo", "(JI)J", (void*)Font_getAxisInfo},
};
static const JNINativeMethod gFontFileUtilMethods[] = {
@@ -343,8 +384,6 @@
NELEM(gFontBuilderMethods)) +
RegisterMethodsOrDie(env, "android/graphics/fonts/Font", gFontMethods,
NELEM(gFontMethods)) +
- RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFontBufferHelper",
- gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods)) +
RegisterMethodsOrDie(env, "android/graphics/fonts/FontFileUtil", gFontFileUtilMethods,
NELEM(gFontFileUtilMethods));
}
diff --git a/libs/hwui/jni/fonts/FontFamily.cpp b/libs/hwui/jni/fonts/FontFamily.cpp
index 8fe6da318..8096479 100644
--- a/libs/hwui/jni/fonts/FontFamily.cpp
+++ b/libs/hwui/jni/fonts/FontFamily.cpp
@@ -100,17 +100,31 @@
return static_cast<jint>(family->family->variant());
}
+// CriticalNative
+static jint FontFamily_getFontSize(jlong familyPtr) {
+ FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
+ return family->family->getNumFonts();
+}
+
+// CriticalNative
+static jlong FontFamily_getFont(jlong familyPtr, jint index) {
+ FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
+ std::shared_ptr<minikin::Font> font = family->family->getFontRef(index);
+ return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
+}
+
///////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gFontFamilyBuilderMethods[] = {
{ "nInitBuilder", "()J", (void*) FontFamily_Builder_initBuilder },
{ "nAddFont", "(JJ)V", (void*) FontFamily_Builder_addFont },
{ "nBuild", "(JLjava/lang/String;IZ)J", (void*) FontFamily_Builder_build },
-
{ "nGetReleaseNativeFamily", "()J", (void*) FontFamily_Builder_GetReleaseFunc },
};
static const JNINativeMethod gFontFamilyMethods[] = {
+ {"nGetFontSize", "(J)I", (void*)FontFamily_getFontSize},
+ {"nGetFont", "(JI)J", (void*)FontFamily_getFont},
{"nGetLangTags", "(J)Ljava/lang/String;", (void*)FontFamily_getLangTags},
{"nGetVariant", "(J)I", (void*)FontFamily_getVariant},
};
diff --git a/libs/hwui/jni/fonts/NativeFont.cpp b/libs/hwui/jni/fonts/NativeFont.cpp
deleted file mode 100644
index c5c5d46..0000000
--- a/libs/hwui/jni/fonts/NativeFont.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "Minikin"
-
-#include "Font.h"
-#include "SkData.h"
-#include "SkFont.h"
-#include "SkFontMetrics.h"
-#include "SkFontMgr.h"
-#include "SkRefCnt.h"
-#include "SkTypeface.h"
-#include "GraphicsJNI.h"
-#include <nativehelper/ScopedUtfChars.h>
-#include "Utils.h"
-#include "FontUtils.h"
-
-#include <hwui/MinikinSkia.h>
-#include <hwui/Paint.h>
-#include <hwui/Typeface.h>
-#include <minikin/FontFamily.h>
-#include <minikin/LocaleList.h>
-#include <ui/FatVector.h>
-
-#include <memory>
-
-namespace android {
-
-// Critical Native
-static jint NativeFont_getFamilyCount(CRITICAL_JNI_PARAMS_COMMA jlong typefaceHandle) {
- Typeface* tf = reinterpret_cast<Typeface*>(typefaceHandle);
- return tf->fFontCollection->getFamilies().size();
-}
-
-// Critical Native
-static jlong NativeFont_getFamily(CRITICAL_JNI_PARAMS_COMMA jlong typefaceHandle, jint index) {
- Typeface* tf = reinterpret_cast<Typeface*>(typefaceHandle);
- return reinterpret_cast<jlong>(tf->fFontCollection->getFamilies()[index].get());
-
-}
-
-// Fast Native
-static jstring NativeFont_getLocaleList(JNIEnv* env, jobject, jlong familyHandle) {
- minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
- uint32_t localeListId = family->localeListId();
- return env->NewStringUTF(minikin::getLocaleString(localeListId).c_str());
-}
-
-// Critical Native
-static jint NativeFont_getFontCount(CRITICAL_JNI_PARAMS_COMMA jlong familyHandle) {
- minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
- return family->getNumFonts();
-}
-
-// Critical Native
-static jlong NativeFont_getFont(CRITICAL_JNI_PARAMS_COMMA jlong familyHandle, jint index) {
- minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
- return reinterpret_cast<jlong>(family->getFont(index));
-}
-
-// Critical Native
-static jlong NativeFont_getFontInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
-
- uint64_t result = font->style().weight();
- result |= font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 0x10000 : 0x00000;
- result |= ((static_cast<uint64_t>(minikinSkia->GetFontIndex())) << 32);
- result |= ((static_cast<uint64_t>(minikinSkia->GetAxes().size())) << 48);
- return result;
-}
-
-// Critical Native
-static jlong NativeFont_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle, jint index) {
- const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
- const minikin::FontVariation& var = minikinSkia->GetAxes().at(index);
- uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
- return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
-}
-
-// FastNative
-static jstring NativeFont_getFontPath(JNIEnv* env, jobject, jlong fontHandle) {
- const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
- const std::string& filePath = minikinSkia->getFilePath();
- if (filePath.empty()) {
- return nullptr;
- }
- return env->NewStringUTF(filePath.c_str());
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static const JNINativeMethod gNativeFontMethods[] = {
- { "nGetFamilyCount", "(J)I", (void*) NativeFont_getFamilyCount },
- { "nGetFamily", "(JI)J", (void*) NativeFont_getFamily },
- { "nGetLocaleList", "(J)Ljava/lang/String;", (void*) NativeFont_getLocaleList },
- { "nGetFontCount", "(J)I", (void*) NativeFont_getFontCount },
- { "nGetFont", "(JI)J", (void*) NativeFont_getFont },
- { "nGetFontInfo", "(J)J", (void*) NativeFont_getFontInfo },
- { "nGetAxisInfo", "(JI)J", (void*) NativeFont_getAxisInfo },
- { "nGetFontPath", "(J)Ljava/lang/String;", (void*) NativeFont_getFontPath },
-};
-
-int register_android_graphics_fonts_NativeFont(JNIEnv* env) {
- return RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFont", gNativeFontMethods,
- NELEM(gNativeFontMethods));
-}
-
-} // namespace android
diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp
index 9785aa5..a6fb958 100644
--- a/libs/hwui/jni/text/TextShaper.cpp
+++ b/libs/hwui/jni/text/TextShaper.cpp
@@ -23,13 +23,14 @@
#include <set>
#include <algorithm>
-#include "SkPaint.h"
-#include "SkTypeface.h"
#include <hwui/MinikinSkia.h>
#include <hwui/MinikinUtils.h>
#include <hwui/Paint.h>
-#include <minikin/MinikinPaint.h>
#include <minikin/MinikinFont.h>
+#include <minikin/MinikinPaint.h>
+#include "FontUtils.h"
+#include "SkPaint.h"
+#include "SkTypeface.h"
namespace android {
@@ -149,7 +150,8 @@
// CriticalNative
static jlong TextShaper_Result_getFont(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
- return reinterpret_cast<jlong>(layout->layout.getFont(i));
+ std::shared_ptr<minikin::Font> fontRef = layout->layout.getFontRef(i);
+ return reinterpret_cast<jlong>(new FontWrapper(std::move(fontRef)));
}
// CriticalNative
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index 06f158f..6a9a98d 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -40,9 +40,9 @@
return info;
}
-const DisplayConfig& getActiveDisplayConfig() {
- static DisplayConfig config = [] {
- DisplayConfig config;
+const ui::DisplayMode& getActiveDisplayMode() {
+ static ui::DisplayMode config = [] {
+ ui::DisplayMode config;
#if HWUI_NULL_GPU
config.resolution = ui::Size(1080, 1920);
config.xDpi = config.yDpi = 320.f;
@@ -51,7 +51,7 @@
const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
LOG_ALWAYS_FATAL_IF(!token, "%s: No internal display", __FUNCTION__);
- const status_t status = SurfaceComposerClient::getActiveDisplayConfig(token, &config);
+ const status_t status = SurfaceComposerClient::getActiveDisplayMode(token, &config);
LOG_ALWAYS_FATAL_IF(status, "%s: Failed to get active display config", __FUNCTION__);
#endif
return config;
diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h
index a012ecb..7d2f6d8 100644
--- a/libs/hwui/tests/common/TestContext.h
+++ b/libs/hwui/tests/common/TestContext.h
@@ -23,8 +23,8 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
-#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
+#include <ui/DisplayMode.h>
#include <utils/Looper.h>
#include <atomic>
@@ -37,10 +37,10 @@
namespace test {
const DisplayInfo& getDisplayInfo();
-const DisplayConfig& getActiveDisplayConfig();
+const ui::DisplayMode& getActiveDisplayMode();
inline const ui::Size& getActiveDisplayResolution() {
- return getActiveDisplayConfig().resolution;
+ return getActiveDisplayMode().resolution;
}
class TestContext {
diff --git a/libs/tracingproxy/Android.bp b/libs/tracingproxy/Android.bp
new file mode 100644
index 0000000..67f407f
--- /dev/null
+++ b/libs/tracingproxy/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Provides C++ wrappers for system services.
+
+cc_library_shared {
+ name: "libtracingproxy",
+
+ aidl: {
+ export_aidl_headers: true,
+ include_dirs: [
+ "frameworks/base/core/java",
+ ],
+ },
+
+ srcs: [
+ ":ITracingServiceProxy.aidl",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 65721cc..adf58da 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -36,6 +36,7 @@
import android.location.Location;
import android.location.LocationRequest;
import android.location.LocationTime;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.os.Bundle;
import android.os.ICancellationSignal;
@@ -91,6 +92,9 @@
void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, @nullable String attributionTag);
void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
+ void addProviderRequestListener(in IProviderRequestListener listener);
+ void removeProviderRequestListener(in IProviderRequestListener listener);
+
int getGnssBatchSize();
void startGnssBatch(long periodNanos, in ILocationListener listener, String packageName, @nullable String attributionTag, @nullable String listenerId);
void flushGnssBatch();
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index d569482..088b789 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -49,7 +49,10 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
+import android.location.provider.ProviderRequest;
+import android.location.provider.ProviderRequest.Listener;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -436,6 +439,9 @@
new GnssNavigationTransportManager();
}
+ private static final ProviderRequestTransportManager sProviderRequestListeners =
+ new ProviderRequestTransportManager();
+
private final Context mContext;
private final ILocationManager mService;
@@ -2772,6 +2778,37 @@
}
/**
+ * Registers a {@link ProviderRequest.Listener} to all providers.
+ *
+ * @param executor the executor that the callback runs on
+ * @param listener the listener to register
+ * @return {@code true} always
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public boolean registerProviderRequestListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Listener listener) {
+ sProviderRequestListeners.addListener(listener,
+ new ProviderRequestTransport(executor, listener));
+ return true;
+ }
+
+ /**
+ * Unregisters a {@link ProviderRequest.Listener}.
+ *
+ * @param listener the listener to remove.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public void unregisterProviderRequestListener(
+ @NonNull Listener listener) {
+ sProviderRequestListeners.removeListener(listener);
+ }
+
+ /**
* Returns the batch size (in number of Location objects) that are supported by the batching
* interface.
*
@@ -2960,6 +2997,22 @@
}
}
+ private static class ProviderRequestTransportManager extends
+ ListenerTransportManager<ProviderRequestTransport> {
+
+ @Override
+ protected void registerTransport(ProviderRequestTransport transport)
+ throws RemoteException {
+ getService().addProviderRequestListener(transport);
+ }
+
+ @Override
+ protected void unregisterTransport(ProviderRequestTransport transport)
+ throws RemoteException {
+ getService().removeProviderRequestListener(transport);
+ }
+ }
+
private static class GetCurrentLocationTransport extends ILocationCallback.Stub implements
ListenerExecutor, CancellationSignal.OnCancelListener {
@@ -3359,6 +3412,36 @@
}
}
+ private static class ProviderRequestTransport extends IProviderRequestListener.Stub
+ implements ListenerTransport<ProviderRequest.Listener> {
+
+ private final Executor mExecutor;
+
+ private volatile @Nullable ProviderRequest.Listener mListener;
+
+ ProviderRequestTransport(Executor executor, ProviderRequest.Listener listener) {
+ Preconditions.checkArgument(executor != null, "invalid null executor");
+ Preconditions.checkArgument(listener != null, "invalid null callback");
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void unregister() {
+ mListener = null;
+ }
+
+ @Override
+ public @Nullable ProviderRequest.Listener getListener() {
+ return mListener;
+ }
+
+ @Override
+ public void onProviderRequestChanged(String provider, ProviderRequest request) {
+ execute(mExecutor, listener -> listener.onProviderRequestChanged(provider, request));
+ }
+ }
+
private static class BatchedLocationCallbackWrapper implements LocationListener {
private final BatchedLocationCallback mCallback;
diff --git a/location/java/android/location/provider/IProviderRequestListener.aidl b/location/java/android/location/provider/IProviderRequestListener.aidl
new file mode 100644
index 0000000..89d454a
--- /dev/null
+++ b/location/java/android/location/provider/IProviderRequestListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location.provider;
+
+import android.location.provider.ProviderRequest;
+
+/**
+ * {@hide}
+ */
+oneway interface IProviderRequestListener {
+ void onProviderRequestChanged(String provider, in ProviderRequest request);
+}
diff --git a/location/java/android/location/provider/ProviderRequest.java b/location/java/android/location/provider/ProviderRequest.java
index e543b04..b6ec323 100644
--- a/location/java/android/location/provider/ProviderRequest.java
+++ b/location/java/android/location/provider/ProviderRequest.java
@@ -53,6 +53,17 @@
private final boolean mLocationSettingsIgnored;
private final WorkSource mWorkSource;
+ /**
+ * Listener to be invoked when a new request is set to the provider.
+ */
+ public interface Listener {
+
+ /**
+ * Invoked when a new request is set.
+ */
+ void onProviderRequestChanged(@NonNull String provider, @NonNull ProviderRequest request);
+ }
+
private ProviderRequest(
long intervalMillis,
@Quality int quality,
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 06bf5f7..9c6b276 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -119,9 +119,14 @@
*/
public static final int QUALITY_2K = 12;
+ /**
+ * Quality level corresponding to 8K UHD (7680 x 4320) resolution
+ */
+ public static final int QUALITY_8KUHD = 13;
+
// Start and end of quality list
private static final int QUALITY_LIST_START = QUALITY_LOW;
- private static final int QUALITY_LIST_END = QUALITY_2K;
+ private static final int QUALITY_LIST_END = QUALITY_8KUHD;
/**
* Time lapse quality level corresponding to the lowest available resolution.
@@ -188,10 +193,14 @@
*/
public static final int QUALITY_TIME_LAPSE_2K = 1012;
+ /**
+ * Time lapse quality level corresponding to the 8K UHD (7680 x 4320) resolution.
+ */
+ public static final int QUALITY_TIME_LAPSE_8KUHD = 1013;
// Start and end of timelapse quality list
private static final int QUALITY_TIME_LAPSE_LIST_START = QUALITY_TIME_LAPSE_LOW;
- private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_2K;
+ private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_8KUHD;
/**
* High speed ( >= 100fps) quality level corresponding to the lowest available resolution.
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 3b054e9..a746139 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -1368,7 +1368,7 @@
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
try {
return mService.getDefaultNetworkCapabilitiesForUser(
- userId, mContext.getOpPackageName());
+ userId, mContext.getOpPackageName(), getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1450,7 +1450,8 @@
@Nullable
public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
try {
- return mService.getNetworkCapabilities(network, mContext.getOpPackageName());
+ return mService.getNetworkCapabilities(
+ network, mContext.getOpPackageName(), getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3735,7 +3736,8 @@
Binder binder = new Binder();
if (reqType == LISTEN) {
request = mService.listenForNetwork(
- need, messenger, binder, callingPackageName);
+ need, messenger, binder, callingPackageName,
+ getAttributionTag());
} else {
request = mService.requestNetwork(
need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
@@ -4180,7 +4182,8 @@
checkPendingIntentNotNull(operation);
try {
mService.pendingListenForNetwork(
- request.networkCapabilities, operation, mContext.getOpPackageName());
+ request.networkCapabilities, operation, mContext.getOpPackageName(),
+ getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index e2672c4..f909d13 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -66,7 +66,7 @@
Network getNetworkForType(int networkType);
Network[] getAllNetworks();
NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
- int userId, String callingPackageName);
+ int userId, String callingPackageName, String callingAttributionTag);
boolean isNetworkSupported(int networkType);
@@ -75,7 +75,8 @@
LinkProperties getLinkPropertiesForType(int networkType);
LinkProperties getLinkProperties(in Network network);
- NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
+ NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName,
+ String callingAttributionTag);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
NetworkState[] getAllNetworkState();
@@ -176,10 +177,12 @@
void releasePendingNetworkRequest(in PendingIntent operation);
NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
- in Messenger messenger, in IBinder binder, String callingPackageName);
+ in Messenger messenger, in IBinder binder, String callingPackageName,
+ String callingAttributionTag);
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
- in PendingIntent operation, String callingPackageName);
+ in PendingIntent operation, String callingPackageName,
+ String callingAttributionTag);
void releaseNetworkRequest(in NetworkRequest networkRequest);
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index b9ef4c2..6540397 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -16,6 +16,22 @@
package android.net;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -30,6 +46,8 @@
import android.text.TextUtils;
import android.util.proto.ProtoOutputStream;
+import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -156,8 +174,30 @@
* needed in terms of {@link NetworkCapabilities} features
*/
public static class Builder {
+ /**
+ * Capabilities that are currently compatible with VCN networks.
+ */
+ private static final List<Integer> VCN_SUPPORTED_CAPABILITIES = Arrays.asList(
+ NET_CAPABILITY_CAPTIVE_PORTAL,
+ NET_CAPABILITY_DUN,
+ NET_CAPABILITY_FOREGROUND,
+ NET_CAPABILITY_INTERNET,
+ NET_CAPABILITY_NOT_CONGESTED,
+ NET_CAPABILITY_NOT_METERED,
+ NET_CAPABILITY_NOT_RESTRICTED,
+ NET_CAPABILITY_NOT_ROAMING,
+ NET_CAPABILITY_NOT_SUSPENDED,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+ NET_CAPABILITY_TEMPORARILY_NOT_METERED,
+ NET_CAPABILITY_TRUSTED,
+ NET_CAPABILITY_VALIDATED);
+
private final NetworkCapabilities mNetworkCapabilities;
+ // A boolean that represents the user modified NOT_VCN_MANAGED capability.
+ private boolean mModifiedNotVcnManaged = false;
+
/**
* Default constructor for Builder.
*/
@@ -179,6 +219,7 @@
// maybeMarkCapabilitiesRestricted() doesn't add back.
final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
nc.maybeMarkCapabilitiesRestricted();
+ deduceNotVcnManagedCapability(nc);
return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
}
@@ -195,6 +236,9 @@
*/
public Builder addCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addCapability(capability);
+ if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+ mModifiedNotVcnManaged = true;
+ }
return this;
}
@@ -206,6 +250,9 @@
*/
public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.removeCapability(capability);
+ if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+ mModifiedNotVcnManaged = true;
+ }
return this;
}
@@ -263,6 +310,9 @@
@NonNull
public Builder clearCapabilities() {
mNetworkCapabilities.clearAll();
+ // If the caller explicitly clear all capabilities, the NOT_VCN_MANAGED capabilities
+ // should not be add back later.
+ mModifiedNotVcnManaged = true;
return this;
}
@@ -382,6 +432,25 @@
mNetworkCapabilities.setSignalStrength(signalStrength);
return this;
}
+
+ /**
+ * Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other capabilities
+ * and user intention, which includes:
+ * 1. For the requests that don't have anything besides
+ * {@link #VCN_SUPPORTED_CAPABILITIES}, add the NET_CAPABILITY_NOT_VCN_MANAGED to
+ * allow the callers automatically utilize VCN networks if available.
+ * 2. For the requests that explicitly add or remove NET_CAPABILITY_NOT_VCN_MANAGED,
+ * do not alter them to allow user fire request that suits their need.
+ *
+ * @hide
+ */
+ private void deduceNotVcnManagedCapability(final NetworkCapabilities nc) {
+ if (mModifiedNotVcnManaged) return;
+ for (final int cap : nc.getCapabilities()) {
+ if (!VCN_SUPPORTED_CAPABILITIES.contains(cap)) return;
+ }
+ nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ }
}
// implement the Parcelable interface
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
index b8030f1..4c7b898 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
@@ -259,7 +259,12 @@
.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode).append(',')
.append("dataState=").append(dataState).append(',')
.append("serviceState=").append(serviceState == null ? ""
- : serviceState.toString()).append(',')
+ : "mVoiceRegState=" + serviceState.getState() + "("
+ + ServiceState.rilServiceStateToString(serviceState.getState())
+ + ")" + ", mDataRegState=" + serviceState.getDataRegState() + "("
+ + ServiceState.rilServiceStateToString(
+ serviceState.getDataRegState()) + ")")
+ .append(',')
.append("signalStrength=").append(signalStrength == null ? ""
: signalStrength.toString()).append(',')
.append("telephonyDisplayInfo=").append(telephonyDisplayInfo == null ? ""
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d932395..589a39c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -954,11 +954,8 @@
<string name="quick_settings_dark_mode_secondary_label_on_at">On at <xliff:g id="time" example="10 pm">%s</xliff:g></string>
<!-- QuickSettings: Secondary text for when the Dark theme or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->
<string name="quick_settings_dark_mode_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string>
- <!-- TODO(b/170970602): remove translatable=false when RBC has official name and strings -->
- <!-- QuickSettings: Label for the toggle that controls whether Reduce Bright Colors is enabled. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_reduce_bright_colors_label" translatable="false">Reduce Bright Colors</string>
- <!-- QuickSettings: Secondary text for intensity level of Reduce Bright Colors. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_reduce_bright_colors_secondary_label" translatable="false"> <xliff:g id="intensity" example="50">%d</xliff:g>%% reduction</string>
+ <!-- QuickSettings: Label for the toggle that controls whether Reduce Brightness is enabled. [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_reduce_bright_colors_label">Reduce Brightness</string>
<!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
<string name="quick_settings_nfc_label">NFC</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 70021b6..fbabaa4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -114,10 +114,13 @@
for (int i = params.length - 1; i >= 0; i--) {
SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
params[i];
- t.deferTransactionUntil(surfaceParams.surface, mBarrierSurfaceControl, frame);
surfaceParams.applyTo(t);
}
- t.apply();
+ if (mTargetViewRootImpl != null) {
+ mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
+ } else {
+ t.apply();
+ }
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
.sendToTarget();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index 4a28d56..89c60f1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -56,4 +56,12 @@
});
}
}
+
+ public void mergeWithNextTransaction(SurfaceControl.Transaction t, long frame) {
+ if (mViewRoot != null) {
+ mViewRoot.mergeWithNextTransaction(t, frame);
+ } else {
+ t.apply();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
index 9ab2d73..35a8257 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -16,6 +16,9 @@
package com.android.systemui.qs.dagger;
+import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
+
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.FeatureFlags;
@@ -27,6 +30,7 @@
@Module
public interface QSFlagsModule {
String QS_LABELS_FLAG = "qs_labels_flag";
+ String RBC_AVAILABLE = "rbc_available";
@Provides
@SysUISingleton
@@ -34,4 +38,12 @@
static boolean provideQSFlag(FeatureFlags featureFlags) {
return featureFlags.isQSLabelsEnabled();
}
+
+ /** */
+ @Provides
+ @SysUISingleton
+ @Named(RBC_AVAILABLE)
+ static boolean isReduceBrightColorsAvailable(Context context) {
+ return ColorDisplayManager.isReduceBrightColorsAvailable(context);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index 84c7611..f94cabc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -16,12 +16,13 @@
package com.android.systemui.qs.tiles;
+import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
+
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.service.quicksettings.Tile;
-import android.text.TextUtils;
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
@@ -39,6 +40,7 @@
import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
+import javax.inject.Named;
/** Quick settings tile: Reduce Bright Colors **/
public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> {
@@ -46,9 +48,11 @@
//TODO(b/170973645): get icon drawable
private final Icon mIcon = null;
private final SecureSetting mActivatedSetting;
+ private final boolean mIsAvailable;
@Inject
public ReduceBrightColorsTile(
+ @Named(RBC_AVAILABLE) boolean isAvailable,
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
@@ -69,11 +73,12 @@
refreshState();
}
};
+ mIsAvailable = isAvailable;
+
}
@Override
public boolean isAvailable() {
- // TODO(b/170970675): Call into ColorDisplayService to get availability/config status
- return true;
+ return mIsAvailable;
}
@Override
@@ -121,15 +126,6 @@
state.label = mContext.getString(R.string.quick_settings_reduce_bright_colors_label);
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
-
- final int intensity = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mActivatedSetting.getCurrentUser());
- state.secondaryLabel = state.value ? mContext.getString(
- R.string.quick_settings_reduce_bright_colors_secondary_label, intensity) : "";
-
- state.contentDescription = TextUtils.isEmpty(state.secondaryLabel)
- ? state.label
- : TextUtils.concat(state.label, ", ", state.secondaryLabel);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index 08a4492..ccaa1f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -25,6 +25,8 @@
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
@@ -42,11 +44,18 @@
private static final int MSG_MOBILE_DATA_ENABLED_CHANGED = 5;
private static final int MSG_ADD_REMOVE_EMERGENCY = 6;
private static final int MSG_ADD_REMOVE_SIGNAL = 7;
+ private static final int HISTORY_SIZE = 64;
+ private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
// All the callbacks.
private final ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<>();
private final ArrayList<SignalCallback> mSignalCallbacks = new ArrayList<>();
+ // Save the previous HISTORY_SIZE states for logging.
+ private final String[] mHistory = new String[HISTORY_SIZE];
+ // Where to copy the next state into.
+ private int mHistoryIndex;
+
public CallbackHandler() {
super(Looper.getMainLooper());
}
@@ -111,12 +120,27 @@
public void setWifiIndicators(final boolean enabled, final IconState statusIcon,
final IconState qsIcon, final boolean activityIn, final boolean activityOut,
final String description, boolean isTransient, String secondaryLabel) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setWifiIndicators: ")
+ .append("enabled=").append(enabled).append(",")
+ .append("statusIcon=").append(statusIcon).append(",")
+ .append("qsIcon=").append(qsIcon).append(",")
+ .append("activityIn=").append(activityIn).append(",")
+ .append("activityOut=").append(activityOut).append(",")
+ .append("description=").append(description).append(",")
+ .append("isTransient=").append(isTransient).append(",")
+ .append("secondaryLabel=").append(secondaryLabel)
+ .toString();
+ recordLastCallback(log);
post(() -> {
for (SignalCallback callback : mSignalCallbacks) {
callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut,
description, isTransient, secondaryLabel);
}
});
+
+
}
@Override
@@ -125,6 +149,25 @@
final boolean activityOut, final CharSequence typeContentDescription,
CharSequence typeContentDescriptionHtml, final CharSequence description,
final boolean isWide, final int subId, boolean roaming, boolean showTriangle) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setMobileDataIndicators: ")
+ .append("statusIcon=").append(statusIcon).append(",")
+ .append("qsIcon=").append(qsIcon).append(",")
+ .append("statusType=").append(statusType).append(",")
+ .append("qsType=").append(qsType).append(",")
+ .append("activityIn=").append(activityIn).append(",")
+ .append("activityOut=").append(activityOut).append(",")
+ .append("typeContentDescription=").append(typeContentDescription).append(",")
+ .append("typeContentDescriptionHtml=").append(typeContentDescriptionHtml)
+ .append(",")
+ .append("description=").append(description).append(",")
+ .append("isWide=").append(isWide).append(",")
+ .append("subId=").append(subId).append(",")
+ .append("roaming=").append(roaming).append(",")
+ .append("showTriangle=").append(showTriangle)
+ .toString();
+ recordLastCallback(log);
post(() -> {
for (SignalCallback signalCluster : mSignalCallbacks) {
signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType, qsType,
@@ -138,6 +181,14 @@
@Override
public void setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork,
boolean noNetworksAvailable) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setConnectivityStatus: ")
+ .append("noDefaultNetwork=").append(noDefaultNetwork).append(",")
+ .append("noValidatedNetwork=").append(noValidatedNetwork).append(",")
+ .append("noNetworksAvailable=").append(noNetworksAvailable)
+ .toString();
+ recordLastCallback(log);
post(() -> {
for (SignalCallback signalCluster : mSignalCallbacks) {
signalCluster.setConnectivityStatus(
@@ -148,6 +199,13 @@
@Override
public void setNoCallingStatus(boolean noCalling, int subId) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setNoCallingStatus: ")
+ .append("noCalling=").append(noCalling).append(",")
+ .append("subId=").append(subId)
+ .toString();
+ recordLastCallback(log);
post(() -> {
for (SignalCallback signalCluster : mSignalCallbacks) {
signalCluster.setNoCallingStatus(noCalling, subId);
@@ -157,16 +215,35 @@
@Override
public void setSubs(List<SubscriptionInfo> subs) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setSubs: ")
+ .append("subs=").append(subs == null ? "" : subs.toString())
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_SUBS_CHANGED, subs).sendToTarget();
}
@Override
public void setNoSims(boolean show, boolean simDetected) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setNoSims: ")
+ .append("show=").append(show).append(",")
+ .append("simDetected=").append(simDetected)
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_NO_SIM_VISIBLE_CHANGED, show ? 1 : 0, simDetected ? 1 : 0).sendToTarget();
}
@Override
public void setMobileDataEnabled(boolean enabled) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setMobileDataEnabled: ")
+ .append("enabled=").append(enabled)
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_MOBILE_DATA_ENABLED_CHANGED, enabled ? 1 : 0, 0).sendToTarget();
}
@@ -177,11 +254,23 @@
@Override
public void setEthernetIndicators(IconState icon) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setEthernetIndicators: ")
+ .append("icon=").append(icon)
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_ETHERNET_CHANGED, icon).sendToTarget();;
}
@Override
public void setIsAirplaneMode(IconState icon) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setIsAirplaneMode: ")
+ .append("icon=").append(icon)
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_AIRPLANE_MODE_CHANGED, icon).sendToTarget();;
}
@@ -193,4 +282,25 @@
obtainMessage(MSG_ADD_REMOVE_SIGNAL, listening ? 1 : 0, 0, listener).sendToTarget();
}
+ protected void recordLastCallback(String callback) {
+ mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)] = callback;
+ }
+
+ /**
+ * Dump the Callback logs
+ */
+ public void dump(PrintWriter pw) {
+ pw.println(" - CallbackHandler -----");
+ int size = 0;
+ for (int i = 0; i < HISTORY_SIZE; i++) {
+ if (mHistory[i] != null) size++;
+ }
+ // Print out the previous states in ordered number.
+ for (int i = mHistoryIndex + HISTORY_SIZE - 1;
+ i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
+ pw.println(" Previous Callback(" + (mHistoryIndex + HISTORY_SIZE - i) + "): "
+ + mHistory[i & (HISTORY_SIZE - 1)]);
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 39472de..0fe338e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -46,6 +46,7 @@
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.MobileMappings.Config;
import com.android.settingslib.mobile.MobileStatusTracker;
+import com.android.settingslib.mobile.MobileStatusTracker.MobileStatus;
import com.android.settingslib.mobile.MobileStatusTracker.SubscriptionDefaults;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
@@ -54,6 +55,7 @@
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.BitSet;
import java.util.List;
import java.util.Map;
@@ -62,6 +64,8 @@
* Monitors the mobile signal changes and update the SysUI icons.
*/
public class MobileSignalController extends SignalController<MobileState, MobileIconGroup> {
+ private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+
private final TelephonyManager mPhone;
private final SubscriptionDefaults mDefaults;
private final String mNetworkNameDefault;
@@ -90,6 +94,11 @@
@VisibleForTesting
MobileStatusTracker mMobileStatusTracker;
+ // Save the previous HISTORY_SIZE states for logging.
+ private final String[] mMobileStatusHistory = new String[HISTORY_SIZE];
+ // Where to copy the next state into.
+ private int mMobileStatusHistoryIndex;
+
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
public MobileSignalController(Context context, Config config, boolean hasMobileData,
@@ -126,12 +135,17 @@
mCallback = new MobileStatusTracker.Callback() {
@Override
public void onMobileStatusChanged(boolean updateTelephony,
- MobileStatusTracker.MobileStatus mobileStatus) {
+ MobileStatus mobileStatus) {
if (Log.isLoggable(mTag, Log.DEBUG)) {
Log.d(mTag, "onMobileStatusChanged="
+ " updateTelephony=" + updateTelephony
+ " mobileStatus=" + mobileStatus.toString());
}
+ String status = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append(mobileStatus.toString())
+ .toString();
+ recordLastMobileStatus(status);
updateMobileStatus(mobileStatus);
if (updateTelephony) {
updateTelephony();
@@ -343,16 +357,8 @@
return Utils.isInService(mServiceState);
}
- String getNonDefaultCarrierName() {
- if (!mCurrentState.networkNameData.equals(mNetworkNameDefault)) {
- return mCurrentState.networkNameData;
- } else if (mSubscriptionInfo.getCarrierName() != null) {
- return mSubscriptionInfo.getCarrierName().toString();
- } else if (mSubscriptionInfo.getDisplayName() != null) {
- return mSubscriptionInfo.getDisplayName().toString();
- } else {
- return "";
- }
+ String getNetworkNameForCarrierWiFi() {
+ return mPhone.getSimOperatorName();
}
private boolean isRoaming() {
@@ -455,7 +461,7 @@
return CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
- private void updateMobileStatus(MobileStatusTracker.MobileStatus mobileStatus) {
+ private void updateMobileStatus(MobileStatus mobileStatus) {
mCurrentState.activityIn = mobileStatus.activityIn;
mCurrentState.activityOut = mobileStatus.activityOut;
mCurrentState.dataSim = mobileStatus.dataSim;
@@ -570,6 +576,10 @@
notifyListenersIfNecessary();
}
+ private void recordLastMobileStatus(String mobileStatus) {
+ mMobileStatusHistory[mMobileStatusHistoryIndex++ & (HISTORY_SIZE - 1)] = mobileStatus;
+ }
+
@Override
public void dump(PrintWriter pw) {
super.dump(pw);
@@ -580,5 +590,17 @@
pw.println(" mDataState=" + mDataState + ",");
pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
+ pw.println(" MobileStatusHistory");
+ int size = 0;
+ for (int i = 0; i < HISTORY_SIZE; i++) {
+ if (mMobileStatusHistory[i] != null) size++;
+ }
+ // Print out the previous states in ordered number.
+ for (int i = mMobileStatusHistoryIndex + HISTORY_SIZE - 1;
+ i >= mMobileStatusHistoryIndex + HISTORY_SIZE - size; i--) {
+ pw.println(" Previous MobileStatus("
+ + (mMobileStatusHistoryIndex + HISTORY_SIZE - i) + "): "
+ + mMobileStatusHistory[i & (HISTORY_SIZE - 1)]);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index e13e30b..80c7811 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -76,6 +76,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
@@ -100,6 +101,8 @@
private static final int EMERGENCY_VOICE_CONTROLLER = 200;
private static final int EMERGENCY_NO_SUB = 300;
private static final int EMERGENCY_ASSUMED_VOICE_CONTROLLER = 400;
+ private static final int HISTORY_SIZE = 16;
+ private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
private final Context mContext;
private final TelephonyManager mPhone;
@@ -150,6 +153,11 @@
// This list holds our ordering.
private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>();
+ // Save the previous HISTORY_SIZE states for logging.
+ private final String[] mHistory = new String[HISTORY_SIZE];
+ // Where to copy the next state into.
+ private int mHistoryIndex;
+
@VisibleForTesting
boolean mListening;
@@ -307,6 +315,12 @@
public void onLost(Network network) {
mLastNetwork = null;
mLastNetworkCapabilities = null;
+ String callback = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("onLost: ")
+ .append("network=").append(network)
+ .toString();
+ recordLastNetworkCallback(callback);
updateConnectivity();
}
@@ -327,6 +341,13 @@
}
mLastNetwork = network;
mLastNetworkCapabilities = networkCapabilities;
+ String callback = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("onCapabilitiesChanged: ")
+ .append("network=").append(network).append(",")
+ .append("networkCapabilities=").append(networkCapabilities)
+ .toString();
+ recordLastNetworkCallback(callback);
updateConnectivity();
}
};
@@ -528,9 +549,9 @@
return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
}
- String getNonDefaultMobileDataNetworkName(int subId) {
+ String getNetworkNameForCarrierWiFi(int subId) {
MobileSignalController controller = getControllerWithSubId(subId);
- return controller != null ? controller.getNonDefaultCarrierName() : "";
+ return controller != null ? controller.getNetworkNameForCarrierWiFi() : "";
}
private void notifyControllersMobileDataChanged() {
@@ -996,6 +1017,19 @@
pw.print(" mEmergencySource=");
pw.println(emergencyToString(mEmergencySource));
+ pw.println(" - DefaultNetworkCallback -----");
+ int size = 0;
+ for (int i = 0; i < HISTORY_SIZE; i++) {
+ if (mHistory[i] != null) {
+ size++;
+ }
+ }
+ for (int i = mHistoryIndex + HISTORY_SIZE - 1;
+ i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
+ pw.println(" Previous NetworkCallback(" + (mHistoryIndex + HISTORY_SIZE - i) + "): "
+ + mHistory[i & (HISTORY_SIZE - 1)]);
+ }
+
pw.println(" - config ------");
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
@@ -1006,6 +1040,8 @@
mEthernetSignalController.dump(pw);
mAccessPoints.dump(pw);
+
+ mCallbackHandler.dump(pw);
}
private static final String emergencyToString(int emergencySource) {
@@ -1235,6 +1271,10 @@
return s;
}
+ private void recordLastNetworkCallback(String callback) {
+ mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)] = callback;
+ }
+
private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
null, null, null, "", false, null, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index b2120d4..1fd2ccb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -147,7 +147,7 @@
IconState qsIcon = new IconState(
mCurrentState.connected, getQsCurrentIconIdForCarrierWifi(), contentDescription);
CharSequence description =
- mNetworkController.getNonDefaultMobileDataNetworkName(mCurrentState.subId);
+ mNetworkController.getNetworkNameForCarrierWiFi(mCurrentState.subId);
callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
mCurrentState.activityIn, mCurrentState.activityOut, dataContentDescription,
dataContentDescriptionHtml, description, icons.isWide,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index 78af20f..ffd747e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -75,6 +75,7 @@
mFakeSettings = new FakeSettings();
mTile = new ReduceBrightColorsTile(
+ true,
mHost,
mTestableLooper.getLooper(),
new Handler(mTestableLooper.getLooper()),
@@ -95,7 +96,6 @@
assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
assertEquals(mTile.getState().label.toString(),
mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
- assertEquals(mTile.getState().secondaryLabel.toString(), "");
}
@Test
@@ -128,13 +128,5 @@
assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
assertEquals(mTile.getState().label.toString(),
mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
-
- final int intensity = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mUserTracker.getUserId());
-
- assertEquals(
- mContext.getString(
- R.string.quick_settings_reduce_bright_colors_secondary_label, intensity),
- mTile.getState().secondaryLabel.toString());
}
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 55e3ef2..96b69dc 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -17,9 +17,17 @@
package com.android.server.companion;
+import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
+import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
+import static android.content.Context.BIND_IMPORTANT;
+import static android.content.pm.PackageManager.MATCH_ALL;
+
+import static com.android.internal.util.CollectionUtils.any;
import static com.android.internal.util.CollectionUtils.emptyIfNull;
+import static com.android.internal.util.CollectionUtils.filter;
import static com.android.internal.util.CollectionUtils.find;
import static com.android.internal.util.CollectionUtils.forEach;
+import static com.android.internal.util.CollectionUtils.map;
import static com.android.internal.util.FunctionalUtils.uncheckExceptions;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -40,22 +48,32 @@
import android.app.role.RoleManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
import android.companion.Association;
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
+import android.companion.CompanionDeviceService;
import android.companion.DeviceNotAssociatedException;
import android.companion.ICompanionDeviceDiscoveryService;
import android.companion.ICompanionDeviceManager;
+import android.companion.ICompanionDeviceService;
import android.companion.IFindDeviceCallback;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.NetworkPolicyManager;
import android.os.Binder;
@@ -77,6 +95,7 @@
import android.provider.Settings;
import android.provider.SettingsStringUtil.ComponentNameSet;
import android.text.BidiFormatter;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.ExceptionUtils;
@@ -115,6 +134,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -135,6 +155,9 @@
CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
".DeviceDiscoveryService");
+ private static final long DEVICE_DISAPPEARED_TIMEOUT_MS = 10 * 1000;
+ private static final long DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS = 10 * 60 * 1000;
+
private static final boolean DEBUG = false;
private static final String LOG_TAG = "CompanionDeviceManagerService";
@@ -146,18 +169,23 @@
private static final String XML_ATTR_PACKAGE = "package";
private static final String XML_ATTR_DEVICE = "device";
private static final String XML_ATTR_PROFILE = "profile";
- private static final String XML_ATTR_PERSISTENT_PROFILE_GRANTS = "persistent_profile_grants";
+ private static final String XML_ATTR_NOTIFY_DEVICE_NEARBY = "notify_device_nearby";
private static final String XML_FILE_NAME = "companion_device_manager_associations.xml";
private final CompanionDeviceManagerImpl mImpl;
private final ConcurrentMap<Integer, AtomicFile> mUidToStorage = new ConcurrentHashMap<>();
private PowerWhitelistManager mPowerWhitelistManager;
private PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>> mServiceConnectors;
+ /** userId -> packageName -> serviceConnector */
+ private PerUser<ArrayMap<String, ServiceConnector<ICompanionDeviceService>>>
+ mDeviceListenerServiceConnectors;
private IAppOpsService mAppOpsManager;
private RoleManager mRoleManager;
private BluetoothAdapter mBluetoothAdapter;
+ private UserManager mUserManager;
private IFindDeviceCallback mFindDeviceCallback;
+ private ScanCallback mBleScanCallback = new BleScanCallback();
private AssociationRequest mRequest;
private String mCallingPackage;
private AndroidFuture<Association> mOngoingDeviceDiscovery;
@@ -165,9 +193,16 @@
private BluetoothDeviceConnectedListener mBluetoothDeviceConnectedListener =
new BluetoothDeviceConnectedListener();
+ private BleStateBroadcastReceiver mBleStateBroadcastReceiver = new BleStateBroadcastReceiver();
private List<String> mCurrentlyConnectedDevices = new ArrayList<>();
+ private ArrayMap<String, Date> mDevicesLastNearby = new ArrayMap<>();
+ private UnbindDeviceListenersRunnable
+ mUnbindDeviceListenersRunnable = new UnbindDeviceListenersRunnable();
+ private ArrayMap<String, TriggerDeviceDisappearedRunnable> mTriggerDeviceDisappearedRunnables =
+ new ArrayMap<>();
private final Object mLock = new Object();
+ private final Handler mMainHandler = Handler.getMain();
/** userId -> [association] */
@GuardedBy("mLock")
@@ -189,6 +224,7 @@
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mPermissionControllerManager = requireNonNull(
context.getSystemService(PermissionControllerManager.class));
+ mUserManager = context.getSystemService(UserManager.class);
Intent serviceIntent = new Intent().setComponent(SERVICE_TO_BIND_TO);
mServiceConnectors = new PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>>() {
@@ -201,6 +237,16 @@
}
};
+ mDeviceListenerServiceConnectors = new PerUser<ArrayMap<String,
+ ServiceConnector<ICompanionDeviceService>>>() {
+ @NonNull
+ @Override
+ protected ArrayMap<String, ServiceConnector<ICompanionDeviceService>> create(
+ int userId) {
+ return new ArrayMap<>();
+ }
+ };
+
registerPackageMonitor();
}
@@ -208,10 +254,13 @@
new PackageMonitor() {
@Override
public void onPackageRemoved(String packageName, int uid) {
+ int userId = getChangingUserId();
updateAssociations(
as -> CollectionUtils.filter(as,
a -> !Objects.equals(a.getPackageName(), packageName)),
- getChangingUserId());
+ userId);
+
+ unbindDevicePresenceListener(packageName, userId);
}
@Override
@@ -225,6 +274,15 @@
}.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
}
+ private void unbindDevicePresenceListener(String packageName, int userId) {
+ ServiceConnector<ICompanionDeviceService> deviceListener =
+ mDeviceListenerServiceConnectors.forUser(userId)
+ .remove(packageName);
+ if (deviceListener != null) {
+ deviceListener.unbind();
+ }
+ }
+
@Override
public void onStart() {
publishBinderService(Context.COMPANION_DEVICE_SERVICE, mImpl);
@@ -233,11 +291,17 @@
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ // Init Bluetooth
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null) {
mBluetoothAdapter.registerBluetoothConnectionCallback(
getContext().getMainExecutor(),
mBluetoothDeviceConnectedListener);
+ getContext().registerReceiver(
+ mBleStateBroadcastReceiver, mBleStateBroadcastReceiver.mIntentFilter);
+ initBleScanning();
+ } else {
+ Log.w(LOG_TAG, "No BluetoothAdapter available");
}
}
}
@@ -287,7 +351,7 @@
@Override
public void binderDied() {
- Handler.getMain().post(this::cleanup);
+ mMainHandler.post(this::cleanup);
}
private void cleanup() {
@@ -399,7 +463,7 @@
checkCallerIsSystemOr(callingPackage, userId);
checkUsesFeature(callingPackage, getCallingUserId());
}
- return new ArrayList<>(CollectionUtils.map(
+ return new ArrayList<>(map(
getAllAssociations(userId, callingPackage),
a -> a.getDeviceMacAddress()));
}
@@ -497,7 +561,7 @@
return true;
}
- return CollectionUtils.any(
+ return any(
getAllAssociations(userId, packageName),
a -> Objects.equals(a.getDeviceMacAddress(), macAddress));
}
@@ -506,22 +570,18 @@
public void registerDevicePresenceListenerService(
String packageName, String deviceAddress)
throws RemoteException {
- checkCanRegisterObserverService(packageName, deviceAddress);
-
- //TODO(eugenesusla) implement
+ registerDevicePresenceListenerActive(packageName, deviceAddress, true);
}
@Override
public void unregisterDevicePresenceListenerService(
String packageName, String deviceAddress)
throws RemoteException {
- checkCanRegisterObserverService(packageName, deviceAddress);
-
- //TODO(eugenesusla) implement
+ registerDevicePresenceListenerActive(packageName, deviceAddress, false);
}
- private void checkCanRegisterObserverService(String packageName, String deviceAddress)
- throws RemoteException {
+ private void registerDevicePresenceListenerActive(String packageName, String deviceAddress,
+ boolean active) throws RemoteException {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE,
"[un]registerDevicePresenceListenerService");
@@ -537,6 +597,20 @@
+ " is not associated with device " + deviceAddress
+ " for user " + userId));
}
+
+ updateAssociations(associations -> map(associations, association -> {
+ if (Objects.equals(association.getPackageName(), packageName)
+ && Objects.equals(association.getDeviceMacAddress(), deviceAddress)) {
+ return new Association(
+ association.getUserId(),
+ association.getDeviceMacAddress(),
+ association.getPackageName(),
+ association.getDeviceProfile(),
+ active /* notifyOnDeviceNearby */);
+ } else {
+ return association;
+ }
+ }));
}
private void checkCanCallNotificationApi(String callingPackage) throws RemoteException {
@@ -693,6 +767,10 @@
if (mCurrentlyConnectedDevices.contains(association.getDeviceMacAddress())) {
grantDeviceProfile(association);
}
+
+ if (association.isNotifyOnDeviceNearby()) {
+ restartBleScan();
+ }
}
private void exemptFromAutoRevoke(String packageName, int uid) {
@@ -795,9 +873,9 @@
association.getDeviceMacAddress());
if (association.getDeviceProfile() != null) {
tag.attribute(null, XML_ATTR_PROFILE, association.getDeviceProfile());
- tag.attribute(null, XML_ATTR_PERSISTENT_PROFILE_GRANTS,
+ tag.attribute(null, XML_ATTR_NOTIFY_DEVICE_NEARBY,
Boolean.toString(
- association.isKeepProfilePrivilegesWhenDeviceAway()));
+ association.isNotifyOnDeviceNearby()));
}
tag.endTag(null, XML_TAG_ASSOCIATION);
});
@@ -835,7 +913,12 @@
}
private List<UserInfo> getAllUsers() {
- return getContext().getSystemService(UserManager.class).getUsers();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mUserManager.getUsers();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Nullable
@@ -845,6 +928,19 @@
a -> Objects.equals(packageFilter, a.getPackageName()));
}
+ private Set<Association> getAllAssociations() {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ ArraySet<Association> result = new ArraySet<>();
+ for (UserInfo user : mUserManager.getAliveUsers()) {
+ result.addAll(getAllAssociations(user.id));
+ }
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private Set<Association> readAllAssociations(int userId) {
final AtomicFile file = getStorageFileForUser(userId);
@@ -865,7 +961,7 @@
final String profile = parser.getAttributeValue(null, XML_ATTR_PROFILE);
final boolean persistentGrants = Boolean.valueOf(
- parser.getAttributeValue(null, XML_ATTR_PERSISTENT_PROFILE_GRANTS));
+ parser.getAttributeValue(null, XML_ATTR_NOTIFY_DEVICE_NEARBY));
if (appPackage == null || deviceAddress == null) continue;
@@ -896,6 +992,8 @@
}
}
}
+
+ onDeviceNearby(address);
}
private void grantDeviceProfile(Association association) {
@@ -919,6 +1017,267 @@
void onDeviceDisconnected(String address) {
mCurrentlyConnectedDevices.remove(address);
+
+ onDeviceDisappeared(address);
+ }
+
+ private ServiceConnector<ICompanionDeviceService> getDeviceListenerServiceConnector(
+ Association a) {
+ return mDeviceListenerServiceConnectors.forUser(a.getUserId()).computeIfAbsent(
+ a.getPackageName(),
+ pkg -> createDeviceListenerServiceConnector(a));
+ }
+
+ private ServiceConnector<ICompanionDeviceService> createDeviceListenerServiceConnector(
+ Association a) {
+ List<ResolveInfo> resolveInfos = getContext().getPackageManager().queryIntentServicesAsUser(
+ new Intent(CompanionDeviceService.SERVICE_INTERFACE), MATCH_ALL, a.getUserId());
+ List<ResolveInfo> packageResolveInfos = filter(resolveInfos,
+ info -> Objects.equals(info.serviceInfo.packageName, a.getPackageName()));
+ if (packageResolveInfos.size() != 1) {
+ Log.w(LOG_TAG, "Device presence listener package must have exactly one "
+ + "CompanionDeviceService, but " + a.getPackageName()
+ + " has " + packageResolveInfos.size());
+ return new ServiceConnector.NoOp<>();
+ }
+ ComponentName componentName = packageResolveInfos.get(0).serviceInfo.getComponentName();
+ Log.i(LOG_TAG, "Initializing CompanionDeviceService binding for " + componentName);
+ return new ServiceConnector.Impl<>(getContext(),
+ new Intent(CompanionDeviceService.SERVICE_INTERFACE).setComponent(componentName),
+ BIND_IMPORTANT,
+ a.getUserId(),
+ ICompanionDeviceService.Stub::asInterface);
+ }
+
+ private class BleScanCallback extends ScanCallback {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onScanResult(callbackType = "
+ + callbackType + ", result = " + result + ")");
+ }
+
+ onDeviceNearby(result.getDevice().getAddress());
+ }
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ for (int i = 0, size = results.size(); i < size; i++) {
+ onScanResult(CALLBACK_TYPE_ALL_MATCHES, results.get(i));
+ }
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ if (errorCode == SCAN_FAILED_ALREADY_STARTED) {
+ // ignore - this might happen if BT tries to auto-restore scans for us in the
+ // future
+ Log.i(LOG_TAG, "Ignoring BLE scan error: SCAN_FAILED_ALREADY_STARTED");
+ } else {
+ Log.w(LOG_TAG, "Failed to start BLE scan: error " + errorCode);
+ }
+ }
+ }
+
+ private class BleStateBroadcastReceiver extends BroadcastReceiver {
+
+ final IntentFilter mIntentFilter =
+ new IntentFilter(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1);
+ int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+ Log.i(LOG_TAG, "Received BT state transition broadcast: "
+ + BluetoothAdapter.nameForState(previousState)
+ + " -> " + BluetoothAdapter.nameForState(newState));
+
+ boolean bleOn = newState == BluetoothAdapter.STATE_ON
+ || newState == BluetoothAdapter.STATE_BLE_ON;
+ if (bleOn) {
+ if (mBluetoothAdapter.getBluetoothLeScanner() != null) {
+ startBleScan();
+ } else {
+ Log.wtf(LOG_TAG, "BLE on, but BluetoothLeScanner == null");
+ }
+ }
+ }
+ }
+
+ private class UnbindDeviceListenersRunnable implements Runnable {
+
+ public String getJobId(String address) {
+ return "CDM_deviceGone_unbind_" + address;
+ }
+
+ @Override
+ public void run() {
+ int size = mDevicesLastNearby.size();
+ for (int i = 0; i < size; i++) {
+ String address = mDevicesLastNearby.keyAt(i);
+ Date lastNearby = mDevicesLastNearby.valueAt(i);
+
+ if (System.currentTimeMillis() - lastNearby.getTime()
+ >= DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS) {
+ for (Association association : getAllAssociations(address)) {
+ if (association.isNotifyOnDeviceNearby()) {
+ getDeviceListenerServiceConnector(association).unbind();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private class TriggerDeviceDisappearedRunnable implements Runnable {
+
+ private final String mAddress;
+
+ TriggerDeviceDisappearedRunnable(String address) {
+ mAddress = address;
+ }
+
+ public void schedule() {
+ mMainHandler.removeCallbacks(this);
+ mMainHandler.postDelayed(this, this, DEVICE_DISAPPEARED_TIMEOUT_MS);
+ }
+
+ @Override
+ public void run() {
+ onDeviceDisappeared(mAddress);
+ }
+ }
+
+ private Set<Association> getAllAssociations(String deviceAddress) {
+ List<UserInfo> aliveUsers = mUserManager.getAliveUsers();
+ Set<Association> result = new ArraySet<>();
+ for (int i = 0, size = aliveUsers.size(); i < size; i++) {
+ UserInfo user = aliveUsers.get(i);
+ for (Association association : getAllAssociations(user.id)) {
+ if (Objects.equals(association.getDeviceMacAddress(), deviceAddress)) {
+ result.add(association);
+ }
+ }
+ }
+ return result;
+ }
+
+ private void onDeviceNearby(String address) {
+ Date timestamp = new Date();
+ Date oldTimestamp = mDevicesLastNearby.put(address, timestamp);
+
+ cancelUnbindDeviceListener(address);
+
+ mTriggerDeviceDisappearedRunnables
+ .computeIfAbsent(address, addr -> new TriggerDeviceDisappearedRunnable(address))
+ .schedule();
+
+ // Avoid spamming the app if device is already known to be nearby
+ boolean justAppeared = oldTimestamp == null
+ || timestamp.getTime() - oldTimestamp.getTime() >= DEVICE_DISAPPEARED_TIMEOUT_MS;
+ if (justAppeared) {
+ for (Association association : getAllAssociations(address)) {
+ if (association.isNotifyOnDeviceNearby()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Device " + address
+ + " managed by " + association.getPackageName()
+ + " is nearby on " + timestamp);
+ }
+ getDeviceListenerServiceConnector(association).run(
+ service -> service.onDeviceAppeared(association.getDeviceMacAddress()));
+ }
+ }
+ }
+ }
+
+ private void onDeviceDisappeared(String address) {
+ boolean hasDeviceListeners = false;
+ for (Association association : getAllAssociations(address)) {
+ if (association.isNotifyOnDeviceNearby()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Device " + address
+ + " managed by " + association.getPackageName()
+ + " disappeared; last seen on " + mDevicesLastNearby.get(address));
+ }
+
+ getDeviceListenerServiceConnector(association).run(
+ service -> service.onDeviceDisappeared(address));
+ hasDeviceListeners = true;
+ }
+ }
+
+ cancelUnbindDeviceListener(address);
+ if (hasDeviceListeners) {
+ mMainHandler.postDelayed(
+ mUnbindDeviceListenersRunnable,
+ mUnbindDeviceListenersRunnable.getJobId(address),
+ DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS);
+ }
+ }
+
+ private void cancelUnbindDeviceListener(String address) {
+ mMainHandler.removeCallbacks(
+ mUnbindDeviceListenersRunnable, mUnbindDeviceListenersRunnable.getJobId(address));
+ }
+
+ private void initBleScanning() {
+ Log.i(LOG_TAG, "initBleScanning()");
+
+ boolean bluetoothReady = mBluetoothAdapter.registerServiceLifecycleCallback(
+ new BluetoothAdapter.ServiceLifecycleCallback() {
+ @Override
+ public void onBluetoothServiceUp() {
+ Log.i(LOG_TAG, "Bluetooth stack is up");
+ startBleScan();
+ }
+
+ @Override
+ public void onBluetoothServiceDown() {
+ Log.w(LOG_TAG, "Bluetooth stack is down");
+ }
+ });
+ if (bluetoothReady) {
+ startBleScan();
+ }
+ }
+
+ void startBleScan() {
+ Log.i(LOG_TAG, "startBleScan()");
+
+ List<ScanFilter> filters = getBleScanFilters();
+ if (filters.isEmpty()) {
+ return;
+ }
+ BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
+ if (scanner == null) {
+ Log.w(LOG_TAG, "scanner == null (likely BLE isn't ON yet)");
+ } else {
+ scanner.startScan(
+ filters,
+ new ScanSettings.Builder().setScanMode(SCAN_MODE_BALANCED).build(),
+ mBleScanCallback);
+ }
+ }
+
+ void restartBleScan() {
+ mBluetoothAdapter.getBluetoothLeScanner().stopScan(mBleScanCallback);
+ startBleScan();
+ }
+
+ private List<ScanFilter> getBleScanFilters() {
+ ArrayList<ScanFilter> result = new ArrayList<>();
+ ArraySet<String> addressesSeen = new ArraySet<>();
+ for (Association association : getAllAssociations()) {
+ String address = association.getDeviceMacAddress();
+ if (addressesSeen.contains(address)) {
+ continue;
+ }
+ if (association.isNotifyOnDeviceNearby()) {
+ result.add(new ScanFilter.Builder().setDeviceAddress(address).build());
+ addressesSeen.add(address);
+ }
+ }
+ return result;
}
private AndroidFuture<String> getDeviceProfilePermissionDescription(String deviceProfile) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3933e37..06f9358 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -45,6 +45,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
@@ -1038,7 +1039,8 @@
mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultInternetRequestForTransport(
-1, NetworkRequest.Type.REQUEST);
- mDefaultRequest = new NetworkRequestInfo(null, defaultInternetRequest, new Binder());
+ mDefaultRequest = new NetworkRequestInfo(null, defaultInternetRequest, new Binder(),
+ null /* attributionTag */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
mDefaultNetworkRequests.add(mDefaultRequest);
mNetworkRequestInfoLogs.log("REGISTER " + mDefaultRequest);
@@ -1246,6 +1248,7 @@
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
netCap.setSingleUid(uid);
return netCap;
@@ -1255,6 +1258,7 @@
int transportType, NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
if (transportType > -1) {
netCap.addTransportType(transportType);
@@ -1308,7 +1312,7 @@
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- null, networkRequest, new Binder()));
+ null, networkRequest, new Binder(), null /* attributionTag */));
} else {
handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
/* callOnUnavailable */ false);
@@ -1643,7 +1647,7 @@
@Override
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
- int userId, String callingPackageName) {
+ int userId, String callingPackageName, @Nullable String callingAttributionTag) {
// The basic principle is: if an app's traffic could possibly go over a
// network, without the app doing anything multinetwork-specific,
// (hence, by "default"), then include that network's capabilities in
@@ -1674,7 +1678,8 @@
result.put(
nai.network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName));
+ nc, mDeps.getCallingUid(), callingPackageName,
+ callingAttributionTag));
}
}
@@ -1687,7 +1692,8 @@
result.put(
network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName));
+ nc, mDeps.getCallingUid(), callingPackageName,
+ callingAttributionTag));
}
}
}
@@ -1762,12 +1768,13 @@
}
@Override
- public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
+ public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName,
+ @Nullable String callingAttributionTag) {
mAppOpsManager.checkPackage(mDeps.getCallingUid(), callingPackageName);
enforceAccessPermission();
return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
getNetworkCapabilitiesInternal(network),
- mDeps.getCallingUid(), callingPackageName);
+ mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
}
@VisibleForTesting
@@ -1786,11 +1793,12 @@
return newNc;
}
- private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName) {
+ private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName,
+ @Nullable String callingAttributionTag) {
final long token = Binder.clearCallingIdentity();
try {
return mLocationPermissionChecker.checkLocationPermission(
- callerPkgName, null /* featureId */, callerUid, null /* message */);
+ callerPkgName, callingAttributionTag, callerUid, null /* message */);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1799,7 +1807,8 @@
@VisibleForTesting
@Nullable
NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
+ @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName,
+ @Nullable String callingAttributionTag) {
if (nc == null) {
return null;
}
@@ -1808,7 +1817,8 @@
// Avoid doing location permission check if the transport info has no location sensitive
// data.
if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) {
- hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
+ hasLocationPermission =
+ hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
newNc = new NetworkCapabilities(nc, hasLocationPermission);
} else {
newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */);
@@ -1825,7 +1835,8 @@
}
if (hasLocationPermission == null) {
// Location permission not checked yet, check now for masking owner UID.
- hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
+ hasLocationPermission =
+ hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
}
// Reset owner uid if the app has no location permission.
if (!hasLocationPermission) {
@@ -5541,6 +5552,8 @@
final int mPid;
final int mUid;
final Messenger messenger;
+ @Nullable
+ final String mCallingAttributionTag;
/**
* Get the list of UIDs this nri applies to.
@@ -5554,7 +5567,8 @@
return uids;
}
- NetworkRequestInfo(NetworkRequest r, PendingIntent pi) {
+ NetworkRequestInfo(NetworkRequest r, PendingIntent pi,
+ @Nullable String callingAttributionTag) {
mRequests = initializeRequests(r);
ensureAllNetworkRequestsHaveType(mRequests);
mPendingIntent = pi;
@@ -5563,9 +5577,11 @@
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallingAttributionTag = callingAttributionTag;
}
- NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder) {
+ NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder,
+ @Nullable String callingAttributionTag) {
super();
messenger = m;
mRequests = initializeRequests(r);
@@ -5575,6 +5591,7 @@
mUid = mDeps.getCallingUid();
mPendingIntent = null;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallingAttributionTag = callingAttributionTag;
try {
mBinder.linkToDeath(this, 0);
@@ -5584,7 +5601,7 @@
}
NetworkRequestInfo(NetworkRequest r) {
- this(r, null);
+ this(r, null /* pi */, null /* callingAttributionTag */);
}
// True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
@@ -5777,7 +5794,8 @@
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
- NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
+ NetworkRequestInfo nri =
+ new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag);
if (DBG) log("requestNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
@@ -5866,7 +5884,8 @@
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
- NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
+ NetworkRequestInfo nri =
+ new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
if (DBG) log("pendingRequest for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
nri));
@@ -5910,7 +5929,8 @@
@Override
public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, IBinder binder, @NonNull String callingPackageName) {
+ Messenger messenger, IBinder binder, @NonNull String callingPackageName,
+ @Nullable String callingAttributionTag) {
final int callingUid = mDeps.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
@@ -5930,7 +5950,8 @@
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
- NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
+ NetworkRequestInfo nri =
+ new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5939,7 +5960,8 @@
@Override
public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
- PendingIntent operation, @NonNull String callingPackageName) {
+ PendingIntent operation, @NonNull String callingPackageName,
+ @Nullable String callingAttributionTag) {
Objects.requireNonNull(operation, "PendingIntent cannot be null.");
final int callingUid = mDeps.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
@@ -5953,7 +5975,8 @@
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
- NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
+ NetworkRequestInfo nri =
+ new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
if (VDBG) log("pendingListenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -7168,7 +7191,8 @@
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, nri.mUid, nrForCallback.getRequestorPackageName()));
+ nc, nri.mUid, nrForCallback.getRequestorPackageName(),
+ nri.mCallingAttributionTag));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
// For this notification, arg1 contains the blocked status.
@@ -7187,7 +7211,8 @@
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, nri.mUid, nrForCallback.getRequestorPackageName()));
+ netCap, nri.mUid, nrForCallback.getRequestorPackageName(),
+ nri.mCallingAttributionTag));
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index e685ee2..1b6b9d7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -643,8 +643,7 @@
final Sensor sensor = mSensors.valueAt(i);
final int sensorId = mSensors.keyAt(i);
PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
- sensor.getScheduler().recordCrashState();
- sensor.getScheduler().reset();
+ sensor.onBinderDied();
}
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 640838c..baeb3fd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -33,7 +33,6 @@
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.keymaster.HardwareAuthToken;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserManager;
import android.util.Slog;
@@ -63,7 +62,7 @@
/**
* Maintains the state of a single sensor within an instance of the {@link IFace} HAL.
*/
-public class Sensor implements IBinder.DeathRecipient {
+public class Sensor {
private boolean mTestHalEnabled;
@@ -481,7 +480,6 @@
mTag, mScheduler, sensorId, userId, callback);
final ISession newSession = daemon.createSession(sensorId, userId, resultController);
- newSession.asBinder().linkToDeath(this, 0 /* flags */);
mCurrentSession = new Session(mTag, newSession, userId, resultController);
}
@@ -523,24 +521,21 @@
proto.end(sensorToken);
}
- @Override
- public void binderDied() {
- Slog.e(mTag, "Binder died");
- mHandler.post(() -> {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
- if (client instanceof Interruptable) {
- Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
- final Interruptable interruptable = (Interruptable) client;
- interruptable.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
- 0 /* vendorCode */);
+ public void onBinderDied() {
+ final BaseClientMonitor client = mScheduler.getCurrentClient();
+ if (client instanceof Interruptable) {
+ Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ final Interruptable interruptable = (Interruptable) client;
+ interruptable.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
- mScheduler.recordCrashState();
+ FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+ BiometricsProtoEnums.MODALITY_FACE,
+ BiometricsProtoEnums.ISSUE_HAL_DEATH);
+ }
- FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
- BiometricsProtoEnums.MODALITY_FACE,
- BiometricsProtoEnums.ISSUE_HAL_DEATH);
- mCurrentSession = null;
- }
- });
+ mScheduler.recordCrashState();
+ mScheduler.reset();
+ mCurrentSession = null;
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index ced46e1..0bd2f24 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -697,8 +697,7 @@
final Sensor sensor = mSensors.valueAt(i);
final int sensorId = mSensors.keyAt(i);
PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
- sensor.getScheduler().recordCrashState();
- sensor.getScheduler().reset();
+ sensor.onBinderDied();
}
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index f0e7e1c..7e4ee9e7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -31,7 +31,6 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.keymaster.HardwareAuthToken;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserManager;
import android.util.Slog;
@@ -65,7 +64,7 @@
* {@link android.hardware.biometrics.fingerprint.IFingerprint} HAL.
*/
@SuppressWarnings("deprecation")
-class Sensor implements IBinder.DeathRecipient {
+class Sensor {
private boolean mTestHalEnabled;
@@ -461,7 +460,6 @@
mTag, mScheduler, sensorId, userId, callback);
final ISession newSession = daemon.createSession(sensorId, userId, resultController);
- newSession.asBinder().linkToDeath(this, 0 /* flags */);
mCurrentSession = new Session(mTag, newSession, userId, resultController);
}
@@ -503,24 +501,21 @@
proto.end(sensorToken);
}
- @Override
- public void binderDied() {
- Slog.e(mTag, "Binder died");
- mHandler.post(() -> {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
- if (client instanceof Interruptable) {
- Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
- final Interruptable interruptable = (Interruptable) client;
- interruptable.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
- 0 /* vendorCode */);
+ public void onBinderDied() {
+ final BaseClientMonitor client = mScheduler.getCurrentClient();
+ if (client instanceof Interruptable) {
+ Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ final Interruptable interruptable = (Interruptable) client;
+ interruptable.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
- mScheduler.recordCrashState();
+ FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT,
+ BiometricsProtoEnums.ISSUE_HAL_DEATH);
+ }
- FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
- BiometricsProtoEnums.MODALITY_FINGERPRINT,
- BiometricsProtoEnums.ISSUE_HAL_DEATH);
- mCurrentSession = null;
- }
- });
+ mScheduler.recordCrashState();
+ mScheduler.reset();
+ mCurrentSession = null;
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7e6a137..73ebb2e 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -105,17 +105,18 @@
Slog.w(TAG, "No valid info found for display device " + physicalDisplayId);
return;
}
- SurfaceControl.DisplayConfig[] configs = SurfaceControl.getDisplayConfigs(displayToken);
- if (configs == null) {
- // There are no valid configs for this device, so we can't use it
- Slog.w(TAG, "No valid configs found for display device " + physicalDisplayId);
+ SurfaceControl.DisplayMode[] displayModes =
+ SurfaceControl.getDisplayModes(displayToken);
+ if (displayModes == null) {
+ // There are no valid modes for this device, so we can't use it
+ Slog.w(TAG, "No valid modes found for display device " + physicalDisplayId);
return;
}
- int activeConfig = SurfaceControl.getActiveConfig(displayToken);
- if (activeConfig < 0) {
- // There is no active config, and for now we don't have the
+ int activeDisplayMode = SurfaceControl.getActiveDisplayMode(displayToken);
+ if (activeDisplayMode < 0) {
+ // There is no active mode, and for now we don't have the
// policy to set one.
- Slog.w(TAG, "No active config found for display device " + physicalDisplayId);
+ Slog.w(TAG, "No active mode found for display device " + physicalDisplayId);
return;
}
int activeColorMode = SurfaceControl.getActiveColorMode(displayToken);
@@ -127,8 +128,8 @@
physicalDisplayId);
activeColorMode = Display.COLOR_MODE_INVALID;
}
- SurfaceControl.DesiredDisplayConfigSpecs configSpecs =
- SurfaceControl.getDesiredDisplayConfigSpecs(displayToken);
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecsSpecs =
+ SurfaceControl.getDesiredDisplayModeSpecs(displayToken);
int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
Display.HdrCapabilities hdrCapabilities =
SurfaceControl.getHdrCapabilities(displayToken);
@@ -136,13 +137,13 @@
if (device == null) {
// Display was added.
final boolean isDefaultDisplay = mDevices.size() == 0;
- device = new LocalDisplayDevice(displayToken, physicalDisplayId, info,
- configs, activeConfig, configSpecs, colorModes, activeColorMode,
+ device = new LocalDisplayDevice(displayToken, physicalDisplayId, info, displayModes,
+ activeDisplayMode, modeSpecsSpecs, colorModes, activeColorMode,
hdrCapabilities, isDefaultDisplay);
mDevices.put(physicalDisplayId, device);
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
- } else if (device.updateDisplayPropertiesLocked(info, configs, activeConfig,
- configSpecs, colorModes, activeColorMode, hdrCapabilities)) {
+ } else if (device.updateDisplayPropertiesLocked(info, displayModes, activeDisplayMode,
+ modeSpecsSpecs, colorModes, activeColorMode, hdrCapabilities)) {
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
} else {
@@ -189,12 +190,12 @@
// This is only set in the runnable returned from requestDisplayStateLocked.
private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private int mDefaultModeId;
- private int mDefaultConfigGroup;
+ private int mDefaultModeGroup;
private int mActiveModeId;
private DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs =
new DisplayModeDirector.DesiredDisplayModeSpecs();
private boolean mDisplayModeSpecsInvalid;
- private int mActiveConfigId;
+ private int mActiveDisplayModeId;
private int mActiveColorMode;
private Display.HdrCapabilities mHdrCapabilities;
private boolean mAllmSupported;
@@ -204,7 +205,7 @@
private boolean mSidekickActive;
private SidekickInternal mSidekickInternal;
private SurfaceControl.DisplayInfo mDisplayInfo;
- private SurfaceControl.DisplayConfig[] mDisplayConfigs;
+ private SurfaceControl.DisplayMode[] mDisplayModes;
private Spline mSystemBrightnessToNits;
private Spline mNitsToHalBrightness;
private DisplayDeviceConfig mDisplayDeviceConfig;
@@ -213,15 +214,15 @@
new DisplayEventReceiver.FrameRateOverride[0];
LocalDisplayDevice(IBinder displayToken, long physicalDisplayId,
- SurfaceControl.DisplayInfo info, SurfaceControl.DisplayConfig[] configs,
- int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs,
+ SurfaceControl.DisplayInfo info, SurfaceControl.DisplayMode[] displayModes,
+ int activeDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs,
int[] colorModes, int activeColorMode, Display.HdrCapabilities hdrCapabilities,
boolean isDefaultDisplay) {
super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId);
mPhysicalDisplayId = physicalDisplayId;
mIsDefaultDisplay = isDefaultDisplay;
- updateDisplayPropertiesLocked(info, configs, activeConfigId, configSpecs, colorModes,
- activeColorMode, hdrCapabilities);
+ updateDisplayPropertiesLocked(info, displayModes, activeDisplayModeId, modeSpecs,
+ colorModes, activeColorMode, hdrCapabilities);
mSidekickInternal = LocalServices.getService(SidekickInternal.class);
mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay);
mAllmSupported = SurfaceControl.getAutoLowLatencyModeSupport(displayToken);
@@ -241,10 +242,11 @@
* Returns true if there is a change.
**/
public boolean updateDisplayPropertiesLocked(SurfaceControl.DisplayInfo info,
- SurfaceControl.DisplayConfig[] configs,
- int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs,
+ SurfaceControl.DisplayMode[] displayModes,
+ int activeDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs,
int[] colorModes, int activeColorMode, Display.HdrCapabilities hdrCapabilities) {
- boolean changed = updateDisplayConfigsLocked(configs, activeConfigId, configSpecs);
+ boolean changed = updateDisplayModesLocked(
+ displayModes, activeDisplayModeId, modeSpecs);
changed |= updateDisplayInfo(info);
changed |= updateColorModesLocked(colorModes, activeColorMode);
changed |= updateHdrCapabilitiesLocked(hdrCapabilities);
@@ -255,35 +257,35 @@
return changed;
}
- public boolean updateDisplayConfigsLocked(
- SurfaceControl.DisplayConfig[] configs, int activeConfigId,
- SurfaceControl.DesiredDisplayConfigSpecs configSpecs) {
- mDisplayConfigs = Arrays.copyOf(configs, configs.length);
- mActiveConfigId = activeConfigId;
+ public boolean updateDisplayModesLocked(
+ SurfaceControl.DisplayMode[] displayModes, int activeDisplayModeId,
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
+ mDisplayModes = Arrays.copyOf(displayModes, displayModes.length);
+ mActiveDisplayModeId = activeDisplayModeId;
// Build an updated list of all existing modes.
ArrayList<DisplayModeRecord> records = new ArrayList<>();
boolean modesAdded = false;
- for (int i = 0; i < configs.length; i++) {
- SurfaceControl.DisplayConfig config = configs[i];
+ for (int i = 0; i < displayModes.length; i++) {
+ SurfaceControl.DisplayMode mode = displayModes[i];
List<Float> alternativeRefreshRates = new ArrayList<>();
- for (int j = 0; j < configs.length; j++) {
- SurfaceControl.DisplayConfig other = configs[j];
- boolean isAlternative = j != i && other.width == config.width
- && other.height == config.height
- && other.refreshRate != config.refreshRate
- && other.configGroup == config.configGroup;
+ for (int j = 0; j < displayModes.length; j++) {
+ SurfaceControl.DisplayMode other = displayModes[j];
+ boolean isAlternative = j != i && other.width == mode.width
+ && other.height == mode.height
+ && other.refreshRate != mode.refreshRate
+ && other.group == mode.group;
if (isAlternative) {
- alternativeRefreshRates.add(configs[j].refreshRate);
+ alternativeRefreshRates.add(displayModes[j].refreshRate);
}
}
Collections.sort(alternativeRefreshRates);
// First, check to see if we've already added a matching mode. Since not all
// configuration options are exposed via Display.Mode, it's possible that we have
- // multiple DisplayConfigs that would generate the same Display.Mode.
+ // multiple DisplayModess that would generate the same Display.Mode.
boolean existingMode = false;
for (DisplayModeRecord record : records) {
- if (record.hasMatchingMode(config)
+ if (record.hasMatchingMode(mode)
&& refreshRatesEquals(alternativeRefreshRates,
record.mMode.getAlternativeRefreshRates())) {
existingMode = true;
@@ -296,13 +298,13 @@
// If we haven't already added a mode for this configuration to the new set of
// supported modes then check to see if we have one in the prior set of supported
// modes to reuse.
- DisplayModeRecord record = findDisplayModeRecord(config, alternativeRefreshRates);
+ DisplayModeRecord record = findDisplayModeRecord(mode, alternativeRefreshRates);
if (record == null) {
float[] alternativeRates = new float[alternativeRefreshRates.size()];
for (int j = 0; j < alternativeRates.length; j++) {
alternativeRates[j] = alternativeRefreshRates.get(j);
}
- record = new DisplayModeRecord(config, alternativeRates);
+ record = new DisplayModeRecord(mode, alternativeRates);
modesAdded = true;
}
records.add(record);
@@ -312,7 +314,7 @@
DisplayModeRecord activeRecord = null;
for (int i = 0; i < records.size(); i++) {
DisplayModeRecord record = records.get(i);
- if (record.hasMatchingMode(configs[activeConfigId])) {
+ if (record.hasMatchingMode(displayModes[activeDisplayModeId])) {
activeRecord = record;
break;
}
@@ -334,20 +336,20 @@
// Check whether surface flinger spontaneously changed display config specs out from
// under us. If so, schedule a traversal to reapply our display config specs.
if (mDisplayModeSpecs.baseModeId != NO_DISPLAY_MODE_ID) {
- int activeBaseMode = findMatchingModeIdLocked(configSpecs.defaultConfig);
- // If we can't map the defaultConfig index to a mode, then the physical display
- // configs must have changed, and the code below for handling changes to the
- // list of available modes will take care of updating display config specs.
+ int activeBaseMode = findMatchingModeIdLocked(modeSpecs.defaultMode);
+ // If we can't map the defaultMode index to a mode, then the physical display
+ // modes must have changed, and the code below for handling changes to the
+ // list of available modes will take care of updating display mode specs.
if (activeBaseMode != NO_DISPLAY_MODE_ID) {
if (mDisplayModeSpecs.baseModeId != activeBaseMode
|| mDisplayModeSpecs.primaryRefreshRateRange.min
- != configSpecs.primaryRefreshRateMin
+ != modeSpecs.primaryRefreshRateMin
|| mDisplayModeSpecs.primaryRefreshRateRange.max
- != configSpecs.primaryRefreshRateMax
+ != modeSpecs.primaryRefreshRateMax
|| mDisplayModeSpecs.appRequestRefreshRateRange.min
- != configSpecs.appRequestRefreshRateMin
+ != modeSpecs.appRequestRefreshRateMin
|| mDisplayModeSpecs.appRequestRefreshRateRange.max
- != configSpecs.appRequestRefreshRateMax) {
+ != modeSpecs.appRequestRefreshRateMax) {
mDisplayModeSpecsInvalid = true;
sendTraversalRequestLocked();
}
@@ -368,17 +370,17 @@
// For a new display, we need to initialize the default mode ID.
if (mDefaultModeId == NO_DISPLAY_MODE_ID) {
mDefaultModeId = activeRecord.mMode.getModeId();
- mDefaultConfigGroup = configs[activeConfigId].configGroup;
+ mDefaultModeGroup = displayModes[activeDisplayModeId].group;
} else if (modesAdded && activeModeChanged) {
Slog.d(TAG, "New display modes are added and the active mode has changed, "
+ "use active mode as default mode.");
mDefaultModeId = activeRecord.mMode.getModeId();
- mDefaultConfigGroup = configs[activeConfigId].configGroup;
- } else if (findDisplayConfigIdLocked(mDefaultModeId, mDefaultConfigGroup) < 0) {
+ mDefaultModeGroup = displayModes[activeDisplayModeId].group;
+ } else if (findDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) {
Slog.w(TAG, "Default display mode no longer available, using currently"
+ " active mode as default.");
mDefaultModeId = activeRecord.mMode.getModeId();
- mDefaultConfigGroup = configs[activeConfigId].configGroup;
+ mDefaultModeGroup = displayModes[activeDisplayModeId].group;
}
// Determine whether the display mode specs' base mode is still there.
@@ -518,11 +520,11 @@
return true;
}
- private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config,
+ private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayMode mode,
List<Float> alternativeRefreshRates) {
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
- if (record.hasMatchingMode(config)
+ if (record.hasMatchingMode(mode)
&& refreshRatesEquals(alternativeRefreshRates,
record.mMode.getAlternativeRefreshRates())) {
return record;
@@ -554,10 +556,10 @@
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
if (mInfo == null) {
- SurfaceControl.DisplayConfig config = mDisplayConfigs[mActiveConfigId];
+ SurfaceControl.DisplayMode mode = mDisplayModes[mActiveDisplayModeId];
mInfo = new DisplayDeviceInfo();
- mInfo.width = config.width;
- mInfo.height = config.height;
+ mInfo.width = mode.width;
+ mInfo.height = mode.height;
mInfo.modeId = mActiveModeId;
mInfo.defaultModeId = mDefaultModeId;
mInfo.supportedModes = getDisplayModes(mSupportedModes);
@@ -570,16 +572,16 @@
mInfo.supportedColorModes[i] = mSupportedColorModes.get(i);
}
mInfo.hdrCapabilities = mHdrCapabilities;
- mInfo.appVsyncOffsetNanos = config.appVsyncOffsetNanos;
- mInfo.presentationDeadlineNanos = config.presentationDeadlineNanos;
+ mInfo.appVsyncOffsetNanos = mode.appVsyncOffsetNanos;
+ mInfo.presentationDeadlineNanos = mode.presentationDeadlineNanos;
mInfo.state = mState;
mInfo.uniqueId = getUniqueId();
final DisplayAddress.Physical physicalAddress =
DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
mInfo.address = physicalAddress;
mInfo.densityDpi = (int) (mDisplayInfo.density * 160 + 0.5f);
- mInfo.xDpi = config.xDpi;
- mInfo.yDpi = config.yDpi;
+ mInfo.xDpi = mode.xDpi;
+ mInfo.yDpi = mode.yDpi;
mInfo.deviceProductInfo = mDisplayInfo.deviceProductInfo;
// Assume that all built-in displays that have secure output (eg. HDCP) also
@@ -835,16 +837,16 @@
return;
}
- // Find the config Id based on the desired mode specs. In case there is more than one
- // config matching the mode spec, prefer the one that is in the default config group.
- // For now the default config group is taken from the active config when we got the
+ // Find the mode Id based on the desired mode specs. In case there is more than one
+ // mode matching the mode spec, prefer the one that is in the default mode group.
+ // For now the default config mode is taken from the active mode when we got the
// hotplug event for the display. In the future we might want to change the default
- // config based on vendor requirements.
- // Note: We prefer the default config group over the current one as this is the config
+ // mode based on vendor requirements.
+ // Note: We prefer the default mode group over the current one as this is the mode
// group the vendor prefers.
- int baseConfigId = findDisplayConfigIdLocked(displayModeSpecs.baseModeId,
- mDefaultConfigGroup);
- if (baseConfigId < 0) {
+ int baseModeId = findDisplayModeIdLocked(displayModeSpecs.baseModeId,
+ mDefaultModeGroup);
+ if (baseModeId < 0) {
// When a display is hotplugged, it's possible for a mode to be removed that was
// previously valid. Because of the way display changes are propagated through the
// framework, and the caching of the display mode specs in LogicalDisplay, it's
@@ -862,7 +864,7 @@
getHandler().sendMessage(PooledLambda.obtainMessage(
LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
getDisplayTokenLocked(),
- new SurfaceControl.DesiredDisplayConfigSpecs(baseConfigId,
+ new SurfaceControl.DesiredDisplayModeSpecs(baseModeId,
mDisplayModeSpecs.allowGroupSwitching,
mDisplayModeSpecs.primaryRefreshRateRange.min,
mDisplayModeSpecs.primaryRefreshRateRange.max,
@@ -872,13 +874,13 @@
}
private void setDesiredDisplayModeSpecsAsync(IBinder displayToken,
- SurfaceControl.DesiredDisplayConfigSpecs configSpecs) {
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
// Do not lock when calling these SurfaceControl methods because they are sync
// operations that may block for a while when setting display power mode.
- SurfaceControl.setDesiredDisplayConfigSpecs(displayToken, configSpecs);
- final int activePhysIndex = SurfaceControl.getActiveConfig(displayToken);
+ SurfaceControl.setDesiredDisplayModeSpecs(displayToken, modeSpecs);
+ final int activeMode = SurfaceControl.getActiveDisplayMode(displayToken);
synchronized (getSyncRoot()) {
- if (updateActiveModeLocked(activePhysIndex)) {
+ if (updateActiveModeLocked(activeMode)) {
updateDeviceInfoLocked();
}
}
@@ -889,8 +891,8 @@
updateDeviceInfoLocked();
}
- public void onActiveDisplayConfigChangedLocked(int configId) {
- if (updateActiveModeLocked(configId)) {
+ public void onActiveDisplayModeChangedLocked(int modeId) {
+ if (updateActiveModeLocked(modeId)) {
updateDeviceInfoLocked();
}
}
@@ -902,15 +904,15 @@
}
}
- public boolean updateActiveModeLocked(int activeConfigId) {
- if (mActiveConfigId == activeConfigId) {
+ public boolean updateActiveModeLocked(int activeModeId) {
+ if (mActiveDisplayModeId == activeModeId) {
return false;
}
- mActiveConfigId = activeConfigId;
- mActiveModeId = findMatchingModeIdLocked(activeConfigId);
+ mActiveDisplayModeId = activeModeId;
+ mActiveModeId = findMatchingModeIdLocked(activeModeId);
if (mActiveModeId == NO_DISPLAY_MODE_ID) {
- Slog.w(TAG, "In unknown mode after setting allowed configs"
- + ", activeConfigId=" + mActiveConfigId);
+ Slog.w(TAG, "In unknown mode after setting allowed modes"
+ + ", activeModeId=" + mActiveDisplayModeId);
}
return true;
}
@@ -990,7 +992,7 @@
pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
pw.println("mDisplayModeSpecs={" + mDisplayModeSpecs + "}");
pw.println("mDisplayModeSpecsInvalid=" + mDisplayModeSpecsInvalid);
- pw.println("mActiveConfigId=" + mActiveConfigId);
+ pw.println("mActiveDisplayModeId=" + mActiveDisplayModeId);
pw.println("mActiveModeId=" + mActiveModeId);
pw.println("mActiveColorMode=" + mActiveColorMode);
pw.println("mDefaultModeId=" + mDefaultModeId);
@@ -1002,9 +1004,9 @@
pw.println("mGameContentTypeSupported=" + mGameContentTypeSupported);
pw.println("mGameContentTypeRequested=" + mGameContentTypeRequested);
pw.println("mDisplayInfo=" + mDisplayInfo);
- pw.println("mDisplayConfigs=");
- for (int i = 0; i < mDisplayConfigs.length; i++) {
- pw.println(" " + mDisplayConfigs[i]);
+ pw.println("mDisplayModes=");
+ for (int i = 0; i < mDisplayModes.length; i++) {
+ pw.println(" " + mDisplayModes[i]);
}
pw.println("mSupportedModes=");
for (int i = 0; i < mSupportedModes.size(); i++) {
@@ -1014,37 +1016,37 @@
pw.println("mDisplayDeviceConfig=" + mDisplayDeviceConfig);
}
- private int findDisplayConfigIdLocked(int modeId, int configGroup) {
- int matchingConfigId = SurfaceControl.DisplayConfig.INVALID_DISPLAY_CONFIG_ID;
+ private int findDisplayModeIdLocked(int modeId, int modeGroup) {
+ int matchingModeId = SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID;
DisplayModeRecord record = mSupportedModes.get(modeId);
if (record != null) {
- for (int i = 0; i < mDisplayConfigs.length; i++) {
- SurfaceControl.DisplayConfig config = mDisplayConfigs[i];
- if (record.hasMatchingMode(config)) {
- if (matchingConfigId
- == SurfaceControl.DisplayConfig.INVALID_DISPLAY_CONFIG_ID) {
- matchingConfigId = i;
+ for (int i = 0; i < mDisplayModes.length; i++) {
+ SurfaceControl.DisplayMode mode = mDisplayModes[i];
+ if (record.hasMatchingMode(mode)) {
+ if (matchingModeId
+ == SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID) {
+ matchingModeId = i;
}
- // Prefer to return a config that matches the configGroup
- if (config.configGroup == configGroup) {
+ // Prefer to return a mode that matches the modeGroup
+ if (mode.group == modeGroup) {
return i;
}
}
}
}
- return matchingConfigId;
+ return matchingModeId;
}
- private int findMatchingModeIdLocked(int configId) {
- if (configId < 0 || configId >= mDisplayConfigs.length) {
- Slog.e(TAG, "Invalid display config index " + configId);
+ private int findMatchingModeIdLocked(int modeId) {
+ if (modeId < 0 || modeId >= mDisplayModes.length) {
+ Slog.e(TAG, "Invalid display config index " + modeId);
return NO_DISPLAY_MODE_ID;
}
- SurfaceControl.DisplayConfig config = mDisplayConfigs[configId];
+ SurfaceControl.DisplayMode mode = mDisplayModes[modeId];
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
- if (record.hasMatchingMode(config)) {
+ if (record.hasMatchingMode(mode)) {
return record.mMode.getModeId();
}
}
@@ -1091,30 +1093,29 @@
}
/**
- * Keeps track of a display configuration.
+ * Keeps track of a display mode.
*/
private static final class DisplayModeRecord {
public final Display.Mode mMode;
- DisplayModeRecord(SurfaceControl.DisplayConfig config,
+ DisplayModeRecord(SurfaceControl.DisplayMode mode,
float[] alternativeRefreshRates) {
- mMode = createMode(config.width, config.height, config.refreshRate,
+ mMode = createMode(mode.width, mode.height, mode.refreshRate,
alternativeRefreshRates);
}
/**
- * Returns whether the mode generated by the given DisplayConfig matches the mode
+ * Returns whether the mode generated by the given DisplayModes matches the mode
* contained by the record modulo mode ID.
*
- * Note that this doesn't necessarily mean that the DisplayConfigs are identical, just
+ * Note that this doesn't necessarily mean that the DisplayModes are identical, just
* that they generate identical modes.
*/
- public boolean hasMatchingMode(SurfaceControl.DisplayConfig config) {
- int modeRefreshRate = Float.floatToIntBits(mMode.getRefreshRate());
- int configRefreshRate = Float.floatToIntBits(config.refreshRate);
- return mMode.getPhysicalWidth() == config.width
- && mMode.getPhysicalHeight() == config.height
- && modeRefreshRate == configRefreshRate;
+ public boolean hasMatchingMode(SurfaceControl.DisplayMode mode) {
+ return mMode.getPhysicalWidth() == mode.width
+ && mMode.getPhysicalHeight() == mode.height
+ && Float.floatToIntBits(mMode.getRefreshRate())
+ == Float.floatToIntBits(mode.refreshRate);
}
public String toString() {
@@ -1131,7 +1132,7 @@
public interface DisplayEventListener {
void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected);
- void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId);
+ void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId);
void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
DisplayEventReceiver.FrameRateOverride[] overrides);
@@ -1141,7 +1142,7 @@
private final DisplayEventListener mListener;
ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) {
super(looper, VSYNC_SOURCE_APP,
- EVENT_REGISTRATION_CONFIG_CHANGED_FLAG
+ EVENT_REGISTRATION_MODE_CHANGED_FLAG
| EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG);
mListener = listener;
}
@@ -1152,8 +1153,8 @@
}
@Override
- public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
- mListener.onConfigChanged(timestampNanos, physicalDisplayId, configId);
+ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
+ mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId);
}
@Override
@@ -1176,23 +1177,23 @@
}
@Override
- public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
if (DEBUG) {
- Slog.d(TAG, "onConfigChanged("
+ Slog.d(TAG, "onModeChanged("
+ "timestampNanos=" + timestampNanos
+ ", physicalDisplayId=" + physicalDisplayId
- + ", configId=" + configId + ")");
+ + ", modeId=" + modeId + ")");
}
synchronized (getSyncRoot()) {
LocalDisplayDevice device = mDevices.get(physicalDisplayId);
if (device == null) {
if (DEBUG) {
- Slog.d(TAG, "Received config change for unhandled physical display: "
+ Slog.d(TAG, "Received mode change for unhandled physical display: "
+ "physicalDisplayId=" + physicalDisplayId);
}
return;
}
- device.onActiveDisplayConfigChangedLocked(configId);
+ device.onActiveDisplayModeChangedLocked(modeId);
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 5ca255c..4e97411 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -234,12 +234,7 @@
private final SparseBooleanArray mIsVibrating = new SparseBooleanArray();
// State for lid switch
- // Lock for the lid switch state. Held when triggering callbacks to guarantee lid switch events
- // are delivered in order. For ex, when a new lid switch callback is registered the lock is held
- // while the callback is processing the initial lid switch event which guarantees that any
- // events that occur at the same time are delivered after the callback has returned.
private final Object mLidSwitchLock = new Object();
- @GuardedBy("mLidSwitchLock")
private List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>();
// State for the currently installed input filter.
@@ -387,6 +382,9 @@
public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
+ /** Indicates an open state for the lid switch. */
+ public static final int SW_STATE_LID_OPEN = 0;
+
/** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
final boolean mUseDevInputEventForAudioJack;
@@ -422,18 +420,13 @@
}
void registerLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
+ boolean lidOpen;
synchronized (mLidSwitchLock) {
mLidSwitchCallbacks.add(callback);
-
- // Skip triggering the initial callback if the system is not yet ready as the switch
- // state will be reported as KEY_STATE_UNKNOWN. The callback will be triggered in
- // systemRunning().
- if (mSystemReady) {
- boolean lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)
- == KEY_STATE_UP;
- callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);
- }
+ lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)
+ == SW_STATE_LID_OPEN;
}
+ callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);
}
void unregisterLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
@@ -481,18 +474,7 @@
}
mNotificationManager = (NotificationManager)mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
-
- synchronized (mLidSwitchLock) {
- mSystemReady = true;
-
- // Send the initial lid switch state to any callback registered before the system was
- // ready.
- int switchState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID);
- for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
- LidSwitchCallback callback = mLidSwitchCallbacks.get(i);
- callback.notifyLidSwitchChanged(0 /* whenNanos */, switchState == KEY_STATE_UP);
- }
- }
+ mSystemReady = true;
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -2349,13 +2331,14 @@
if ((switchMask & SW_LID_BIT) != 0) {
final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
+
+ ArrayList<LidSwitchCallback> callbacksCopy;
synchronized (mLidSwitchLock) {
- if (mSystemReady) {
- for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
- LidSwitchCallback callbacks = mLidSwitchCallbacks.get(i);
- callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
- }
- }
+ callbacksCopy = new ArrayList<>(mLidSwitchCallbacks);
+ }
+ for (int i = 0; i < callbacksCopy.size(); i++) {
+ LidSwitchCallback callbacks = callbacksCopy.get(i);
+ callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
}
}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 142f64f..ea759bf 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -66,6 +66,7 @@
import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
@@ -882,6 +883,20 @@
}
@Override
+ public void addProviderRequestListener(IProviderRequestListener listener) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.addProviderRequestListener(listener);
+ }
+ }
+
+ @Override
+ public void removeProviderRequestListener(IProviderRequestListener listener) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.removeProviderRequestListener(listener);
+ }
+ }
+
+ @Override
public void injectGnssMeasurementCorrections(GnssMeasurementCorrections corrections) {
if (mGnssManagerService != null) {
mGnssManagerService.injectGnssMeasurementCorrections(corrections);
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 221d4fb..48a012e 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -55,6 +55,7 @@
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.LocationRequest;
import android.location.LocationResult;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.location.provider.ProviderRequest;
import android.location.util.identity.CallerIdentity;
@@ -117,6 +118,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
/**
@@ -1219,6 +1221,8 @@
@GuardedBy("mLock")
private final ArrayList<ProviderEnabledListener> mEnabledListeners;
+ private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
+
protected final LocationManagerInternal mLocationManagerInternal;
protected final SettingsHelper mSettingsHelper;
protected final UserInfoHelper mUserHelper;
@@ -1279,6 +1283,7 @@
mLastLocations = new SparseArray<>(2);
mEnabledListeners = new ArrayList<>();
+ mProviderRequestListeners = new CopyOnWriteArrayList<>();
mLocationManagerInternal = Objects.requireNonNull(
LocalServices.getService(LocationManagerInternal.class));
@@ -1344,6 +1349,7 @@
// if external entities are registering listeners it's their responsibility to
// unregister them before stopManager() is called
Preconditions.checkState(mEnabledListeners.isEmpty());
+ mProviderRequestListeners.clear();
mEnabled.clear();
mLastLocations.clear();
@@ -1404,6 +1410,16 @@
}
}
+ /** Add a {@link IProviderRequestListener}. */
+ public void addProviderRequestListener(IProviderRequestListener listener) {
+ mProviderRequestListeners.add(listener);
+ }
+
+ /** Remove a {@link IProviderRequestListener}. */
+ public void removeProviderRequestListener(IProviderRequestListener listener) {
+ mProviderRequestListeners.remove(listener);
+ }
+
public void setRealProvider(@Nullable AbstractLocationProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mState != STATE_STOPPED);
@@ -1873,8 +1889,7 @@
Preconditions.checkState(delayMs >= 0 && delayMs <= newRequest.getIntervalMillis());
if (delayMs < MIN_REQUEST_DELAY_MS) {
- mLocationEventLog.logProviderUpdateRequest(mName, newRequest);
- mProvider.getController().setRequest(newRequest);
+ setProviderRequest(newRequest);
} else {
if (D) {
Log.d(TAG, mName + " provider delaying request update " + newRequest + " by "
@@ -1886,8 +1901,7 @@
public void onAlarm() {
synchronized (mLock) {
if (mDelayedRegister == this) {
- mLocationEventLog.logProviderUpdateRequest(mName, newRequest);
- mProvider.getController().setRequest(newRequest);
+ setProviderRequest(newRequest);
mDelayedRegister = null;
}
}
@@ -1906,8 +1920,23 @@
Preconditions.checkState(Thread.holdsLock(mLock));
}
- mLocationEventLog.logProviderUpdateRequest(mName, ProviderRequest.EMPTY_REQUEST);
- mProvider.getController().setRequest(ProviderRequest.EMPTY_REQUEST);
+ setProviderRequest(ProviderRequest.EMPTY_REQUEST);
+ }
+
+ @GuardedBy("mLock")
+ private void setProviderRequest(ProviderRequest request) {
+ mLocationEventLog.logProviderUpdateRequest(mName, request);
+ mProvider.getController().setRequest(request);
+
+ FgThread.getHandler().post(() -> {
+ for (IProviderRequestListener listener : mProviderRequestListeners) {
+ try {
+ listener.onProviderRequestChanged(mName, request);
+ } catch (RemoteException e) {
+ mProviderRequestListeners.remove(listener);
+ }
+ }
+ });
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index 70dea73..87e170a 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -62,6 +63,13 @@
private static final int PACKAGE_MANAGER_COMMON_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ /**
+ * Denotes the duration during which a media button receiver will be exempted from
+ * FGS-from-BG restriction and so will be allowed to start an FGS even if it is in the
+ * background state while it receives a media key event.
+ */
+ private static final long FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS = 10_000;
+
private final int mUserId;
private final PendingIntent mPendingIntent;
private final ComponentName mComponentName;
@@ -186,6 +194,9 @@
// TODO: Find a way to also send PID/UID in secure way.
mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackageName);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setTemporaryAppWhitelistDuration(
+ FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS);
if (mPendingIntent != null) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to the last known PendingIntent "
@@ -193,7 +204,8 @@
}
try {
mPendingIntent.send(
- context, resultCode, mediaButtonIntent, onFinishedListener, handler);
+ context, resultCode, mediaButtonIntent, onFinishedListener, handler,
+ /* requiredPermission= */ null, options.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Error sending key event to media button receiver " + mPendingIntent, e);
return false;
@@ -216,7 +228,8 @@
break;
default:
// Legacy behavior for other cases.
- context.sendBroadcastAsUser(mediaButtonIntent, userHandle);
+ context.sendBroadcastAsUser(mediaButtonIntent, userHandle,
+ /* receiverPermission= */ null, options.toBundle());
}
} catch (Exception e) {
Log.w(TAG, "Error sending media button to the restored intent "
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 8f19158..e24e5bb 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -542,8 +542,6 @@
userState.removeHosts(domains);
}
}
-
- mConnection.scheduleWriteSettings();
}
@Nullable
@@ -849,6 +847,7 @@
public void setLegacyUserState(@NonNull String packageName, @UserIdInt int userId, int state) {
mEnforcer.callerIsLegacyUserSelector(mConnection.getCallingUid());
mLegacySettings.add(packageName, userId, state);
+ mConnection.scheduleWriteSettings();
}
@Override
@@ -1067,6 +1066,8 @@
}
}
}
+
+ mConnection.scheduleWriteSettings();
}
/**
@@ -1124,6 +1125,8 @@
}
}
}
+
+ mConnection.scheduleWriteSettings();
}
@Override
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
index 65ea78d..9389e63 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
@@ -153,18 +153,22 @@
UUID domainSetId = pair.first;
String packageName = pair.second;
- DomainVerificationInfo set;
+ DomainVerificationInfo info;
try {
- set = mManager.getDomainVerificationInfo(packageName);
+ info = mManager.getDomainVerificationInfo(packageName);
} catch (PackageManager.NameNotFoundException ignored) {
return true;
}
- if (!Objects.equals(domainSetId, set.getIdentifier())) {
+ if (info == null) {
return true;
}
- Set<String> successfulDomains = new ArraySet<>(set.getHostToStateMap().keySet());
+ if (!Objects.equals(domainSetId, info.getIdentifier())) {
+ return true;
+ }
+
+ Set<String> successfulDomains = new ArraySet<>(info.getHostToStateMap().keySet());
successfulDomains.removeAll(response.failedDomains);
int callingUid = response.callingUid;
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
index 03d7664..57cf986 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
@@ -150,7 +150,7 @@
@Override
public void resolveRotation(
@NonNull RotationResolverCallbackInternal callbackInternal, int proposedRotation,
- int currentRotation, String packageName, long timeout,
+ int currentRotation, long timeout,
@NonNull CancellationSignal cancellationSignalInternal) {
Objects.requireNonNull(callbackInternal);
Objects.requireNonNull(cancellationSignalInternal);
@@ -159,7 +159,8 @@
final RotationResolverManagerPerUserService service = getServiceForUserLocked(
UserHandle.getCallingUserId());
service.resolveRotationLocked(callbackInternal, proposedRotation,
- currentRotation, packageName, timeout, cancellationSignalInternal);
+ currentRotation, /* packageName */ "", timeout,
+ cancellationSignalInternal);
} else {
Slog.w(TAG, "Rotation Resolver service is disabled.");
callbackInternal.onFailure(ROTATION_RESULT_FAILURE_CANCELLED);
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 263776c..5e681c6 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -2509,7 +2509,6 @@
try {
// force procstats to flush & combine old files into one store
long lastHighWaterMark = readProcStatsHighWaterMark(section);
- List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
ProtoOutputStream[] protoStreams = new ProtoOutputStream[MAX_PROCSTATS_SHARDS];
for (int i = 0; i < protoStreams.length; i++) {
@@ -2519,7 +2518,7 @@
ProcessStats procStats = new ProcessStats(false);
// Force processStatsService to aggregate all in-storage and in-memory data.
long highWaterMark = processStatsService.getCommittedStatsMerged(
- lastHighWaterMark, section, true, statsFiles, procStats);
+ lastHighWaterMark, section, true, null, procStats);
procStats.dumpAggregatedProtoForStatsd(protoStreams, MAX_PROCSTATS_RAW_SHARD_SIZE);
for (int i = 0; i < protoStreams.length; i++) {
diff --git a/services/core/java/com/android/server/tracing/OWNERS b/services/core/java/com/android/server/tracing/OWNERS
new file mode 100644
index 0000000..f5de4eb
--- /dev/null
+++ b/services/core/java/com/android/server/tracing/OWNERS
@@ -0,0 +1,2 @@
+cfijalkovich@google.com
+carmenjackson@google.com
diff --git a/services/core/java/com/android/server/tracing/TracingServiceProxy.java b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
new file mode 100644
index 0000000..8f22748
--- /dev/null
+++ b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.tracing;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.UserHandle;
+import android.tracing.ITracingServiceProxy;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+/**
+ * TracingServiceProxy is the system_server intermediary between the Perfetto tracing daemon and the
+ * system tracing app Traceur.
+ *
+ * @hide
+ */
+public class TracingServiceProxy extends SystemService {
+ private static final String TAG = "TracingServiceProxy";
+
+ public static final String TRACING_SERVICE_PROXY_BINDER_NAME = "tracing.proxy";
+
+ private static final String TRACING_APP_PACKAGE_NAME = "com.android.traceur";
+ private static final String TRACING_APP_ACTIVITY = "com.android.traceur.StopTraceService";
+
+ // Keep this in sync with the definitions in TraceService
+ private static final String INTENT_ACTION_NOTIFY_SESSION_STOPPED =
+ "com.android.traceur.NOTIFY_SESSION_STOPPED";
+ private static final String INTENT_ACTION_NOTIFY_SESSION_STOLEN =
+ "com.android.traceur.NOTIFY_SESSION_STOLEN";
+
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+
+ private final ITracingServiceProxy.Stub mTracingServiceProxy = new ITracingServiceProxy.Stub() {
+ /**
+ * Notifies system tracing app that a tracing session has ended. If a session is repurposed
+ * for use in a bugreport, sessionStolen can be set to indicate that tracing has ended but
+ * there is no buffer available to dump.
+ */
+ @Override
+ public void notifyTraceSessionEnded(boolean sessionStolen) {
+ notifyTraceur(sessionStolen);
+ }
+ };
+
+ public TracingServiceProxy(Context context) {
+ super(context);
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(TRACING_SERVICE_PROXY_BINDER_NAME, mTracingServiceProxy);
+ }
+
+ private void notifyTraceur(boolean sessionStolen) {
+ final Intent intent = new Intent();
+
+ try {
+ // Validate that Traceur is a system app.
+ PackageInfo info = mPackageManager.getPackageInfo(TRACING_APP_PACKAGE_NAME,
+ PackageManager.MATCH_SYSTEM_ONLY);
+
+ intent.setClassName(info.packageName, TRACING_APP_ACTIVITY);
+ if (sessionStolen) {
+ intent.setAction(INTENT_ACTION_NOTIFY_SESSION_STOLEN);
+ } else {
+ intent.setAction(INTENT_ACTION_NOTIFY_SESSION_STOPPED);
+ }
+
+ try {
+ mContext.startForegroundServiceAsUser(intent, UserHandle.SYSTEM);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to notifyTraceSessionEnded", e);
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Failed to locate Traceur", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 5ec527a..3726407 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -16,6 +16,7 @@
package com.android.server.vcn;
+import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
import android.net.NetworkCapabilities;
@@ -225,7 +226,7 @@
private void handleConfigUpdated(@NonNull VcnConfig config) {
// TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode()
- Slog.v(getLogTag(), String.format("Config updated: config = %s", config.hashCode()));
+ Slog.v(getLogTag(), "Config updated: config = " + config.hashCode());
mConfig = config;
@@ -251,17 +252,29 @@
private void handleNetworkRequested(
@NonNull NetworkRequest request, int score, int providerId) {
if (score > getNetworkScore()) {
- Slog.v(getLogTag(),
- "Request already satisfied by higher-scoring (" + score + ") network from "
- + "provider " + providerId + ": " + request);
+ if (VDBG) {
+ Slog.v(
+ getLogTag(),
+ "Request already satisfied by higher-scoring ("
+ + score
+ + ") network from "
+ + "provider "
+ + providerId
+ + ": "
+ + request);
+ }
return;
}
// If preexisting VcnGatewayConnection(s) satisfy request, return
for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
- Slog.v(getLogTag(),
- "Request already satisfied by existing VcnGatewayConnection: " + request);
+ if (VDBG) {
+ Slog.v(
+ getLogTag(),
+ "Request already satisfied by existing VcnGatewayConnection: "
+ + request);
+ }
return;
}
}
@@ -308,7 +321,7 @@
}
private String getLogTag() {
- return String.format("%s [%d]", TAG, mSubscriptionGroup.hashCode());
+ return TAG + " [" + mSubscriptionGroup.hashCode() + "]";
}
/** Retrieves the network score for a VCN Network */
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 9ecdf1b..2503e81 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -75,6 +75,7 @@
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -297,9 +298,9 @@
private static final int EVENT_SETUP_COMPLETED = 6;
private static class EventSetupCompletedInfo implements EventInfo {
- @NonNull public final ChildSessionConfiguration childSessionConfig;
+ @NonNull public final VcnChildSessionConfiguration childSessionConfig;
- EventSetupCompletedInfo(@NonNull ChildSessionConfiguration childSessionConfig) {
+ EventSetupCompletedInfo(@NonNull VcnChildSessionConfiguration childSessionConfig) {
this.childSessionConfig = Objects.requireNonNull(childSessionConfig);
}
@@ -471,7 +472,7 @@
* <p>Set in Connected and Migrating states, always @NonNull in Connected, Migrating
* states, @Nullable otherwise.
*/
- private ChildSessionConfiguration mChildConfig;
+ private VcnChildSessionConfiguration mChildConfig;
/**
* The active network agent.
@@ -659,7 +660,7 @@
new EventTransformCreatedInfo(direction, transform));
}
- private void childOpened(int token, @NonNull ChildSessionConfiguration childConfig) {
+ private void childOpened(int token, @NonNull VcnChildSessionConfiguration childConfig) {
sendMessage(EVENT_SETUP_COMPLETED, token, new EventSetupCompletedInfo(childConfig));
}
@@ -1008,7 +1009,7 @@
protected void updateNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull NetworkAgent agent,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
@@ -1020,7 +1021,7 @@
protected NetworkAgent buildNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
@@ -1068,15 +1069,15 @@
protected void setupInterface(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
setupInterface(token, tunnelIface, childConfig, null);
}
protected void setupInterface(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig,
- @Nullable ChildSessionConfiguration oldChildConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig,
+ @Nullable VcnChildSessionConfiguration oldChildConfig) {
try {
final Set<LinkAddress> newAddrs =
new ArraySet<>(childConfig.getInternalAddresses());
@@ -1189,7 +1190,7 @@
protected void setupInterfaceAndNetworkAgent(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
setupInterface(token, tunnelIface, childConfig);
if (mNetworkAgent == null) {
@@ -1207,7 +1208,64 @@
*/
class RetryTimeoutState extends ActiveBaseState {
@Override
- protected void processStateMsg(Message msg) {}
+ protected void enterState() throws Exception {
+ // Reset upon entry to ConnectedState
+ mFailedAttempts++;
+
+ if (mUnderlying == null) {
+ Slog.wtf(TAG, "Underlying network was null in retry state");
+ transitionTo(mDisconnectedState);
+ } else {
+ sendMessageDelayed(
+ EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken, getNextRetryIntervalsMs());
+ }
+ }
+
+ @Override
+ protected void processStateMsg(Message msg) {
+ switch (msg.what) {
+ case EVENT_UNDERLYING_NETWORK_CHANGED:
+ final UnderlyingNetworkRecord oldUnderlying = mUnderlying;
+ mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+ // If new underlying is null, all networks were lost; go back to disconnected.
+ if (mUnderlying == null) {
+ removeMessages(EVENT_RETRY_TIMEOUT_EXPIRED);
+
+ transitionTo(mDisconnectedState);
+ return;
+ } else if (oldUnderlying != null
+ && mUnderlying.network.equals(oldUnderlying.network)) {
+ // If the network has not changed, do nothing.
+ return;
+ }
+
+ // Fallthrough
+ case EVENT_RETRY_TIMEOUT_EXPIRED:
+ removeMessages(EVENT_RETRY_TIMEOUT_EXPIRED);
+
+ transitionTo(mConnectingState);
+ break;
+ case EVENT_DISCONNECT_REQUESTED:
+ handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+ break;
+ default:
+ logUnhandledMessage(msg);
+ break;
+ }
+ }
+
+ private long getNextRetryIntervalsMs() {
+ final int retryDelayIndex = mFailedAttempts - 1;
+ final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMs();
+
+ // Repeatedly use last item in retry timeout list.
+ if (retryDelayIndex >= retryIntervalsMs.length) {
+ return retryIntervalsMs[retryIntervalsMs.length - 1];
+ }
+
+ return retryIntervalsMs[retryDelayIndex];
+ }
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -1277,7 +1335,7 @@
private static LinkProperties buildConnectedLinkProperties(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(tunnelIface.getInterfaceName());
@@ -1328,17 +1386,25 @@
}
}
- private class ChildSessionCallbackImpl implements ChildSessionCallback {
+ /** Implementation of ChildSessionCallback, exposed for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public class VcnChildSessionCallback implements ChildSessionCallback {
private final int mToken;
- ChildSessionCallbackImpl(int token) {
+ VcnChildSessionCallback(int token) {
mToken = token;
}
+ /** Internal proxy method for injecting of mocked ChildSessionConfiguration */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void onOpened(@NonNull VcnChildSessionConfiguration childConfig) {
+ Slog.v(TAG, "ChildOpened for token " + mToken);
+ childOpened(mToken, childConfig);
+ }
+
@Override
public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
- Slog.v(TAG, "ChildOpened for token " + mToken);
- childOpened(mToken, childConfig);
+ onOpened(new VcnChildSessionConfiguration(childConfig));
}
@Override
@@ -1421,7 +1487,7 @@
buildIkeParams(),
buildChildParams(),
new IkeSessionCallbackImpl(token),
- new ChildSessionCallbackImpl(token));
+ new VcnChildSessionCallback(token));
}
/** External dependencies used by VcnGatewayConnection, for injection in tests */
@@ -1458,6 +1524,35 @@
}
}
+ /**
+ * Proxy implementation of Child Session Configuration, used for testing.
+ *
+ * <p>This wrapper allows mocking of the final, parcelable ChildSessionConfiguration object for
+ * testing purposes. This is the unfortunate result of mockito-inline (for mocking final
+ * classes) not working properly with system services & associated classes.
+ *
+ * <p>This class MUST EXCLUSIVELY be a passthrough, proxying calls directly to the actual
+ * ChildSessionConfiguration.
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class VcnChildSessionConfiguration {
+ private final ChildSessionConfiguration mChildConfig;
+
+ public VcnChildSessionConfiguration(ChildSessionConfiguration childConfig) {
+ mChildConfig = childConfig;
+ }
+
+ /** Retrieves the addresses to be used inside the tunnel. */
+ public List<LinkAddress> getInternalAddresses() {
+ return mChildConfig.getInternalAddresses();
+ }
+
+ /** Retrieves the DNS servers to be used inside the tunnel. */
+ public List<InetAddress> getInternalDnsServers() {
+ return mChildConfig.getInternalDnsServers();
+ }
+ }
+
/** Proxy implementation of IKE session, used for testing. */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class VcnIkeSession {
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index fe4ea30..bfeec01 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -16,6 +16,8 @@
package com.android.server.vcn;
+import static com.android.server.VcnManagementService.VDBG;
+
import android.annotation.NonNull;
import android.content.Context;
import android.net.NetworkProvider;
@@ -83,11 +85,16 @@
@Override
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
- Slog.v(
- TAG,
- String.format(
- "Network requested: Request = %s, score = %d, providerId = %d",
- request, score, providerId));
+ if (VDBG) {
+ Slog.v(
+ TAG,
+ "Network requested: Request = "
+ + request
+ + ", score = "
+ + score
+ + ", providerId = "
+ + providerId);
+ }
final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 35611c0..b106657 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -1499,6 +1499,21 @@
}
@Override
+ public boolean canUseRotationResolver() {
+ if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) return false;
+
+ switch (mCurrentAppOrientation) {
+ case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
+ case ActivityInfo.SCREEN_ORIENTATION_USER:
+ case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
+ case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
+ case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
+ return true;
+ }
+ return false;
+ }
+
+ @Override
public void onProposedRotationChanged(int rotation) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation);
Runnable r = mRunnableCache.get(rotation, null);
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index e18219e..622fe05 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -497,7 +497,7 @@
void notifyTaskDisplayChanged(int taskId, int newDisplayId) {
final Message msg = mHandler.obtainMessage(NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG,
taskId, newDisplayId);
- forAllLocalListeners(mNotifyTaskStackChanged, msg);
+ forAllLocalListeners(mNotifyTaskDisplayChanged, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java
index da31bb2..5ef9420 100644
--- a/services/core/java/com/android/server/wm/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java
@@ -16,25 +16,36 @@
package com.android.server.wm;
+import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER;
+
import static com.android.server.wm.WindowOrientationListenerProto.ENABLED;
import static com.android.server.wm.WindowOrientationListenerProto.ROTATION;
+import android.app.ActivityThread;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.rotationresolver.RotationResolverInternal;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Surface;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.LocalServices;
import java.io.PrintWriter;
import java.util.List;
+import java.util.Set;
/**
* A special helper class used by the WindowManager
@@ -55,6 +66,9 @@
private static final boolean USE_GRAVITY_SENSOR = false;
private static final int DEFAULT_BATCH_LATENCY = 100000;
+ private static final int DEFAULT_ROTATION_RESOLVER_ENABLED = 0; // disabled
+ private static final String KEY_ROTATION_RESOLVER_TIMEOUT = "rotation_resolver_timeout_millis";
+ private static final long DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS = 700L;
private Handler mHandler;
private SensorManager mSensorManager;
@@ -62,7 +76,13 @@
private int mRate;
private String mSensorType;
private Sensor mSensor;
- private OrientationJudge mOrientationJudge;
+
+ @VisibleForTesting
+ OrientationJudge mOrientationJudge;
+
+ @VisibleForTesting
+ RotationResolverInternal mRotationResolverService;
+
private int mCurrentRotation = -1;
private final Context mContext;
private final WindowManagerConstants mConstants;
@@ -256,6 +276,32 @@
}
/**
+ * Returns true if the current status of the phone is suitable for using rotation resolver
+ * service.
+ *
+ * To reduce the power consumption of rotation resolver service, rotation query should run less
+ * frequently than other low power orientation sensors. This method is used to check whether
+ * the current status of the phone is necessary to request a suggested screen rotation from the
+ * rotation resolver service. Note that it always returns {@code false} in the base class. It
+ * should be overridden in the derived classes.
+ */
+ public boolean canUseRotationResolver() {
+ return false;
+ }
+
+ /**
+ * Returns true if the rotation resolver feature is enabled by setting. It means {@link
+ * WindowOrientationListener} will then ask {@link RotationResolverInternal} for the appropriate
+ * screen rotation.
+ */
+ @VisibleForTesting
+ boolean isRotationResolverEnabled() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.CAMERA_AUTOROTATE, DEFAULT_ROTATION_RESOLVER_ENABLED,
+ UserHandle.USER_CURRENT) == 1;
+ }
+
+ /**
* Called when the rotation view of the device has changed.
*
* This method is called whenever the orientation becomes certain of an orientation.
@@ -1045,6 +1091,30 @@
private int mProposedRotation = -1;
private int mDesiredRotation = -1;
private boolean mRotationEvaluationScheduled;
+ private long mRotationResolverTimeoutMillis;
+
+ OrientationSensorJudge() {
+ super();
+ setupRotationResolverParameters();
+ }
+
+ private void setupRotationResolverParameters() {
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_WINDOW_MANAGER,
+ ActivityThread.currentApplication().getMainExecutor(), (properties) -> {
+ final Set<String> keys = properties.getKeyset();
+ if (keys.contains(KEY_ROTATION_RESOLVER_TIMEOUT)) {
+ readRotationResolverParameters();
+ }
+ });
+ readRotationResolverParameters();
+ }
+
+ private void readRotationResolverParameters() {
+ mRotationResolverTimeoutMillis = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_ROTATION_RESOLVER_TIMEOUT,
+ DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS);
+ }
@Override
public int getProposedRotationLocked() {
@@ -1069,19 +1139,13 @@
@Override
public void onSensorChanged(SensorEvent event) {
- int newRotation;
-
int reportedRotation = (int) event.values[0];
if (reportedRotation < 0 || reportedRotation > 3) {
return;
}
- synchronized (mLock) {
- mDesiredRotation = reportedRotation;
- newRotation = evaluateRotationChangeLocked();
- }
- if (newRotation >= 0) {
- onProposedRotationChanged(newRotation);
+ // Log raw sensor rotation.
+ if (evaluateRotationChangeLocked() >= 0) {
if (mConstants.mRawSensorLoggingEnabled) {
FrameworkStatsLog.write(
FrameworkStatsLog.DEVICE_ROTATED,
@@ -1089,6 +1153,35 @@
rotationToLogEnum(reportedRotation));
}
}
+
+ if (isRotationResolverEnabled() && canUseRotationResolver()) {
+ if (mRotationResolverService == null) {
+ mRotationResolverService = LocalServices.getService(
+ RotationResolverInternal.class);
+ }
+
+ final CancellationSignal cancellationSignal = new CancellationSignal();
+ mRotationResolverService.resolveRotation(
+ new RotationResolverInternal.RotationResolverCallbackInternal() {
+ @Override
+ public void onSuccess(int result) {
+ finalizeRotation(result);
+ }
+
+ @Override
+ public void onFailure(int error) {
+ finalizeRotation(reportedRotation);
+ }
+ },
+ reportedRotation,
+ mCurrentRotation,
+ mRotationResolverTimeoutMillis,
+ cancellationSignal);
+ getHandler().postDelayed(cancellationSignal::cancel,
+ mRotationResolverTimeoutMillis);
+ } else {
+ finalizeRotation(reportedRotation);
+ }
}
@Override
@@ -1131,6 +1224,17 @@
return -1;
}
+ private void finalizeRotation(int reportedRotation) {
+ int newRotation;
+ synchronized (mLock) {
+ mDesiredRotation = reportedRotation;
+ newRotation = evaluateRotationChangeLocked();
+ }
+ if (newRotation >= 0) {
+ onProposedRotationChanged(newRotation);
+ }
+ }
+
private boolean isDesiredRotationAcceptableLocked(long now) {
if (mTouching) {
return false;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7a4c611..98c3b99 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -186,6 +186,7 @@
import com.android.server.testharness.TestHarnessModeService;
import com.android.server.textclassifier.TextClassificationManagerService;
import com.android.server.textservices.TextServicesManagerService;
+import com.android.server.tracing.TracingServiceProxy;
import com.android.server.trust.TrustManagerService;
import com.android.server.tv.TvInputManagerService;
import com.android.server.tv.TvRemoteService;
@@ -2483,6 +2484,11 @@
mSystemServiceManager.startService(AppBindingService.Lifecycle.class);
t.traceEnd();
+ // Perfetto TracingServiceProxy
+ t.traceBegin("startTracingServiceProxy");
+ mSystemServiceManager.startService(TracingServiceProxy.class);
+ t.traceEnd();
+
// It is now time to start up the app processes...
t.traceBegin("MakeVibratorServiceReady");
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
new file mode 100644
index 0000000..5792e02
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.verify.domain
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.PackageUserState
+import android.content.pm.verify.domain.DomainVerificationManager
+import android.content.pm.parsing.component.ParsedActivity
+import android.content.pm.parsing.component.ParsedIntentInfo
+import android.os.Build
+import android.os.Process
+import android.util.ArraySet
+import android.util.SparseArray
+import com.android.server.pm.PackageSetting
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
+import com.android.server.pm.verify.domain.DomainVerificationService
+import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.testutils.mockThrowOnUnmocked
+import com.android.server.testutils.spyThrowOnUnmocked
+import com.android.server.testutils.whenever
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.mockito.Mockito
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyLong
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.verify
+import java.io.File
+import java.util.UUID
+
+@RunWith(Parameterized::class)
+class DomainVerificationSettingsMutationTest {
+
+ companion object {
+ private const val TEST_PKG = "com.test"
+
+ // Pretend to be the system. This class doesn't verify any enforcement behavior.
+ private const val TEST_UID = Process.SYSTEM_UID
+ private const val TEST_USER_ID = 10
+ private val TEST_UUID = UUID.fromString("5168e42e-327e-432b-b562-cfb553518a70")
+
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun parameters(): Array<Any> {
+ val context: Context = mockThrowOnUnmocked {
+ whenever(
+ enforcePermission(
+ eq(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT),
+ anyInt(), anyInt(), anyString()
+ )
+ )
+ whenever(
+ enforcePermission(
+ eq(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION),
+ anyInt(), anyInt(), anyString()
+ )
+ )
+ whenever(
+ enforcePermission(
+ eq(android.Manifest.permission.INTERACT_ACROSS_USERS),
+ anyInt(), anyInt(), anyString()
+ )
+ )
+ whenever(
+ enforcePermission(
+ eq(android.Manifest.permission.SET_PREFERRED_APPLICATIONS),
+ anyInt(), anyInt(), anyString()
+ )
+ )
+ }
+ val proxy: DomainVerificationProxy = mockThrowOnUnmocked {
+ whenever(isCallerVerifier(anyInt())) { true }
+ whenever(sendBroadcastForPackages(any()))
+ }
+
+ val makeService: (DomainVerificationManagerInternal.Connection) -> DomainVerificationService =
+ { connection ->
+ DomainVerificationService(
+ context,
+ mockThrowOnUnmocked { whenever(linkedApps) { ArraySet<String>() } },
+ mockThrowOnUnmocked {
+ whenever(isChangeEnabled(anyLong(),any())) { true }
+ }).apply {
+ setConnection(connection)
+ }
+ }
+
+ fun service(name: String, block: DomainVerificationService.() -> Unit) =
+ Params(makeService, name) { service ->
+ service.proxy = proxy
+ service.addPackage(mockPkgSetting())
+ service.block()
+ }
+
+ return arrayOf(
+ service("clearPackage") {
+ clearPackage(TEST_PKG)
+ },
+ service("clearUser") {
+ clearUser(TEST_USER_ID)
+ },
+ service("clearState") {
+ clearDomainVerificationState(listOf(TEST_PKG))
+ },
+ service("clearUserSelections") {
+ clearUserSelections(listOf(TEST_PKG), TEST_USER_ID)
+ },
+ service("setStatus") {
+ setDomainVerificationStatus(
+ TEST_UUID,
+ setOf("example.com"),
+ DomainVerificationManager.STATE_SUCCESS
+ )
+ },
+ service("setStatusInternalPackageName") {
+ setDomainVerificationStatusInternal(
+ TEST_PKG,
+ DomainVerificationManager.STATE_SUCCESS,
+ ArraySet(setOf("example.com"))
+ )
+ },
+ service("setStatusInternalUid") {
+ setDomainVerificationStatusInternal(
+ TEST_UID,
+ TEST_UUID,
+ setOf("example.com"),
+ DomainVerificationManager.STATE_SUCCESS
+ )
+ },
+ service("setLinkHandlingAllowed") {
+ setDomainVerificationLinkHandlingAllowed(TEST_PKG, true)
+ },
+ service("setLinkHandlingAllowedUserId") {
+ setDomainVerificationLinkHandlingAllowed(TEST_PKG, true, TEST_USER_ID)
+ },
+ service("setLinkHandlingAllowedInternal") {
+ setDomainVerificationLinkHandlingAllowedInternal(TEST_PKG, true, TEST_USER_ID)
+ },
+ service("setUserSelection") {
+ setDomainVerificationUserSelection(TEST_UUID, setOf("example.com"), true)
+ },
+ service("setUserSelectionUserId") {
+ setDomainVerificationUserSelection(
+ TEST_UUID,
+ setOf("example.com"),
+ true,
+ TEST_USER_ID
+ )
+ },
+ service("setUserSelectionInternal") {
+ setDomainVerificationUserSelectionInternal(
+ TEST_USER_ID,
+ TEST_PKG,
+ true,
+ ArraySet(setOf("example.com")),
+ )
+ },
+ service("setLegacyUserState") {
+ setLegacyUserState(
+ TEST_PKG,
+ TEST_USER_ID,
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER
+ )
+ },
+ )
+ }
+
+ data class Params(
+ val construct: (
+ DomainVerificationManagerInternal.Connection
+ ) -> DomainVerificationService,
+ val name: String,
+ val method: (DomainVerificationService) -> Unit
+ ) {
+ override fun toString() = name
+ }
+
+
+ fun mockPkg() = mockThrowOnUnmocked<AndroidPackage> {
+ whenever(packageName) { TEST_PKG }
+ whenever(targetSdkVersion) { Build.VERSION_CODES.S }
+ whenever(activities) {
+ listOf(
+ ParsedActivity().apply {
+ addIntent(
+ ParsedIntentInfo().apply {
+ autoVerify = true
+ addAction(Intent.ACTION_VIEW)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataScheme("https")
+ addDataAuthority("example.com", null)
+ }
+ )
+ }
+ )
+ }
+ }
+
+ // TODO: PackageSetting field encapsulation to move to whenever(name)
+ fun mockPkgSetting() = spyThrowOnUnmocked(
+ PackageSetting(
+ TEST_PKG,
+ TEST_PKG,
+ File("/test"),
+ null,
+ null,
+ null,
+ null,
+ 1,
+ 0,
+ 0,
+ 0,
+ null,
+ null,
+ null,
+ TEST_UUID
+ )
+ ) {
+ whenever(getPkg()) { mockPkg() }
+ whenever(domainSetId) { TEST_UUID }
+ whenever(userState) {
+ SparseArray<PackageUserState>().apply {
+ this[0] = PackageUserState()
+ }
+ }
+ }
+ }
+
+ @Parameterized.Parameter(0)
+ lateinit var params: Params
+
+ @Test
+ fun writeScheduled() {
+ val connection = mockConnection()
+ val service = params.construct(connection)
+ params.method(service)
+
+ verify(connection).scheduleWriteSettings()
+ }
+
+ private fun mockConnection(): DomainVerificationManagerInternal.Connection =
+ mockThrowOnUnmocked {
+ whenever(callingUid) { TEST_UID }
+ whenever(callingUserId) { TEST_USER_ID }
+ whenever(getPackageSettingLocked(TEST_PKG)) { mockPkgSetting() }
+ whenever(getPackageLocked(TEST_PKG)) { mockPkg() }
+ whenever(schedule(anyInt(), any()))
+ whenever(scheduleWriteSettings())
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index af4130d..ca53492 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -200,12 +200,12 @@
}
private static class DisplayModeWrapper {
- public SurfaceControl.DisplayConfig config;
+ public SurfaceControl.DisplayMode mode;
public float[] expectedAlternativeRefreshRates;
- DisplayModeWrapper(SurfaceControl.DisplayConfig config,
+ DisplayModeWrapper(SurfaceControl.DisplayMode mode,
float[] expectedAlternativeRefreshRates) {
- this.config = config;
+ this.mode = mode;
this.expectedAlternativeRefreshRates = expectedAlternativeRefreshRates;
}
}
@@ -215,14 +215,15 @@
* <code>expectedAlternativeRefreshRates</code> are present for each of the
* <code>modes</code>.
*/
- private void testAlternativeRefreshRatesCommon(FakeDisplay display, DisplayModeWrapper[] modes)
+ private void testAlternativeRefreshRatesCommon(FakeDisplay display,
+ DisplayModeWrapper[] wrappedModes)
throws InterruptedException {
// Update the display.
- SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[modes.length];
- for (int i = 0; i < modes.length; i++) {
- configs[i] = modes[i].config;
+ SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[wrappedModes.length];
+ for (int i = 0; i < wrappedModes.length; i++) {
+ modes[i] = wrappedModes[i].mode;
}
- display.configs = configs;
+ display.modes = modes;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
@@ -233,11 +234,11 @@
mListener.changedDisplays.get(mListener.changedDisplays.size() - 1);
displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
Display.Mode[] supportedModes = displayDevice.getDisplayDeviceInfoLocked().supportedModes;
- assertThat(supportedModes.length).isEqualTo(configs.length);
+ assertThat(supportedModes.length).isEqualTo(modes.length);
- for (int i = 0; i < modes.length; i++) {
- assertModeIsSupported(supportedModes, configs[i],
- modes[i].expectedAlternativeRefreshRates);
+ for (int i = 0; i < wrappedModes.length; i++) {
+ assertModeIsSupported(supportedModes, modes[i],
+ wrappedModes[i].expectedAlternativeRefreshRates);
}
}
@@ -251,56 +252,56 @@
testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 60f, 0), new float[]{24f, 50f}),
+ createFakeDisplayMode(1920, 1080, 60f, 0), new float[]{24f, 50f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 50f, 0), new float[]{24f, 60f}),
+ createFakeDisplayMode(1920, 1080, 50f, 0), new float[]{24f, 60f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 24f, 0), new float[]{50f, 60f}),
+ createFakeDisplayMode(1920, 1080, 24f, 0), new float[]{50f, 60f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 60f, 0), new float[]{24f, 50f}),
+ createFakeDisplayMode(3840, 2160, 60f, 0), new float[]{24f, 50f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 50f, 0), new float[]{24f, 60f}),
+ createFakeDisplayMode(3840, 2160, 50f, 0), new float[]{24f, 60f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 24f, 0), new float[]{50f, 60f}),
+ createFakeDisplayMode(3840, 2160, 24f, 0), new float[]{50f, 60f}),
});
testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 60f, 0), new float[]{50f}),
+ createFakeDisplayMode(1920, 1080, 60f, 0), new float[]{50f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 50f, 0), new float[]{60f}),
+ createFakeDisplayMode(1920, 1080, 50f, 0), new float[]{60f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 24f, 1), new float[0]),
+ createFakeDisplayMode(1920, 1080, 24f, 1), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 60f, 2), new float[0]),
+ createFakeDisplayMode(3840, 2160, 60f, 2), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 50f, 3), new float[]{24f}),
+ createFakeDisplayMode(3840, 2160, 50f, 3), new float[]{24f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 24f, 3), new float[]{50f}),
+ createFakeDisplayMode(3840, 2160, 24f, 3), new float[]{50f}),
});
testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 60f, 0), new float[0]),
+ createFakeDisplayMode(1920, 1080, 60f, 0), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 50f, 1), new float[0]),
+ createFakeDisplayMode(1920, 1080, 50f, 1), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 24f, 2), new float[0]),
+ createFakeDisplayMode(1920, 1080, 24f, 2), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 60f, 3), new float[0]),
+ createFakeDisplayMode(3840, 2160, 60f, 3), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 50f, 4), new float[0]),
+ createFakeDisplayMode(3840, 2160, 50f, 4), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 24f, 5), new float[0]),
+ createFakeDisplayMode(3840, 2160, 24f, 5), new float[0]),
});
}
@Test
public void testAfterDisplayChange_DisplayModesAreUpdated() throws Exception {
- SurfaceControl.DisplayConfig displayConfig = createFakeDisplayConfig(1920, 1080, 60f);
- SurfaceControl.DisplayConfig[] configs =
- new SurfaceControl.DisplayConfig[]{displayConfig};
- FakeDisplay display = new FakeDisplay(PORT_A, configs, 0);
+ SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(1920, 1080, 60f);
+ SurfaceControl.DisplayMode[] modes =
+ new SurfaceControl.DisplayMode[]{displayMode};
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, 0);
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -312,29 +313,29 @@
DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(
0).getDisplayDeviceInfoLocked();
- assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(configs.length);
- assertModeIsSupported(displayDeviceInfo.supportedModes, displayConfig);
+ assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length);
+ assertModeIsSupported(displayDeviceInfo.supportedModes, displayMode);
Display.Mode defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId);
- assertThat(defaultMode.matches(displayConfig.width, displayConfig.height,
- displayConfig.refreshRate)).isTrue();
+ assertThat(defaultMode.matches(displayMode.width, displayMode.height,
+ displayMode.refreshRate)).isTrue();
Display.Mode activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId);
- assertThat(activeMode.matches(displayConfig.width, displayConfig.height,
- displayConfig.refreshRate)).isTrue();
+ assertThat(activeMode.matches(displayMode.width, displayMode.height,
+ displayMode.refreshRate)).isTrue();
// Change the display
- SurfaceControl.DisplayConfig addedDisplayInfo = createFakeDisplayConfig(3840, 2160,
+ SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(3840, 2160,
60f);
- configs = new SurfaceControl.DisplayConfig[]{displayConfig, addedDisplayInfo};
- display.configs = configs;
- display.activeConfig = 1;
+ modes = new SurfaceControl.DisplayMode[]{displayMode, addedDisplayInfo};
+ display.modes = modes;
+ display.activeMode = 1;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
- assertThat(SurfaceControl.getActiveConfig(display.token)).isEqualTo(1);
- assertThat(SurfaceControl.getDisplayConfigs(display.token).length).isEqualTo(2);
+ assertThat(SurfaceControl.getActiveDisplayMode(display.token)).isEqualTo(1);
+ assertThat(SurfaceControl.getDisplayModes(display.token).length).isEqualTo(2);
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -343,8 +344,8 @@
displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
- assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(configs.length);
- assertModeIsSupported(displayDeviceInfo.supportedModes, displayConfig);
+ assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length);
+ assertModeIsSupported(displayDeviceInfo.supportedModes, displayMode);
assertModeIsSupported(displayDeviceInfo.supportedModes, addedDisplayInfo);
activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId);
@@ -358,11 +359,11 @@
@Test
public void testAfterDisplayChange_ActiveModeIsUpdated() throws Exception {
- SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[]{
- createFakeDisplayConfig(1920, 1080, 60f),
- createFakeDisplayConfig(1920, 1080, 50f)
+ SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(1920, 1080, 60f),
+ createFakeDisplayMode(1920, 1080, 50f)
};
- FakeDisplay display = new FakeDisplay(PORT_A, configs, /* activeConfig */ 0);
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, /* activeMode */ 0);
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -378,12 +379,12 @@
assertThat(activeMode.matches(1920, 1080, 60f)).isTrue();
// Change the display
- display.activeConfig = 1;
+ display.activeMode = 1;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
- assertThat(SurfaceControl.getActiveConfig(display.token)).isEqualTo(1);
+ assertThat(SurfaceControl.getActiveDisplayMode(display.token)).isEqualTo(1);
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -471,14 +472,14 @@
}
@Test
- public void testDisplayChange_withStaleDesiredDisplayConfigSpecs() throws Exception {
- SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[]{
- createFakeDisplayConfig(1920, 1080, 60f),
- createFakeDisplayConfig(1920, 1080, 50f)
+ public void testDisplayChange_withStaleDesiredDisplayModeSpecs() throws Exception {
+ SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(1920, 1080, 60f),
+ createFakeDisplayMode(1920, 1080, 50f)
};
- final int activeConfig = 0;
- FakeDisplay display = new FakeDisplay(PORT_A, configs, activeConfig);
- display.desiredDisplayConfigSpecs.defaultConfig = 1;
+ final int activeMode = 0;
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, activeMode);
+ display.desiredDisplayModeSpecs.defaultMode = 1;
setUpDisplay(display);
updateAvailableDisplays();
@@ -486,12 +487,12 @@
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
// Change the display
- display.configs = new SurfaceControl.DisplayConfig[]{
- createFakeDisplayConfig(1920, 1080, 60f)
+ display.modes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(1920, 1080, 60f)
};
- // SurfaceFlinger can return a stale defaultConfig. Make sure this doesn't
+ // SurfaceFlinger can return a stale defaultMode. Make sure this doesn't
// trigger ArrayOutOfBoundsException.
- display.desiredDisplayConfigSpecs.defaultConfig = 1;
+ display.desiredDisplayModeSpecs.defaultMode = 1;
setUpDisplay(display);
updateAvailableDisplays();
@@ -562,13 +563,13 @@
}
private void assertModeIsSupported(Display.Mode[] supportedModes,
- SurfaceControl.DisplayConfig mode) {
+ SurfaceControl.DisplayMode mode) {
assertThat(Arrays.stream(supportedModes).anyMatch(
x -> x.matches(mode.width, mode.height, mode.refreshRate))).isTrue();
}
private void assertModeIsSupported(Display.Mode[] supportedModes,
- SurfaceControl.DisplayConfig mode, float[] alternativeRefreshRates) {
+ SurfaceControl.DisplayMode mode, float[] alternativeRefreshRates) {
float[] sortedAlternativeRates =
Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length);
Arrays.sort(sortedAlternativeRates);
@@ -588,13 +589,13 @@
public final DisplayAddress.Physical address;
public final IBinder token = new Binder();
public final SurfaceControl.DisplayInfo info;
- public SurfaceControl.DisplayConfig[] configs;
- public int activeConfig;
+ public SurfaceControl.DisplayMode[] modes;
+ public int activeMode;
public int[] colorModes = new int[]{ Display.COLOR_MODE_DEFAULT };
public Display.HdrCapabilities hdrCapabilities = new Display.HdrCapabilities(new int[0],
1000, 1000, 0);
- public SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs =
- new SurfaceControl.DesiredDisplayConfigSpecs(/* defaultConfig */ 0,
+ public SurfaceControl.DesiredDisplayModeSpecs desiredDisplayModeSpecs =
+ new SurfaceControl.DesiredDisplayModeSpecs(/* defaultMode */ 0,
/* allowGroupSwitching */ false,
/* primaryRefreshRateMin */ 60.f,
/* primaryRefreshRateMax */ 60.f,
@@ -604,17 +605,17 @@
private FakeDisplay(int port) {
this.address = createDisplayAddress(port);
this.info = createFakeDisplayInfo();
- this.configs = new SurfaceControl.DisplayConfig[]{
- createFakeDisplayConfig(800, 600, 60f)
+ this.modes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(800, 600, 60f)
};
- this.activeConfig = 0;
+ this.activeMode = 0;
}
- private FakeDisplay(int port, SurfaceControl.DisplayConfig[] configs, int activeConfig) {
+ private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode) {
this.address = createDisplayAddress(port);
this.info = createFakeDisplayInfo();
- this.configs = configs;
- this.activeConfig = activeConfig;
+ this.modes = modes;
+ this.activeMode = activeMode;
}
}
@@ -623,16 +624,16 @@
doReturn(display.token).when(() ->
SurfaceControl.getPhysicalDisplayToken(display.address.getPhysicalDisplayId()));
doReturn(display.info).when(() -> SurfaceControl.getDisplayInfo(display.token));
- doReturn(display.configs).when(
- () -> SurfaceControl.getDisplayConfigs(display.token));
- doReturn(display.activeConfig).when(() -> SurfaceControl.getActiveConfig(display.token));
+ doReturn(display.modes).when(
+ () -> SurfaceControl.getDisplayModes(display.token));
+ doReturn(display.activeMode).when(() -> SurfaceControl.getActiveDisplayMode(display.token));
doReturn(0).when(() -> SurfaceControl.getActiveColorMode(display.token));
doReturn(display.colorModes).when(
() -> SurfaceControl.getDisplayColorModes(display.token));
doReturn(display.hdrCapabilities).when(
() -> SurfaceControl.getHdrCapabilities(display.token));
- doReturn(display.desiredDisplayConfigSpecs)
- .when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token));
+ doReturn(display.desiredDisplayModeSpecs)
+ .when(() -> SurfaceControl.getDesiredDisplayModeSpecs(display.token));
}
private void updateAvailableDisplays() {
@@ -655,21 +656,21 @@
return info;
}
- private static SurfaceControl.DisplayConfig createFakeDisplayConfig(int width, int height,
+ private static SurfaceControl.DisplayMode createFakeDisplayMode(int width, int height,
float refreshRate) {
- return createFakeDisplayConfig(width, height, refreshRate, 0);
+ return createFakeDisplayMode(width, height, refreshRate, 0);
}
- private static SurfaceControl.DisplayConfig createFakeDisplayConfig(int width, int height,
- float refreshRate, int configGroup) {
- final SurfaceControl.DisplayConfig config = new SurfaceControl.DisplayConfig();
- config.width = width;
- config.height = height;
- config.refreshRate = refreshRate;
- config.xDpi = 100;
- config.yDpi = 100;
- config.configGroup = configGroup;
- return config;
+ private static SurfaceControl.DisplayMode createFakeDisplayMode(int width, int height,
+ float refreshRate, int group) {
+ final SurfaceControl.DisplayMode mode = new SurfaceControl.DisplayMode();
+ mode.width = width;
+ mode.height = height;
+ mode.refreshRate = refreshRate;
+ mode.xDpi = 100;
+ mode.yDpi = 100;
+ mode.group = group;
+ return mode;
}
private static void waitForHandlerToComplete(Handler handler, long waitTimeMs)
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
new file mode 100644
index 0000000..35ac897
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManagerInternal;
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.os.UserHandle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.server.LocalServices;
+import com.android.server.job.JobConcurrencyManager.GracePeriodObserver;
+import com.android.server.job.controllers.JobStatus;
+import com.android.server.pm.UserManagerInternal;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class JobConcurrencyManagerTest {
+ private static final int UNAVAILABLE_USER = 0;
+ private JobConcurrencyManager mJobConcurrencyManager;
+ private UserManagerInternal mUserManagerInternal;
+ private ActivityManagerInternal mActivityManagerInternal;
+ private int mNextUserId;
+ private GracePeriodObserver mGracePeriodObserver;
+ private Context mContext;
+ private Resources mResources;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ LocalServices.addService(UserManagerInternal.class, mock(UserManagerInternal.class));
+ LocalServices.addService(
+ ActivityManagerInternal.class, mock(ActivityManagerInternal.class));
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ }
+
+ @Before
+ public void setUp() {
+ final JobSchedulerService jobSchedulerService = mock(JobSchedulerService.class);
+ mContext = mock(Context.class);
+ mResources = mock(Resources.class);
+ doReturn(true).when(mResources).getBoolean(
+ R.bool.config_jobSchedulerRestrictBackgroundUser);
+ when(mContext.getResources()).thenReturn(mResources);
+ doReturn(mContext).when(jobSchedulerService).getTestableContext();
+ mJobConcurrencyManager = new JobConcurrencyManager(jobSchedulerService);
+ mGracePeriodObserver = mock(GracePeriodObserver.class);
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mNextUserId = 10;
+ mJobConcurrencyManager.mGracePeriodObserver = mGracePeriodObserver;
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_currentUser() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createCurrentUser(false))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_currentProfile() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createCurrentUser(true))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_primaryUser() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createPrimaryUser(false))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_primaryProfile() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createPrimaryUser(true))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_UnexpiredUser() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createUnexpiredUser(false))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_UnexpiredProfile() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createUnexpiredUser(true))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_restrictedUser() {
+ assertFalse(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createRestrictedUser(false))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_restrictedProfile() {
+ assertFalse(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createRestrictedUser(true))));
+ }
+
+ private UserInfo createCurrentUser(boolean isProfile) {
+ final UserInfo ui = createNewUser();
+ doReturn(ui.id).when(mActivityManagerInternal).getCurrentUserId();
+ return isProfile ? createNewProfile(ui) : ui;
+ }
+
+ private UserInfo createPrimaryUser(boolean isProfile) {
+ final UserInfo ui = createNewUser();
+ doReturn(true).when(ui).isPrimary();
+ return isProfile ? createNewProfile(ui) : ui;
+ }
+
+ private UserInfo createUnexpiredUser(boolean isProfile) {
+ final UserInfo ui = createNewUser();
+ doReturn(true).when(mGracePeriodObserver).isWithinGracePeriodForUser(ui.id);
+ return isProfile ? createNewProfile(ui) : ui;
+ }
+
+ private UserInfo createRestrictedUser(boolean isProfile) {
+ final UserInfo ui = createNewUser();
+ doReturn(UNAVAILABLE_USER).when(mActivityManagerInternal).getCurrentUserId();
+ doReturn(false).when(ui).isPrimary();
+ doReturn(false).when(mGracePeriodObserver).isWithinGracePeriodForUser(ui.id);
+ return isProfile ? createNewProfile(ui) : ui;
+ }
+
+ private UserInfo createNewProfile(UserInfo parent) {
+ final UserInfo ui = createNewUser();
+ parent.profileGroupId = parent.id;
+ ui.profileGroupId = parent.id;
+ doReturn(true).when(ui).isProfile();
+ return ui;
+ }
+
+ private UserInfo createNewUser() {
+ final UserInfo ui = mock(UserInfo.class);
+ ui.id = mNextUserId++;
+ doReturn(ui).when(mUserManagerInternal).getUserInfo(ui.id);
+ ui.profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
+ return ui;
+ }
+
+ private static JobStatus createJob(UserInfo userInfo) {
+ JobStatus jobStatus = JobStatus.createFromJobInfo(
+ new JobInfo.Builder(1, new ComponentName("foo", "bar")).build(),
+ userInfo.id * UserHandle.PER_USER_RANGE,
+ null, userInfo.id, "JobConcurrencyManagerTest");
+ return jobStatus;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 3b5cc88..54fa89a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -64,6 +64,7 @@
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.LocationRequest;
import android.location.LocationResult;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.location.provider.ProviderRequest;
import android.location.util.identity.CallerIdentity;
@@ -662,6 +663,23 @@
}
@Test
+ public void testProviderRequestListener() throws Exception {
+ IProviderRequestListener requestListener = mock(IProviderRequestListener.class);
+ mManager.addProviderRequestListener(requestListener);
+
+ ILocationListener locationListener = createMockLocationListener();
+ LocationRequest request = new LocationRequest.Builder(1).setWorkSource(
+ WORK_SOURCE).build();
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, locationListener);
+
+ verify(requestListener, timeout(TIMEOUT_MS).times(1)).onProviderRequestChanged(anyString(),
+ any(ProviderRequest.class));
+
+ mManager.unregisterLocationRequest(locationListener);
+ mManager.removeProviderRequestListener(requestListener);
+ }
+
+ @Test
public void testGetCurrentLocation() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index 2a7905a..633957a 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -50,6 +50,7 @@
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
@@ -81,6 +82,7 @@
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -92,6 +94,7 @@
@Presubmit
public class VibratorServiceTest {
+ private static final int TEST_TIMEOUT_MILLIS = 1_000;
private static final int UID = Process.ROOT_UID;
private static final int VIBRATOR_ID = 1;
private static final String PACKAGE_NAME = "package";
@@ -342,8 +345,8 @@
verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
// VibrationThread will start this vibration async, so wait before checking it never played.
- Thread.sleep(10);
- assertTrue(mVibratorProvider.getEffects().isEmpty());
+ assertFalse(waitUntil(s -> !mVibratorProvider.getEffects().isEmpty(), service,
+ /* timeout= */ 20));
}
@Test
@@ -399,8 +402,8 @@
verify(mIInputManagerMock).vibrate(eq(1), any(), any());
// VibrationThread will start this vibration async, so wait before checking it never played.
- Thread.sleep(10);
- assertTrue(mVibratorProvider.getEffects().isEmpty());
+ assertFalse(waitUntil(s -> !mVibratorProvider.getEffects().isEmpty(), service,
+ /* timeout= */ 20));
}
@Test
@@ -409,16 +412,10 @@
mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
vibrate(service, VibrationEffect.createOneShot(1000, 100), HAPTIC_FEEDBACK_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
-
- // Wait for callback to cancel vibration.
- Thread.sleep(10);
- assertFalse(service.isVibrating());
+ assertTrue(waitUntil(s -> !s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
}
@Test
@@ -427,26 +424,18 @@
mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
vibrate(service, VibrationEffect.createOneShot(1000, 100), RINGTONE_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
-
- // Wait for callback to cancel vibration.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ // Settings callback is async, so wait before checking it never got cancelled.
+ assertFalse(waitUntil(s -> !s.isVibrating(), service, /* timeout= */ 20));
}
@Test
public void vibrate_withSettingsChanged_doNotCancelVibration() throws Exception {
VibratorService service = createService();
vibrate(service, VibrationEffect.createOneShot(1000, 100), HAPTIC_FEEDBACK_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
Vibrator.VIBRATION_INTENSITY_MEDIUM);
@@ -454,9 +443,8 @@
// FakeSettingsProvider don't support testing triggering ContentObserver yet.
service.updateVibrators();
- // Wait for callback to cancel vibration.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ // Settings callback is async, so wait before checking it never got cancelled.
+ assertFalse(waitUntil(s -> !s.isVibrating(), service, /* timeout= */ 20));
}
@Test
@@ -488,8 +476,8 @@
inOrderVerifier.verify(mIInputManagerMock).vibrate(eq(2), eq(effect), any());
// VibrationThread will start this vibration async, so wait before checking it never played.
- Thread.sleep(10);
- assertTrue(mVibratorProvider.getEffects().isEmpty());
+ assertFalse(waitUntil(s -> !mVibratorProvider.getEffects().isEmpty(), service,
+ /* timeout= */ 20));
}
@Test
@@ -521,8 +509,8 @@
verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
// VibrationThread will start this vibration async, so wait before checking it never played.
- Thread.sleep(10);
- assertTrue(mVibratorProvider.getEffects().isEmpty());
+ assertFalse(waitUntil(s -> !mVibratorProvider.getEffects().isEmpty(), service,
+ /* timeout= */ 20));
}
@Test
@@ -531,18 +519,12 @@
VibratorService service = createService();
vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
// Trigger callbacks from controller.
mTestLooper.moveTimeForward(50);
mTestLooper.dispatchAll();
-
- // VibrationThread needs some time to react to native callbacks and stop the vibrator.
- Thread.sleep(10);
- assertFalse(service.isVibrating());
+ assertTrue(waitUntil(s -> !s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
}
@Test
@@ -550,16 +532,10 @@
VibratorService service = createService();
vibrate(service, VibrationEffect.createOneShot(100, 100), ALARM_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before checking.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
service.cancelVibrate(service);
-
- // VibrationThread will stop this vibration async, so wait before checking.
- Thread.sleep(10);
- assertFalse(service.isVibrating());
+ assertTrue(waitUntil(s -> !s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
}
@Test
@@ -584,17 +560,13 @@
service.registerVibratorStateListener(mVibratorStateListenerMock);
vibrate(service, VibrationEffect.createOneShot(30, 100), ALARM_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
service.unregisterVibratorStateListener(mVibratorStateListenerMock);
// Trigger callbacks from controller.
mTestLooper.moveTimeForward(50);
mTestLooper.dispatchAll();
- Thread.sleep(20);
- assertFalse(service.isVibrating());
+ assertTrue(waitUntil(s -> !s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
InOrder inOrderVerifier = inOrder(mVibratorStateListenerMock);
// First notification done when listener is registered.
@@ -771,4 +743,15 @@
private void setGlobalSetting(String settingName, int value) {
Settings.Global.putInt(mContextSpy.getContentResolver(), settingName, value);
}
+
+ private boolean waitUntil(Predicate<VibratorService> predicate,
+ VibratorService service, long timeout) throws InterruptedException {
+ long timeoutTimestamp = SystemClock.uptimeMillis() + timeout;
+ boolean predicateResult = false;
+ while (!predicateResult && SystemClock.uptimeMillis() < timeoutTimestamp) {
+ Thread.sleep(10);
+ predicateResult = predicate.test(service);
+ }
+ return predicateResult;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/job/GracePeriodObserverTest.java b/services/tests/servicestests/src/com/android/server/job/GracePeriodObserverTest.java
new file mode 100644
index 0000000..1915b8c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/GracePeriodObserverTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.app.ActivityManagerInternal;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.SystemClock;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.job.JobConcurrencyManager.GracePeriodObserver;
+import com.android.server.pm.UserManagerInternal;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.ZoneOffset;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class GracePeriodObserverTest {
+ private GracePeriodObserver mGracePeriodObserver;
+ private UserManagerInternal mUserManagerInternal;
+ private static final int FIRST_USER = 0;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ UserManagerInternal userManagerInternal = mock(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, userManagerInternal);
+ ActivityManagerInternal activityManagerInternal = mock(ActivityManagerInternal.class);
+ LocalServices.addService(ActivityManagerInternal.class, activityManagerInternal);
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ }
+
+ @Before
+ public void setUp() {
+ final Context context = ApplicationProvider.getApplicationContext();
+ JobSchedulerService.sElapsedRealtimeClock =
+ Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
+ doReturn(FIRST_USER)
+ .when(LocalServices.getService(ActivityManagerInternal.class)).getCurrentUserId();
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ doReturn(true).when(mUserManagerInternal).exists(FIRST_USER);
+ mGracePeriodObserver = new GracePeriodObserver(context);
+ }
+
+ @Test
+ public void testGracePeriod() throws RemoteException {
+ final int oldUser = FIRST_USER;
+ final int newUser = 10;
+ doReturn(true).when(mUserManagerInternal).exists(newUser);
+ mGracePeriodObserver.onUserSwitchComplete(newUser);
+ assertTrue(mGracePeriodObserver.isWithinGracePeriodForUser(oldUser));
+ JobSchedulerService.sElapsedRealtimeClock =
+ Clock.offset(JobSchedulerService.sElapsedRealtimeClock,
+ Duration.ofMillis(mGracePeriodObserver.mGracePeriod));
+ assertFalse(mGracePeriodObserver.isWithinGracePeriodForUser(oldUser));
+ }
+
+ @Test
+ public void testCleanUp() throws RemoteException {
+ final int removedUser = FIRST_USER;
+ final int newUser = 10;
+ mGracePeriodObserver.onUserSwitchComplete(newUser);
+
+ final int sizeBefore = mGracePeriodObserver.mGracePeriodExpiration.size();
+ doReturn(false).when(mUserManagerInternal).exists(removedUser);
+
+ mGracePeriodObserver.onUserRemoved(removedUser);
+ assertEquals(sizeBefore - 1, mGracePeriodObserver.mGracePeriodExpiration.size());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
index 263cf48..9c78192 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
@@ -17,6 +17,7 @@
package com.android.server.job;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
@@ -63,17 +64,27 @@
public final SparseIntArray running = new SparseIntArray();
public final SparseIntArray pending = new SparseIntArray();
- public void maybeEnqueueJobs(double startRatio, double fgJobRatio) {
+ public void maybeEnqueueJobs(double startRatio, double fgJobRatio, double fgUserJobRatio) {
+ // fgUserJobRatio should always be at least fgJobRatio, otherwise no WORK_TYPE_BG will
+ // be enqueued.
while (mRandom.nextDouble() < startRatio) {
- if (mRandom.nextDouble() < fgJobRatio) {
+ final double random = mRandom.nextDouble();
+ if (random < fgJobRatio) {
pending.put(WORK_TYPE_TOP, pending.get(WORK_TYPE_TOP) + 1);
- } else {
+ } else if (random < fgUserJobRatio) {
pending.put(WORK_TYPE_BG, pending.get(WORK_TYPE_BG) + 1);
+ } else {
+ pending.put(WORK_TYPE_BGUSER, pending.get(WORK_TYPE_BGUSER) + 1);
}
}
}
public void maybeFinishJobs(double stopRatio) {
+ for (int i = running.get(WORK_TYPE_BGUSER); i > 0; i--) {
+ if (mRandom.nextDouble() < stopRatio) {
+ running.put(WORK_TYPE_BGUSER, running.get(WORK_TYPE_BGUSER) - 1);
+ }
+ }
for (int i = running.get(WORK_TYPE_BG); i > 0; i--) {
if (mRandom.nextDouble() < stopRatio) {
running.put(WORK_TYPE_BG, running.get(WORK_TYPE_BG) - 1);
@@ -120,8 +131,11 @@
while ((jobs.pending.get(WORK_TYPE_TOP) > 0
&& mWorkCountTracker.canJobStart(WORK_TYPE_TOP) != WORK_TYPE_NONE)
|| (jobs.pending.get(WORK_TYPE_BG) > 0
- && mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE)) {
+ && mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE)
+ || (jobs.pending.get(WORK_TYPE_BGUSER) > 0
+ && mWorkCountTracker.canJobStart(WORK_TYPE_BGUSER) != WORK_TYPE_NONE)) {
final boolean isStartingFg = mRandom.nextBoolean();
+ final boolean isStartingFgUser = mRandom.nextBoolean();
if (isStartingFg) {
if (jobs.pending.get(WORK_TYPE_TOP) > 0
@@ -131,7 +145,7 @@
mWorkCountTracker.stageJob(WORK_TYPE_TOP);
mWorkCountTracker.onJobStarted(WORK_TYPE_TOP);
}
- } else {
+ } else if (isStartingFgUser) {
if (jobs.pending.get(WORK_TYPE_BG) > 0
&& mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE) {
jobs.pending.put(WORK_TYPE_BG, jobs.pending.get(WORK_TYPE_BG) - 1);
@@ -139,6 +153,14 @@
mWorkCountTracker.stageJob(WORK_TYPE_BG);
mWorkCountTracker.onJobStarted(WORK_TYPE_BG);
}
+ } else {
+ if (jobs.pending.get(WORK_TYPE_BGUSER) > 0
+ && mWorkCountTracker.canJobStart(WORK_TYPE_BGUSER) != WORK_TYPE_NONE) {
+ jobs.pending.put(WORK_TYPE_BGUSER, jobs.pending.get(WORK_TYPE_BGUSER) - 1);
+ jobs.running.put(WORK_TYPE_BGUSER, jobs.running.get(WORK_TYPE_BGUSER) + 1);
+ mWorkCountTracker.stageJob(WORK_TYPE_BGUSER);
+ mWorkCountTracker.onJobStarted(WORK_TYPE_BGUSER);
+ }
}
}
}
@@ -149,10 +171,10 @@
private void checkRandom(Jobs jobs, int numTests, int totalMax,
@NonNull List<Pair<Integer, Integer>> minLimits,
@NonNull List<Pair<Integer, Integer>> maxLimits,
- double startRatio, double fgJobRatio, double stopRatio) {
+ double startRatio, double fgJobRatio, double fgUserJobRatio, double stopRatio) {
for (int i = 0; i < numTests; i++) {
jobs.maybeFinishJobs(stopRatio);
- jobs.maybeEnqueueJobs(startRatio, fgJobRatio);
+ jobs.maybeEnqueueJobs(startRatio, fgJobRatio, fgUserJobRatio);
recount(jobs, totalMax, minLimits, maxLimits);
startPendingJobs(jobs);
@@ -182,14 +204,21 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
- final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double stopRatio = 0.1;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 50%
+ // WORK_TYPE_BG -- 50%
+ // WORK_TYPE_BGUSER -- 0%
final double fgJobRatio = 0.5;
+ final double fgUserJobRatio = 1;
final double startRatio = 0.1;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
}
@Test
@@ -198,14 +227,20 @@
final int numTests = 5000;
final int totalMax = 2;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of();
final double stopRatio = 0.5;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 50%
+ // WORK_TYPE_BG -- 50%
+ // WORK_TYPE_BGUSER -- 0%
final double fgJobRatio = 0.5;
+ final double fgUserJobRatio = 1;
final double startRatio = 0.5;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
}
@Test
@@ -214,14 +249,20 @@
final int numTests = 5000;
final int totalMax = 2;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.5;
- final double fgJobRatio = 0.5;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 33%
+ // WORK_TYPE_BG -- 33%
+ // WORK_TYPE_BGUSER -- 33%
+ final double fgJobRatio = 1 / 3.0;
+ final double fgUserJobRatio = 2 / 3.0;
final double startRatio = 0.5;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
}
@Test
@@ -230,14 +271,20 @@
final int numTests = 5000;
final int totalMax = 10;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of();
final double stopRatio = 0.5;
- final double fgJobRatio = 0.5;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 33%
+ // WORK_TYPE_BG -- 33%
+ // WORK_TYPE_BGUSER -- 33%
+ final double fgJobRatio = 1 / 3.0;
+ final double fgUserJobRatio = 2 / 3.0;
final double startRatio = 0.5;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
}
@Test
@@ -246,14 +293,20 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.5;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 10%
+ // WORK_TYPE_BG -- 80%
+ // WORK_TYPE_BGUSER -- 10%
final double fgJobRatio = 0.1;
+ final double fgUserJobRatio = 0.9;
final double startRatio = 0.5;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
}
@Test
@@ -262,14 +315,20 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.5;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 90%
+ // WORK_TYPE_BG -- 10%
+ // WORK_TYPE_BGUSER -- 0%
final double fgJobRatio = 0.9;
+ final double fgUserJobRatio = 1;
final double startRatio = 0.5;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
}
@Test
@@ -278,14 +337,20 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.4;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 10%
+ // WORK_TYPE_BG -- 10%
+ // WORK_TYPE_BGUSER -- 80%
final double fgJobRatio = 0.1;
+ final double fgUserJobRatio = 0.2;
final double startRatio = 0.5;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
}
@Test
@@ -294,14 +359,90 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
- final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double stopRatio = 0.4;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 90%
+ // WORK_TYPE_BG -- 5%
+ // WORK_TYPE_BGUSER -- 5%
final double fgJobRatio = 0.9;
+ final double fgUserJobRatio = 0.95;
final double startRatio = 0.5;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
+ }
+
+ @Test
+ public void testRandom9() {
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 6;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final double stopRatio = 0.5;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 0%
+ // WORK_TYPE_BG -- 50%
+ // WORK_TYPE_BGUSER -- 50%
+ final double fgJobRatio = 0;
+ final double fgUserJobRatio = 0.5;
+ final double startRatio = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
+ }
+
+ @Test
+ public void testRandom10() {
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 6;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final double stopRatio = 0.5;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 0%
+ // WORK_TYPE_BG -- 10%
+ // WORK_TYPE_BGUSER -- 90%
+ final double fgJobRatio = 0;
+ final double fgUserJobRatio = 0.1;
+ final double startRatio = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
+ }
+
+ @Test
+ public void testRandom11() {
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 6;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final double stopRatio = 0.5;
+ // WorkType probabilities:
+ // WORK_TYPE_TOP -- 0%
+ // WORK_TYPE_BG -- 90%
+ // WORK_TYPE_BGUSER -- 10%
+ final double fgJobRatio = 0;
+ final double fgUserJobRatio = 0.9;
+ final double startRatio = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
}
/** Used by the following tests */
@@ -337,7 +478,7 @@
public void testBasic() {
checkSimple(6,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
@@ -345,7 +486,7 @@
checkSimple(6,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
@@ -354,7 +495,7 @@
// When there are BG jobs pending, 2 (min-BG) jobs should run.
checkSimple(6,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)),
@@ -385,6 +526,16 @@
checkSimple(8,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 49), Pair.create(WORK_TYPE_BG, 49)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 4)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 47), Pair.create(WORK_TYPE_BG, 49))
+ );
+
+
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 6)),
/* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
@@ -407,6 +558,14 @@
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
+
checkSimple(6,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
@@ -425,6 +584,38 @@
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
/* resRun */ List.of(Pair.create(WORK_TYPE_BG, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)));
+
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10),
+ Pair.create(WORK_TYPE_BG, 3),
+ Pair.create(WORK_TYPE_BGUSER, 3)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 6),
+ Pair.create(WORK_TYPE_BG, 3),
+ Pair.create(WORK_TYPE_BGUSER, 3)));
+
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 3)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)),
+ /* resRun */ List.of(
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /* resPen */ List.of(
+ Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)));
+
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)),
+ /* resRun */ List.of(
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
+ /* resPen */ List.of(
+ Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 2)));
}
/** Tests that the counter updates properly when jobs are stopped. */
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
index c28292f..bbc1f1d 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
@@ -16,8 +16,10 @@
package com.android.server.job;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import android.annotation.NonNull;
@@ -31,7 +33,6 @@
import com.android.server.job.JobConcurrencyManager.WorkTypeConfig;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,8 +45,10 @@
private static final String KEY_MAX_TOTAL = "concurrency_max_total_test";
private static final String KEY_MAX_TOP = "concurrency_max_top_test";
private static final String KEY_MAX_BG = "concurrency_max_bg_test";
+ private static final String KEY_MAX_BGUSER = "concurrency_max_bguser_test";
private static final String KEY_MIN_TOP = "concurrency_min_top_test";
private static final String KEY_MIN_BG = "concurrency_min_bg_test";
+ private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test";
@After
public void tearDown() throws Exception {
@@ -57,17 +60,21 @@
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, "", false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, "", false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, "", false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, "", false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, "", false);
}
private void check(@Nullable DeviceConfig.Properties config,
int defaultTotal,
@Nullable Pair<Integer, Integer> defaultTopLimits,
@Nullable Pair<Integer, Integer> defaultBgLimits,
+ @Nullable Pair<Integer, Integer> defaultBgUserLimits,
boolean expectedValid, int expectedTotal,
@NonNull Pair<Integer, Integer> expectedTopLimits,
- @NonNull Pair<Integer, Integer> expectedBgLimits) throws Exception {
+ @NonNull Pair<Integer, Integer> expectedBgLimits,
+ @NonNull Pair<Integer, Integer> expectedBgUserLimits) throws Exception {
resetConfig();
if (config != null) {
DeviceConfig.setProperties(config);
@@ -92,6 +99,14 @@
defaultMax.add(Pair.create(WORK_TYPE_BG, val));
}
}
+ if (defaultBgUserLimits != null) {
+ if ((val = defaultBgUserLimits.first) != null) {
+ defaultMin.add(Pair.create(WORK_TYPE_BGUSER, val));
+ }
+ if ((val = defaultBgUserLimits.second) != null) {
+ defaultMax.add(Pair.create(WORK_TYPE_BGUSER, val));
+ }
+ }
final WorkTypeConfig counts;
try {
@@ -112,40 +127,45 @@
counts.update(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
- Assert.assertEquals(expectedTotal, counts.getMaxTotal());
- Assert.assertEquals((int) expectedTopLimits.first, counts.getMinReserved(WORK_TYPE_TOP));
- Assert.assertEquals((int) expectedTopLimits.second, counts.getMax(WORK_TYPE_TOP));
- Assert.assertEquals((int) expectedBgLimits.first, counts.getMinReserved(WORK_TYPE_BG));
- Assert.assertEquals((int) expectedBgLimits.second, counts.getMax(WORK_TYPE_BG));
+ assertEquals(expectedTotal, counts.getMaxTotal());
+ assertEquals((int) expectedTopLimits.first, counts.getMinReserved(WORK_TYPE_TOP));
+ assertEquals((int) expectedTopLimits.second, counts.getMax(WORK_TYPE_TOP));
+ assertEquals((int) expectedBgLimits.first, counts.getMinReserved(WORK_TYPE_BG));
+ assertEquals((int) expectedBgLimits.second, counts.getMax(WORK_TYPE_BG));
+ assertEquals((int) expectedBgUserLimits.first, counts.getMinReserved(WORK_TYPE_BGUSER));
+ assertEquals((int) expectedBgUserLimits.second, counts.getMax(WORK_TYPE_BGUSER));
}
@Test
public void test() throws Exception {
// Tests with various combinations.
- check(null, /*default*/ 5, Pair.create(4, null), Pair.create(0, 1),
- /*expected*/ true, 5, Pair.create(4, 5), Pair.create(0, 1));
- check(null, /*default*/ 5, Pair.create(5, null), Pair.create(0, 0),
- /*expected*/ true, 5, Pair.create(5, 5), Pair.create(0, 1));
- check(null, /*default*/ 0, Pair.create(5, null), Pair.create(0, 0),
- /*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1));
- check(null, /*default*/ -1, null, Pair.create(-1, -1),
- /*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1));
- check(null, /*default*/ 5, null, Pair.create(5, 5),
- /*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5));
- check(null, /*default*/ 6, Pair.create(1, null), Pair.create(6, 5),
- /*expected*/ false, 6, Pair.create(1, 6), Pair.create(5, 5));
- check(null, /*default*/ 4, null, Pair.create(6, 5),
- /*expected*/ false, 4, Pair.create(1, 4), Pair.create(3, 4));
- check(null, /*default*/ 5, Pair.create(4, null), Pair.create(1, 1),
- /*expected*/ true, 5, Pair.create(4, 5), Pair.create(1, 1));
- check(null, /*default*/ 15, null, Pair.create(15, 15),
- /*expected*/ true, 15, Pair.create(1, 15), Pair.create(14, 15));
- check(null, /*default*/ 16, null, Pair.create(16, 16),
- /*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16));
- check(null, /*default*/ 20, null, Pair.create(20, 20),
- /*expected*/ false, 16, Pair.create(1, 16), Pair.create(15, 16));
- check(null, /*default*/ 20, null, Pair.create(16, 16),
- /*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16));
+ check(null, /*default*/ 5, Pair.create(4, null), Pair.create(0, 1), Pair.create(0, 1),
+ /*expected*/ true, 5, Pair.create(4, 5), Pair.create(0, 1), Pair.create(0, 1));
+ check(null, /*default*/ 5, Pair.create(5, null), Pair.create(0, 0), Pair.create(0, 0),
+ /*expected*/ true, 5, Pair.create(5, 5), Pair.create(0, 1), Pair.create(0, 1));
+ check(null, /*default*/ 0, Pair.create(5, null), Pair.create(0, 0), Pair.create(0, 0),
+ /*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1), Pair.create(0, 1));
+ check(null, /*default*/ -1, null, Pair.create(-1, -1), Pair.create(-1, -1),
+ /*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1), Pair.create(0, 1));
+ check(null, /*default*/ 5, null, Pair.create(5, 5), Pair.create(0, 5),
+ /*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5), Pair.create(0, 5));
+ check(null, /*default*/ 6, Pair.create(1, null), Pair.create(6, 5), Pair.create(2, 1),
+ /*expected*/ false, 6, Pair.create(1, 6), Pair.create(5, 5), Pair.create(0, 1));
+ check(null, /*default*/ 4, null, Pair.create(6, 5), Pair.create(6, 5),
+ /*expected*/ false, 4, Pair.create(1, 4), Pair.create(3, 4), Pair.create(0, 4));
+ check(null, /*default*/ 5, Pair.create(4, null), Pair.create(1, 1), Pair.create(0, 5),
+ /*expected*/ true, 5, Pair.create(4, 5), Pair.create(1, 1), Pair.create(0, 5));
+ check(null, /*default*/ 5, Pair.create(4, null), Pair.create(0, 1), Pair.create(1, 5),
+ /*expected*/ true, 5, Pair.create(4, 5), Pair.create(0, 1), Pair.create(1, 5));
+ check(null, /*default*/ 15, null, Pair.create(15, 15), Pair.create(0, 15),
+ /*expected*/ true, 15, Pair.create(1, 15), Pair.create(14, 15), Pair.create(0, 15));
+ check(null, /*default*/ 16, null, Pair.create(16, 16), Pair.create(0, 16),
+ /*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16), Pair.create(0, 16));
+ check(null, /*default*/ 20, null, Pair.create(20, 20), Pair.create(10, 20),
+ /*expected*/ false, 16,
+ Pair.create(1, 16), Pair.create(15, 16), Pair.create(0, 16));
+ check(null, /*default*/ 20, null, Pair.create(16, 16), Pair.create(0, 16),
+ /*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16), Pair.create(0, 16));
// Test for overriding with a setting string.
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
@@ -153,26 +173,26 @@
.setInt(KEY_MAX_BG, 4)
.setInt(KEY_MIN_BG, 3)
.build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 5, Pair.create(1, 5), Pair.create(3, 4));
+ /*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 2),
+ /*expected*/ true, 5, Pair.create(1, 5), Pair.create(3, 4), Pair.create(0, 2));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_TOTAL, 5).build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5));
+ /*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 0),
+ /*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5), Pair.create(0, 1));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_BG, 4).build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 9, Pair.create(1, 9), Pair.create(4, 4));
+ /*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 9),
+ /*expected*/ true, 9, Pair.create(1, 9), Pair.create(4, 4), Pair.create(0, 9));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MIN_BG, 3).build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 9, Pair.create(1, 9), Pair.create(3, 9));
+ /*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 6),
+ /*expected*/ true, 9, Pair.create(1, 9), Pair.create(3, 9), Pair.create(0, 6));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_TOTAL, 20)
.setInt(KEY_MAX_BG, 20)
.setInt(KEY_MIN_BG, 8)
.build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 16, Pair.create(1, 16), Pair.create(8, 16));
+ /*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 8),
+ /*expected*/ true, 16, Pair.create(1, 16), Pair.create(8, 16), Pair.create(0, 8));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index d876b05..7d20879 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -229,9 +229,9 @@
.compose();
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- Thread.sleep(20);
+ assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), vibrationThread,
+ TEST_TIMEOUT_MILLIS));
assertTrue(vibrationThread.isAlive());
- assertTrue(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
// Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
@@ -254,9 +254,9 @@
VibrationEffect effect = VibrationEffect.createWaveform(new long[]{100}, new int[]{100}, 0);
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- Thread.sleep(20);
+ assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), vibrationThread,
+ TEST_TIMEOUT_MILLIS));
assertTrue(vibrationThread.isAlive());
- assertTrue(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
// Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
@@ -621,10 +621,8 @@
.combine();
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- Thread.sleep(10);
- assertTrue(vibrationThread.isAlive());
- assertTrue(vibrationThread.getVibrators().get(1).isVibrating());
- assertTrue(vibrationThread.getVibrators().get(2).isVibrating());
+ assertTrue(waitUntil(t -> t.getVibrators().get(2).isVibrating(), vibrationThread,
+ TEST_TIMEOUT_MILLIS));
// Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
new file mode 100644
index 0000000..f5d0ca7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorManager;
+import android.hardware.input.InputSensorInfo;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.rotationresolver.RotationResolverInternal;
+import android.view.Surface;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.server.wm.WindowOrientationListener}
+ */
+public class WindowOrientationListenerTest {
+
+ @Mock
+ private Context mMockContext;
+ @Mock
+ private Handler mMockHandler;
+ @Mock
+ private InputSensorInfo mMockInputSensorInfo;
+ @Mock
+ private SensorManager mMockSensorManager;
+ @Mock
+ private WindowManagerService mMockWindowManagerService;
+
+ private TestableRotationResolver mFakeRotationResolverInternal;
+ private com.android.server.wm.WindowOrientationListener mWindowOrientationListener;
+ private int mFinalizedRotation;
+ private boolean mRotationResolverEnabled;
+ private boolean mCanUseRotationResolver;
+ private SensorEvent mFakeSensorEvent;
+ private Sensor mFakeSensor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mRotationResolverEnabled = true;
+ mCanUseRotationResolver = true;
+
+ mFakeRotationResolverInternal = new TestableRotationResolver();
+ doReturn(mMockSensorManager).when(mMockContext).getSystemService(Context.SENSOR_SERVICE);
+ mWindowOrientationListener = new TestableWindowOrientationListener(mMockContext,
+ mMockHandler, mMockWindowManagerService);
+ mWindowOrientationListener.mRotationResolverService = mFakeRotationResolverInternal;
+
+ mFakeSensor = new Sensor(mMockInputSensorInfo);
+ mFakeSensorEvent = new SensorEvent(mFakeSensor, /* accuracy */ 1, /* timestamp */ 1L,
+ new float[]{(float) Surface.ROTATION_90});
+ }
+
+ @Test
+ public void testOnSensorChanged_rotationResolverDisabled_useSensorResult() {
+ mRotationResolverEnabled = false;
+
+ mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
+
+ assertThat(mFinalizedRotation).isEqualTo(Surface.ROTATION_90);
+ }
+
+ @Test
+ public void testOnSensorChanged_cannotUseRotationResolver_useSensorResult() {
+ mCanUseRotationResolver = false;
+
+ mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
+
+ assertThat(mFinalizedRotation).isEqualTo(Surface.ROTATION_90);
+
+ }
+
+ @Test
+ public void testOnSensorChanged_normalCase() {
+ mFakeRotationResolverInternal.mResult = Surface.ROTATION_180;
+
+ mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
+
+ assertThat(mFinalizedRotation).isEqualTo(Surface.ROTATION_180);
+ }
+
+ final class TestableRotationResolver extends RotationResolverInternal {
+ @Surface.Rotation
+ int mResult;
+
+ @Override
+ public boolean isRotationResolverSupported() {
+ return true;
+ }
+
+ @Override
+ public void resolveRotation(@NonNull RotationResolverCallbackInternal callback,
+ @Surface.Rotation int proposedRotation, @Surface.Rotation int currentRotation,
+ @DurationMillisLong long timeoutMillis,
+ @NonNull CancellationSignal cancellationSignal) {
+ callback.onSuccess(mResult);
+ }
+ }
+
+ final class TestableWindowOrientationListener extends WindowOrientationListener {
+
+ TestableWindowOrientationListener(Context context, Handler handler,
+ WindowManagerService service) {
+ super(context, handler, service);
+ this.mOrientationJudge = new OrientationSensorJudge();
+ }
+
+ @Override
+ public void onProposedRotationChanged(int rotation) {
+ mFinalizedRotation = rotation;
+ }
+
+ @Override
+ public boolean canUseRotationResolver() {
+ return mCanUseRotationResolver;
+ }
+
+ @Override
+ public boolean isRotationResolverEnabled() {
+ return mRotationResolverEnabled;
+ }
+ }
+}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index e68fbd8..b2719fb 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -25,7 +25,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.wm.flicker"/>
- <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6600s" />
<option name="hidden-api-checks" value="false" />
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index dc9e587..e1da3d0 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -84,6 +85,7 @@
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
case TRANSPORT_ETHERNET:
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index c2fddf3..fcfb4aa 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -345,15 +345,17 @@
@Test
public void testRequestType() throws Exception {
final String testPkgName = "MyPackage";
+ final String testAttributionTag = "MyTag";
final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
when(mCtx.getOpPackageName()).thenReturn(testPkgName);
+ when(mCtx.getAttributionTag()).thenReturn(testAttributionTag);
final NetworkRequest request = makeRequest(1);
final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
manager.requestNetwork(request, callback);
verify(mService).requestNetwork(eq(request.networkCapabilities),
eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
- eq(testPkgName), eq(null));
+ eq(testPkgName), eq(testAttributionTag));
reset(mService);
// Verify that register network callback does not calls requestNetwork at all.
@@ -361,19 +363,19 @@
verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(),
anyInt(), any(), any());
verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(),
- eq(testPkgName));
+ eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.registerDefaultNetworkCallback(callback);
verify(mService).requestNetwork(eq(null),
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
- eq(testPkgName), eq(null));
+ eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.requestBackgroundNetwork(request, null, callback);
verify(mService).requestNetwork(eq(request.networkCapabilities),
eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
- eq(testPkgName), eq(null));
+ eq(testPkgName), eq(testAttributionTag));
reset(mService);
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bcbc9e0..bf61634 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -2707,6 +2707,10 @@
NetworkCapabilities filter = new NetworkCapabilities();
filter.addCapability(capability);
+ // Add NOT_VCN_MANAGED capability into filter unconditionally since some request will add
+ // NOT_VCN_MANAGED automatically but not for NetworkCapabilities,
+ // see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details.
+ filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
handlerThread.start();
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
@@ -3958,6 +3962,7 @@
handlerThread.start();
NetworkCapabilities filter = new NetworkCapabilities()
.addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.addCapability(NET_CAPABILITY_INTERNET);
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
mServiceContext, "testFactory", filter);
@@ -5861,6 +5866,7 @@
.addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkDownstreamBandwidthKbps(10);
final NetworkCapabilities wifiNc = new NetworkCapabilities()
.addTransportType(TRANSPORT_WIFI)
@@ -5869,6 +5875,7 @@
.addCapability(NET_CAPABILITY_NOT_ROAMING)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkUpstreamBandwidthKbps(20);
mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
@@ -6365,7 +6372,7 @@
private void assertDefaultNetworkCapabilities(int userId, NetworkAgentWrapper... networks) {
final NetworkCapabilities[] defaultCaps = mService.getDefaultNetworkCapabilitiesForUser(
- userId, "com.android.calling.package");
+ userId, "com.android.calling.package", "com.test");
final String defaultCapsString = Arrays.toString(defaultCaps);
assertEquals(defaultCapsString, defaultCaps.length, networks.length);
final Set<NetworkCapabilities> defaultCapsSet = new ArraySet<>(defaultCaps);
@@ -7514,19 +7521,13 @@
mWiFiNetworkAgent.removeCapability(testCap);
callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
- // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
- // it.
- if (testCap == NET_CAPABILITY_TRUSTED) {
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
- }
+ verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
mCellNetworkAgent.removeCapability(testCap);
callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
callbackWithoutCap.assertNoCallback();
- if (testCap == NET_CAPABILITY_TRUSTED) {
- verify(mMockNetd).networkClearDefault();
- }
+ verify(mMockNetd).networkClearDefault();
mCm.unregisterNetworkCallback(callbackWithCap);
mCm.unregisterNetworkCallback(callbackWithoutCap);
@@ -8377,7 +8378,8 @@
when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
if (op != null) {
- when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
+ when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()),
+ eq(mContext.getPackageName()), eq(getAttributionTag()), anyString()))
.thenReturn(AppOpsManager.MODE_ALLOWED);
}
@@ -8390,7 +8392,7 @@
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName()).getOwnerUid();
+ netCap, callerUid, mContext.getPackageName(), getAttributionTag()).getOwnerUid();
}
private void verifyWifiInfoCopyNetCapsForCallerPermission(
@@ -8400,7 +8402,7 @@
final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName());
+ netCap, callerUid, mContext.getPackageName(), getAttributionTag());
verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index e20070e..278d93a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -18,22 +18,35 @@
import static android.net.IpSecManager.DIRECTION_IN;
import static android.net.IpSecManager.DIRECTION_OUT;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Collections;
/** Tests for VcnGatewayConnection.ConnectedState */
@RunWith(AndroidJUnit4.class)
@@ -107,6 +120,51 @@
}
@Test
+ public void testChildOpenedRegistersNetwork() throws Exception {
+ final VcnChildSessionConfiguration mMockChildSessionConfig =
+ mock(VcnChildSessionConfiguration.class);
+ doReturn(Collections.singletonList(TEST_INTERNAL_ADDR))
+ .when(mMockChildSessionConfig)
+ .getInternalAddresses();
+ doReturn(Collections.singletonList(TEST_DNS_ADDR))
+ .when(mMockChildSessionConfig)
+ .getInternalDnsServers();
+
+ getChildSessionCallback().onOpened(mMockChildSessionConfig);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+
+ final ArgumentCaptor<LinkProperties> lpCaptor =
+ ArgumentCaptor.forClass(LinkProperties.class);
+ final ArgumentCaptor<NetworkCapabilities> ncCaptor =
+ ArgumentCaptor.forClass(NetworkCapabilities.class);
+ verify(mConnMgr)
+ .registerNetworkAgent(
+ any(),
+ any(),
+ lpCaptor.capture(),
+ ncCaptor.capture(),
+ anyInt(),
+ any(),
+ anyInt());
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
+
+ final LinkProperties lp = lpCaptor.getValue();
+ assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses());
+ assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers());
+
+ final NetworkCapabilities nc = ncCaptor.getValue();
+ assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+ for (int cap : mConfig.getAllExposedCapabilities()) {
+ assertTrue(nc.hasCapability(cap));
+ }
+ }
+
+ @Test
public void testChildSessionClosedTriggersDisconnect() throws Exception {
getChildSessionCallback().onClosed();
mTestLooper.dispatchAll();
@@ -122,6 +180,4 @@
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
verify(mIkeSession).close();
}
-
- // TODO: Add tests for childOpened() when ChildSessionConfiguration can be mocked or created
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
new file mode 100644
index 0000000..3f2b47c
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.RetryTimeoutState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState);
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testNewNetworkTriggerRetry() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testSameNetworkDoesNotTriggerRetry() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testNullNetworkTriggersDisconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testTimeoutElapsingTriggersRetry() throws Exception {
+ mTestLooper.moveTimeForward(mConfig.getRetryIntervalsMs()[0]);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 333b5b9..d449eab 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -27,10 +27,13 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.InetAddresses;
import android.net.IpSecConfig;
import android.net.IpSecManager;
import android.net.IpSecTransform;
import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -44,15 +47,22 @@
import com.android.server.IpSecService;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
+import java.net.InetAddress;
import java.util.Collections;
import java.util.UUID;
public class VcnGatewayConnectionTestBase {
protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
+ protected static final InetAddress TEST_DNS_ADDR =
+ InetAddresses.parseNumericAddress("2001:DB8:0:1::");
+ protected static final LinkAddress TEST_INTERNAL_ADDR =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64);
+
protected static final int TEST_IPSEC_SPI_VALUE = 0x1234;
protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2;
@@ -86,6 +96,7 @@
@NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
@NonNull protected final IpSecService mIpSecSvc;
+ @NonNull protected final ConnectivityManager mConnMgr;
protected VcnIkeSession mMockIkeSession;
protected VcnGatewayConnection mGatewayConnection;
@@ -103,6 +114,10 @@
mIpSecSvc = mock(IpSecService.class);
setupIpSecManager(mContext, mIpSecSvc);
+ mConnMgr = mock(ConnectivityManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
doReturn(mContext).when(mVcnContext).getContext();
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
@@ -145,10 +160,10 @@
return captor.getValue();
}
- protected ChildSessionCallback getChildSessionCallback() {
+ protected VcnChildSessionCallback getChildSessionCallback() {
ArgumentCaptor<ChildSessionCallback> captor =
ArgumentCaptor.forClass(ChildSessionCallback.class);
verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture());
- return captor.getValue();
+ return (VcnChildSessionCallback) captor.getValue();
}
}