Merge "Merge SV transactions to VRI BlastBufferQueue"
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index ce16a78..36348b3 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -122,17 +122,26 @@
* @hide
*/
public static final int RULE_REJECT_ALL = 1 << 6;
+ /**
+ * Reject traffic on all networks for restricted networking mode.
+ */
+ public static final int RULE_REJECT_RESTRICTED_MODE = 1 << 10;
/**
* Mask used to get the {@code RULE_xxx_METERED} rules
* @hide
*/
- public static final int MASK_METERED_NETWORKS = 0b00001111;
+ public static final int MASK_METERED_NETWORKS = 0b000000001111;
/**
* Mask used to get the {@code RULE_xxx_ALL} rules
* @hide
*/
- public static final int MASK_ALL_NETWORKS = 0b11110000;
+ public static final int MASK_ALL_NETWORKS = 0b000011110000;
+ /**
+ * Mask used to get the {@code RULE_xxx_RESTRICTED_MODE} rules
+ * @hide
+ */
+ public static final int MASK_RESTRICTED_MODE_NETWORKS = 0b111100000000;
/** @hide */
public static final int FIREWALL_RULE_DEFAULT = 0;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 342c4b3..4632621 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14627,6 +14627,17 @@
*/
public static final String MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH =
"maximum_obscuring_opacity_for_touch";
+
+ /**
+ * Used to enable / disable the Restricted Networking Mode in which network access is
+ * restricted to apps holding the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
+ *
+ * Values are:
+ * 0: disabled
+ * 1: enabled
+ * @hide
+ */
+ public static final String RESTRICTED_NETWORKING_MODE = "restricted_networking_mode";
}
/**
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 80437be..49cd3a6 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1334,6 +1334,23 @@
@VisibleForTesting
public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme) {
+ // TODO(b/166736352): We should only skip the animation of specific types, not all types.
+ boolean skipAnim = false;
+ if ((types & ime()) != 0) {
+ final InsetsSourceConsumer consumer = mSourceConsumers.get(ITYPE_IME);
+ final InsetsSourceControl imeControl = consumer != null ? consumer.getControl() : null;
+ // Skip showing animation once that made by system for some reason.
+ // (e.g. starting window with IME snapshot)
+ if (imeControl != null && show) {
+ skipAnim = imeControl.getAndClearSkipAnimationOnce();
+ }
+ }
+ applyAnimation(types, show, fromIme, skipAnim);
+ }
+
+ @VisibleForTesting
+ public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme,
+ boolean skipAnim) {
if (types == 0) {
// nothing to animate.
if (DEBUG) Log.d(TAG, "applyAnimation, nothing to animate");
@@ -1342,7 +1359,7 @@
boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
final InternalAnimationControlListener listener = new InternalAnimationControlListener(
- show, hasAnimationCallbacks, types, mAnimationsDisabled,
+ show, hasAnimationCallbacks, types, skipAnim || mAnimationsDisabled,
mHost.dipToPx(InternalAnimationControlListener.FLOATING_IME_BOTTOM_INSET));
// Show/hide animations always need to be relative to the display frame, in order that shown
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 5ddbd02..c717c2a 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -41,6 +41,7 @@
private final @InternalInsetsType int mType;
private final @Nullable SurfaceControl mLeash;
private final Point mSurfacePosition;
+ private boolean mSkipAnimationOnce;
public InsetsSourceControl(@InternalInsetsType int type, @Nullable SurfaceControl leash,
Point surfacePosition) {
@@ -57,6 +58,7 @@
mLeash = null;
}
mSurfacePosition = new Point(other.mSurfacePosition);
+ mSkipAnimationOnce = other.getAndClearSkipAnimationOnce();
}
public int getType() {
@@ -77,6 +79,7 @@
mType = in.readInt();
mLeash = in.readParcelable(null /* loader */);
mSurfacePosition = in.readParcelable(null /* loader */);
+ mSkipAnimationOnce = in.readBoolean();
}
public boolean setSurfacePosition(int left, int top) {
@@ -87,10 +90,27 @@
return true;
}
+ public void setSkipAnimationOnce(boolean skipAnimation) {
+ mSkipAnimationOnce = skipAnimation;
+ }
+
public Point getSurfacePosition() {
return mSurfacePosition;
}
+ /**
+ * Get the state whether the current control needs to skip animation or not.
+ *
+ * Note that this is a one-time check that the state is only valid and can be called when
+ * {@link InsetsController#applyAnimation} to check if the current control can skip animation
+ * at this time, and then will clear the state value.
+ */
+ public boolean getAndClearSkipAnimationOnce() {
+ final boolean result = mSkipAnimationOnce;
+ mSkipAnimationOnce = false;
+ return result;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -101,6 +121,7 @@
dest.writeInt(mType);
dest.writeParcelable(mLeash, 0 /* flags*/);
dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
+ dest.writeBoolean(mSkipAnimationOnce);
}
public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) {
@@ -114,6 +135,7 @@
pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType));
pw.print(" mLeash="); pw.print(mLeash);
pw.print(" mSurfacePosition="); pw.print(mSurfacePosition);
+ pw.print(" mSkipAnimationOnce="); pw.print(mSkipAnimationOnce);
pw.println();
}
diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java
index 9834aad..dc07e44 100644
--- a/core/java/android/window/TaskSnapshot.java
+++ b/core/java/android/window/TaskSnapshot.java
@@ -60,6 +60,7 @@
private final @WindowInsetsController.Appearance
int mAppearance;
private final boolean mIsTranslucent;
+ private final boolean mHasImeSurface;
// Must be one of the named color spaces, otherwise, always use SRGB color space.
private final ColorSpace mColorSpace;
@@ -68,7 +69,7 @@
@NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize,
Rect contentInsets, boolean isLowResolution, boolean isRealSnapshot,
int windowingMode, @WindowInsetsController.Appearance int appearance,
- boolean isTranslucent) {
+ boolean isTranslucent, boolean hasImeSurface) {
mId = id;
mTopActivityComponent = topActivityComponent;
mSnapshot = snapshot;
@@ -83,6 +84,7 @@
mWindowingMode = windowingMode;
mAppearance = appearance;
mIsTranslucent = isTranslucent;
+ mHasImeSurface = hasImeSurface;
}
private TaskSnapshot(Parcel source) {
@@ -102,6 +104,7 @@
mWindowingMode = source.readInt();
mAppearance = source.readInt();
mIsTranslucent = source.readBoolean();
+ mHasImeSurface = source.readBoolean();
}
/**
@@ -201,6 +204,13 @@
}
/**
+ * @return Whether or not the snapshot has the IME surface.
+ */
+ public boolean hasImeSurface() {
+ return mHasImeSurface;
+ }
+
+ /**
* @return The windowing mode of the task when this snapshot was taken.
*/
public int getWindowingMode() {
@@ -237,6 +247,7 @@
dest.writeInt(mWindowingMode);
dest.writeInt(mAppearance);
dest.writeBoolean(mIsTranslucent);
+ dest.writeBoolean(mHasImeSurface);
}
@Override
@@ -256,7 +267,8 @@
+ " mIsRealSnapshot=" + mIsRealSnapshot
+ " mWindowingMode=" + mWindowingMode
+ " mAppearance=" + mAppearance
- + " mIsTranslucent=" + mIsTranslucent;
+ + " mIsTranslucent=" + mIsTranslucent
+ + " mHasImeSurface=" + mHasImeSurface;
}
public static final @NonNull Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
@@ -283,6 +295,7 @@
private @WindowInsetsController.Appearance
int mAppearance;
private boolean mIsTranslucent;
+ private boolean mHasImeSurface;
private int mPixelFormat;
public Builder setId(long id) {
@@ -290,8 +303,7 @@
return this;
}
- public Builder setTopActivityComponent(
- ComponentName name) {
+ public Builder setTopActivityComponent(ComponentName name) {
mTopActivity = name;
return this;
}
@@ -329,8 +341,7 @@
return this;
}
- public Builder setIsRealSnapshot(
- boolean realSnapshot) {
+ public Builder setIsRealSnapshot(boolean realSnapshot) {
mIsRealSnapshot = realSnapshot;
return this;
}
@@ -340,18 +351,24 @@
return this;
}
- public Builder setAppearance(
- @WindowInsetsController.Appearance int appearance) {
+ public Builder setAppearance(@WindowInsetsController.Appearance int appearance) {
mAppearance = appearance;
return this;
}
- public Builder setIsTranslucent(
- boolean isTranslucent) {
+ public Builder setIsTranslucent(boolean isTranslucent) {
mIsTranslucent = isTranslucent;
return this;
}
+ /**
+ * Sets the IME visibility when taking the snapshot of the task.
+ */
+ public Builder setHasImeSurface(boolean hasImeSurface) {
+ mHasImeSurface = hasImeSurface;
+ return this;
+ }
+
public int getPixelFormat() {
return mPixelFormat;
}
@@ -378,7 +395,8 @@
mIsRealSnapshot,
mWindowingMode,
mAppearance,
- mIsTranslucent);
+ mIsTranslucent,
+ mHasImeSurface);
}
}
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index db838e8..970ab79 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -128,4 +128,26 @@
eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(true) /* fromIme */);
});
}
+
+ @Test
+ public void testImeGetAndClearSkipAnimationOnce() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ // Request IME visible before control is available.
+ mImeConsumer.onWindowFocusGained();
+ mImeConsumer.applyImeVisibility(true /* setVisible */);
+
+ // set control and verify visibility is applied.
+ InsetsSourceControl control = Mockito.spy(
+ new InsetsSourceControl(ITYPE_IME, mLeash, new Point()));
+ // Simulate IME source control set this flag when the target has starting window.
+ control.setSkipAnimationOnce(true);
+ mController.onControlsChanged(new InsetsSourceControl[] { control });
+ // Verify IME show animation should be triggered when control becomes available and
+ // the animation will be skipped by getAndClearSkipAnimationOnce invoked.
+ verify(control).getAndClearSkipAnimationOnce();
+ verify(mController).applyAnimation(
+ eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
+ eq(true) /* skipAnim */);
+ });
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
index 94af329..414a0a7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
@@ -96,7 +96,7 @@
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
Surface.ROTATION_0, taskSize, contentInsets, false,
true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
- 0 /* systemUiVisibility */, false /* isTranslucent */);
+ 0 /* systemUiVisibility */, false /* isTranslucent */, false /* hasImeSurface */);
}
private static TaskDescription createTaskDescription(int background, int statusBar,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 668e267..66165b6 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -146,5 +146,6 @@
VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_USER, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.RESTRICTED_NETWORKING_MODE, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 209218c..2070773 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -420,6 +420,7 @@
Settings.Global.RADIO_WIMAX,
Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS,
Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
+ Settings.Global.RESTRICTED_NETWORKING_MODE,
Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT,
Settings.Global.SAFE_BOOT_DISALLOWED,
Settings.Global.SELINUX_STATUS,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 901a736..77e568c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -37,16 +37,19 @@
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
+import java.util.concurrent.Executor;
+
import javax.inject.Inject;
public class KeyguardDisplayManager {
protected static final String TAG = "KeyguardDisplayManager";
private static boolean DEBUG = KeyguardConstants.DEBUG;
- private final MediaRouter mMediaRouter;
+ private MediaRouter mMediaRouter = null;
private final DisplayManager mDisplayService;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final Context mContext;
@@ -90,10 +93,11 @@
@Inject
public KeyguardDisplayManager(Context context,
- KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
+ KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
+ @UiBackground Executor uiBgExecutor) {
mContext = context;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
- mMediaRouter = mContext.getSystemService(MediaRouter.class);
+ uiBgExecutor.execute(() -> mMediaRouter = mContext.getSystemService(MediaRouter.class));
mDisplayService = mContext.getSystemService(DisplayManager.class);
mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
}
@@ -162,8 +166,12 @@
public void show() {
if (!mShowing) {
if (DEBUG) Log.v(TAG, "show");
- mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
- mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+ if (mMediaRouter != null) {
+ mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+ mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+ } else {
+ Log.w(TAG, "MediaRouter not yet initialized");
+ }
updateDisplays(true /* showing */);
}
mShowing = true;
@@ -172,7 +180,9 @@
public void hide() {
if (mShowing) {
if (DEBUG) Log.v(TAG, "hide");
- mMediaRouter.removeCallback(mMediaRouterCallback);
+ if (mMediaRouter != null) {
+ mMediaRouter.removeCallback(mMediaRouterCallback);
+ }
updateDisplays(false /* showing */);
}
mShowing = false;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 5bd352c..676f421 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -78,6 +78,7 @@
static final int NTWK_BLOCKED_BG_RESTRICT = 5;
static final int NTWK_ALLOWED_DEFAULT = 6;
static final int NTWK_ALLOWED_SYSTEM = 7;
+ static final int NTWK_BLOCKED_RESTRICTED_MODE = 8;
private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
@@ -281,6 +282,8 @@
return "blocked when background is restricted";
case NTWK_ALLOWED_DEFAULT:
return "allowed by default";
+ case NTWK_BLOCKED_RESTRICTED_MODE:
+ return "blocked by restricted networking mode";
default:
return String.valueOf(reason);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index a486096..38ffccd 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
+import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS;
import static android.Manifest.permission.NETWORK_SETTINGS;
@@ -44,6 +45,7 @@
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED;
import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
import static android.net.INetd.FIREWALL_RULE_ALLOW;
import static android.net.INetd.FIREWALL_RULE_DENY;
@@ -57,6 +59,7 @@
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
+import static android.net.NetworkPolicyManager.MASK_RESTRICTED_MODE_NETWORKS;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -65,12 +68,14 @@
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE;
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
import static android.net.NetworkPolicyManager.resolveNetworkId;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.NetworkTemplate.MATCH_MOBILE;
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
@@ -111,6 +116,7 @@
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_DENYLIST;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_POWER;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_RESTRICTED_MODE;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -143,6 +149,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager;
@@ -442,7 +449,10 @@
@GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictPower;
@GuardedBy("mUidRulesFirstLock") volatile boolean mDeviceIdleMode;
// Store whether user flipped restrict background in battery saver mode
- @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackgroundChangedInBsm;
+ @GuardedBy("mUidRulesFirstLock")
+ volatile boolean mRestrictBackgroundChangedInBsm;
+ @GuardedBy("mUidRulesFirstLock")
+ volatile boolean mRestrictedNetworkingMode;
private final boolean mSuppressDefaultPolicy;
@@ -476,6 +486,8 @@
final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
@GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
+ @GuardedBy("mUidRulesFirstLock")
+ final SparseIntArray mUidFirewallRestrictedModeRules = new SparseIntArray();
/** Set of states for the child firewall chains. True if the chain is active. */
@GuardedBy("mUidRulesFirstLock")
@@ -595,6 +607,8 @@
@GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray();
+ private RestrictedModeObserver mRestrictedModeObserver;
+
// TODO: keep allowlist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
@@ -608,7 +622,35 @@
int COUNT = IS_UID_NETWORKING_BLOCKED + 1;
}
- public final StatLogger mStatLogger = new StatLogger(new String[] {
+ private static class RestrictedModeObserver extends ContentObserver {
+ private final Context mContext;
+ private final RestrictedModeListener mListener;
+
+ RestrictedModeObserver(Context ctx, RestrictedModeListener listener) {
+ super(null);
+ mContext = ctx;
+ mListener = listener;
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.RESTRICTED_NETWORKING_MODE), false,
+ this);
+ }
+
+ public boolean isRestrictedModeEnabled() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.RESTRICTED_NETWORKING_MODE, 0) != 0;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mListener.onChange(isRestrictedModeEnabled());
+ }
+
+ public interface RestrictedModeListener {
+ void onChange(boolean enabled);
+ }
+ }
+
+ public final StatLogger mStatLogger = new StatLogger(new String[]{
"updateNetworkEnabledNL()",
"isUidNetworkingBlocked()",
});
@@ -783,6 +825,15 @@
mRestrictPower = mPowerManagerInternal.getLowPowerState(
ServiceType.NETWORK_FIREWALL).batterySaverEnabled;
+ mRestrictedModeObserver = new RestrictedModeObserver(mContext,
+ enabled -> {
+ synchronized (mUidRulesFirstLock) {
+ mRestrictedNetworkingMode = enabled;
+ updateRestrictedModeAllowlistUL();
+ }
+ });
+ mRestrictedNetworkingMode = mRestrictedModeObserver.isRestrictedModeEnabled();
+
mSystemReady = true;
waitForAdminData();
@@ -3496,6 +3547,7 @@
fout.print("Restrict background: "); fout.println(mRestrictBackground);
fout.print("Restrict power: "); fout.println(mRestrictPower);
fout.print("Device idle: "); fout.println(mDeviceIdleMode);
+ fout.print("Restricted networking mode: "); fout.println(mRestrictedNetworkingMode);
synchronized (mMeteredIfacesLock) {
fout.print("Metered ifaces: ");
fout.println(mMeteredIfaces);
@@ -3808,6 +3860,93 @@
}
}
+ /**
+ * updates restricted mode state / access for all apps
+ * Called on initialization and when restricted mode is enabled / disabled.
+ */
+ @VisibleForTesting
+ @GuardedBy("mUidRulesFirstLock")
+ void updateRestrictedModeAllowlistUL() {
+ mUidFirewallRestrictedModeRules.clear();
+ forEachUid("updateRestrictedModeAllowlist", uid -> {
+ final int oldUidRule = mUidRules.get(uid);
+ final int newUidRule = getNewRestrictedModeUidRule(uid, oldUidRule);
+ final boolean hasUidRuleChanged = oldUidRule != newUidRule;
+ final int newFirewallRule = getRestrictedModeFirewallRule(newUidRule);
+
+ // setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
+ // non-default rules.
+ if (newFirewallRule != FIREWALL_RULE_DEFAULT) {
+ mUidFirewallRestrictedModeRules.append(uid, newFirewallRule);
+ }
+
+ if (hasUidRuleChanged) {
+ mUidRules.put(uid, newUidRule);
+ mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
+ }
+ });
+ if (mRestrictedNetworkingMode) {
+ // firewall rules only need to be set when this mode is being enabled.
+ setUidFirewallRulesUL(FIREWALL_CHAIN_RESTRICTED, mUidFirewallRestrictedModeRules);
+ }
+ enableFirewallChainUL(FIREWALL_CHAIN_RESTRICTED, mRestrictedNetworkingMode);
+ }
+
+ // updates restricted mode state / access for a single app / uid.
+ @VisibleForTesting
+ @GuardedBy("mUidRulesFirstLock")
+ void updateRestrictedModeForUidUL(int uid) {
+ final int oldUidRule = mUidRules.get(uid);
+ final int newUidRule = getNewRestrictedModeUidRule(uid, oldUidRule);
+ final boolean hasUidRuleChanged = oldUidRule != newUidRule;
+
+ if (hasUidRuleChanged) {
+ mUidRules.put(uid, newUidRule);
+ mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
+ }
+
+ // if restricted networking mode is on, and the app has an access exemption, the uid rule
+ // will not change, but the firewall rule will have to be updated.
+ if (mRestrictedNetworkingMode) {
+ // Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules.
+ // In this case, default firewall rules can also be added.
+ setUidFirewallRule(FIREWALL_CHAIN_RESTRICTED, uid,
+ getRestrictedModeFirewallRule(newUidRule));
+ }
+ }
+
+ private int getNewRestrictedModeUidRule(int uid, int oldUidRule) {
+ int newRule = oldUidRule;
+ newRule &= ~MASK_RESTRICTED_MODE_NETWORKS;
+ if (mRestrictedNetworkingMode && !hasRestrictedModeAccess(uid)) {
+ newRule |= RULE_REJECT_RESTRICTED_MODE;
+ }
+ return newRule;
+ }
+
+ private static int getRestrictedModeFirewallRule(int uidRule) {
+ if ((uidRule & RULE_REJECT_RESTRICTED_MODE) != 0) {
+ // rejected in restricted mode, this is the default behavior.
+ return FIREWALL_RULE_DEFAULT;
+ } else {
+ return FIREWALL_RULE_ALLOW;
+ }
+ }
+
+ private boolean hasRestrictedModeAccess(int uid) {
+ try {
+ // TODO: this needs to be kept in sync with
+ // PermissionMonitor#hasRestrictedNetworkPermission
+ return mIPm.checkUidPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, uid)
+ == PERMISSION_GRANTED
+ || mIPm.checkUidPermission(NETWORK_STACK, uid) == PERMISSION_GRANTED
+ || mIPm.checkUidPermission(PERMISSION_MAINLINE_NETWORK_STACK, uid)
+ == PERMISSION_GRANTED;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
@GuardedBy("mUidRulesFirstLock")
void updateRulesForPowerSaveUL() {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL");
@@ -4029,6 +4168,7 @@
updateRulesForAppIdleUL();
updateRulesForRestrictPowerUL();
updateRulesForRestrictBackgroundUL();
+ updateRestrictedModeAllowlistUL();
// If the set of restricted networks may have changed, re-evaluate those.
if (restrictedNetworksChanged) {
@@ -4245,6 +4385,7 @@
mPowerSaveWhitelistAppIds.delete(uid);
mPowerSaveTempWhitelistAppIds.delete(uid);
mAppIdleTempWhitelistAppIds.delete(uid);
+ mUidFirewallRestrictedModeRules.delete(uid);
// ...then update iptables asynchronously.
mHandler.obtainMessage(MSG_RESET_FIREWALL_RULES_BY_UID, uid, 0).sendToTarget();
@@ -4270,6 +4411,10 @@
updateRuleForAppIdleUL(uid);
updateRuleForRestrictPowerUL(uid);
+ // If the uid has the necessary permissions, then it should be added to the restricted mode
+ // firewall allowlist.
+ updateRestrictedModeForUidUL(uid);
+
// Update internal state for power-related modes.
updateRulesForPowerRestrictionsUL(uid);
@@ -4995,6 +5140,8 @@
mUidFirewallStandbyRules.put(uid, rule);
} else if (chain == FIREWALL_CHAIN_POWERSAVE) {
mUidFirewallPowerSaveRules.put(uid, rule);
+ } else if (chain == FIREWALL_CHAIN_RESTRICTED) {
+ mUidFirewallRestrictedModeRules.put(uid, rule);
}
try {
@@ -5040,6 +5187,8 @@
mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
mNetworkManager
.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
+ mNetworkManager
+ .setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT);
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
} catch (IllegalStateException e) {
@@ -5226,26 +5375,21 @@
// Networks are never blocked for system components
if (isSystem(uid)) {
reason = NTWK_ALLOWED_SYSTEM;
- }
- else if (hasRule(uidRules, RULE_REJECT_ALL)) {
+ } else if (hasRule(uidRules, RULE_REJECT_RESTRICTED_MODE)) {
+ reason = NTWK_BLOCKED_RESTRICTED_MODE;
+ } else if (hasRule(uidRules, RULE_REJECT_ALL)) {
reason = NTWK_BLOCKED_POWER;
- }
- else if (!isNetworkMetered) {
+ } else if (!isNetworkMetered) {
reason = NTWK_ALLOWED_NON_METERED;
- }
- else if (hasRule(uidRules, RULE_REJECT_METERED)) {
+ } else if (hasRule(uidRules, RULE_REJECT_METERED)) {
reason = NTWK_BLOCKED_DENYLIST;
- }
- else if (hasRule(uidRules, RULE_ALLOW_METERED)) {
+ } else if (hasRule(uidRules, RULE_ALLOW_METERED)) {
reason = NTWK_ALLOWED_ALLOWLIST;
- }
- else if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
+ } else if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
reason = NTWK_ALLOWED_TMP_ALLOWLIST;
- }
- else if (isBackgroundRestricted) {
+ } else if (isBackgroundRestricted) {
reason = NTWK_BLOCKED_BG_RESTRICT;
- }
- else {
+ } else {
reason = NTWK_ALLOWED_DEFAULT;
}
@@ -5258,6 +5402,7 @@
case NTWK_ALLOWED_SYSTEM:
blocked = false;
break;
+ case NTWK_BLOCKED_RESTRICTED_MODE:
case NTWK_BLOCKED_POWER:
case NTWK_BLOCKED_DENYLIST:
case NTWK_BLOCKED_BG_RESTRICT:
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 17c3b20..0320a34 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -30,7 +30,9 @@
import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsSource;
+import android.view.InsetsSourceControl;
import android.view.WindowInsets;
+import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -53,6 +55,26 @@
super(source, stateController, displayContent);
}
+ @Override
+ InsetsSourceControl getControl(InsetsControlTarget target) {
+ final InsetsSourceControl control = super.getControl(target);
+ if (control != null && target != null && target.getWindow() != null) {
+ final WindowState targetWin = target.getWindow();
+ // If the control target changes during the app transition with the task snapshot
+ // starting window and the IME snapshot is visible, in case not have duplicated IME
+ // showing animation during transitioning, use a flag to inform IME source control to
+ // skip showing animation once.
+ final TaskSnapshot snapshot = targetWin.getRootTask() != null
+ ? targetWin.mWmService.getTaskSnapshot(targetWin.getRootTask().mTaskId,
+ 0 /* userId */, false /* isLowResolution */, false /* restoreFromDisk */)
+ : null;
+ control.setSkipAnimationOnce(targetWin.mActivityRecord != null
+ && targetWin.mActivityRecord.hasStartingWindow()
+ && snapshot != null && snapshot.hasImeSurface());
+ }
+ return control;
+ }
+
/**
* Called from {@link WindowManagerInternal#showImePostLayout} when {@link InputMethodService}
* requests to show IME on {@param imeTarget}.
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 28a99825..ff5b356 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -103,8 +103,7 @@
mSource = source;
mDisplayContent = displayContent;
mStateController = stateController;
- mFakeControl = new InsetsSourceControl(source.getType(), null /* leash */,
- new Point());
+ mFakeControl = new InsetsSourceControl(source.getType(), null /* leash */, new Point());
switch (source.getType()) {
case ITYPE_STATUS_BAR:
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index de9fb6a..ed90cc75 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -24,7 +24,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.window.TaskSnapshot;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
@@ -43,6 +42,7 @@
import android.view.WindowInsets.Type;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowManager.LayoutParams;
+import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
@@ -344,20 +344,20 @@
TaskSnapshot.Builder builder) {
Point taskSize = new Point();
final SurfaceControl.ScreenshotHardwareBuffer taskSnapshot = createTaskSnapshot(task,
- mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize);
+ mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize, builder);
builder.setTaskSize(taskSize);
return taskSnapshot;
}
@Nullable
SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
- float scaleFraction) {
- return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888, null);
+ float scaleFraction, TaskSnapshot.Builder builder) {
+ return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888, null, builder);
}
@Nullable
SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
- float scaleFraction, int pixelFormat, Point outTaskSize) {
+ float scaleFraction, int pixelFormat, Point outTaskSize, TaskSnapshot.Builder builder) {
if (task.getSurfaceControl() == null) {
if (DEBUG_SCREENSHOT) {
Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task);
@@ -376,6 +376,7 @@
excludeLayers[0] = imeWindow.getSurfaceControl();
} else {
excludeLayers = new SurfaceControl[0];
+ builder.setHasImeSurface(imeWindow != null && imeWindow.isDrawn());
}
final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
SurfaceControl.captureLayersExcluding(
@@ -510,7 +511,8 @@
hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation,
mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight),
contentInsets, false /* isLowResolution */, false /* isRealSnapshot */,
- task.getWindowingMode(), getAppearance(task), false);
+ task.getWindowingMode(), getAppearance(task), false /* isTranslucent */,
+ false /* hasImeSurface */);
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index cfdb6b3..d3bfbab 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -197,7 +197,7 @@
hwBitmap.getColorSpace(), proto.orientation, proto.rotation, taskSize,
new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
loadLowResolutionBitmap, proto.isRealSnapshot, proto.windowingMode,
- proto.appearance, proto.isTranslucent);
+ proto.appearance, proto.isTranslucent, false /* hasImeSurface */);
} catch (IOException e) {
Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);
return null;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e872c10..a8f4bae 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2927,7 +2927,7 @@
/**
* Returns {@code true} if this window has been shown on screen at some time in the past.
*
- * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods.
+ * @deprecated Use {@link #isDrawn} or any of the other drawn/visibility methods.
*/
@Deprecated
boolean hasDrawn() {
diff --git a/services/core/jni/gnss/Utils.h b/services/core/jni/gnss/Utils.h
index 32f53d0..0938a1b 100644
--- a/services/core/jni/gnss/Utils.h
+++ b/services/core/jni/gnss/Utils.h
@@ -64,6 +64,18 @@
}
template <class T>
+jboolean checkHidlReturn(hardware::Return<sp<T>>& result, const char* errorMessage) {
+ if (!result.isOk()) {
+ logHidlError(result, errorMessage);
+ return JNI_FALSE;
+ } else if ((sp<T>)result == nullptr) {
+ return JNI_FALSE;
+ } else {
+ return JNI_TRUE;
+ }
+}
+
+template <class T>
class JavaMethodHelper {
public:
// Helper function to call setter on a Java object.
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index fec0273..4db7ce2 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -16,13 +16,18 @@
package com.android.server.net;
+import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED;
+import static android.net.INetd.FIREWALL_RULE_ALLOW;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -34,6 +39,7 @@
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.TAG_ALL;
@@ -74,6 +80,7 @@
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
@@ -97,6 +104,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
@@ -123,6 +131,7 @@
import android.os.SimpleClock;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
@@ -131,6 +140,7 @@
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.MediumTest;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.DataUnit;
import android.util.Log;
import android.util.Pair;
@@ -187,6 +197,7 @@
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@@ -240,6 +251,7 @@
private @Mock SubscriptionManager mSubscriptionManager;
private @Mock CarrierConfigManager mCarrierConfigManager;
private @Mock TelephonyManager mTelephonyManager;
+ private @Mock UserManager mUserManager;
private ArgumentCaptor<ConnectivityManager.NetworkCallback> mNetworkCallbackCaptor =
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
@@ -351,6 +363,8 @@
return mNotifManager;
case Context.CONNECTIVITY_SERVICE:
return mConnectivityManager;
+ case Context.USER_SERVICE:
+ return mUserManager;
default:
return super.getSystemService(name);
}
@@ -407,11 +421,14 @@
when(mPackageManager.getPackagesForUid(UID_B)).thenReturn(new String[] {PKG_NAME_B});
when(mPackageManager.getPackagesForUid(UID_C)).thenReturn(new String[] {PKG_NAME_C});
when(mPackageManager.getApplicationInfo(eq(PKG_NAME_A), anyInt()))
- .thenReturn(buildApplicationInfo(PKG_NAME_A));
+ .thenReturn(buildApplicationInfo(PKG_NAME_A, UID_A));
when(mPackageManager.getApplicationInfo(eq(PKG_NAME_B), anyInt()))
- .thenReturn(buildApplicationInfo(PKG_NAME_B));
+ .thenReturn(buildApplicationInfo(PKG_NAME_B, UID_B));
when(mPackageManager.getApplicationInfo(eq(PKG_NAME_C), anyInt()))
- .thenReturn(buildApplicationInfo(PKG_NAME_C));
+ .thenReturn(buildApplicationInfo(PKG_NAME_C, UID_C));
+ when(mPackageManager.getInstalledApplications(anyInt())).thenReturn(
+ buildInstalledApplicationInfoList());
+ when(mUserManager.getUsers()).thenReturn(buildUserInfoList());
when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true);
doNothing().when(mConnectivityManager)
@@ -1874,6 +1891,66 @@
}
}
+ private void enableRestrictedMode(boolean enable) throws Exception {
+ mService.mRestrictedNetworkingMode = enable;
+ mService.updateRestrictedModeAllowlistUL();
+ verify(mNetworkManager).setFirewallChainEnabled(FIREWALL_CHAIN_RESTRICTED,
+ enable);
+ }
+
+ @Test
+ public void testUpdateRestrictedModeAllowlist() throws Exception {
+ // initialization calls setFirewallChainEnabled, so we want to reset the invocations.
+ clearInvocations(mNetworkManager);
+ expectHasUseRestrictedNetworksPermission(UID_A, true);
+ expectHasUseRestrictedNetworksPermission(UID_B, false);
+
+ Map<Integer, Integer> firewallUidRules = new ArrayMap<>();
+ doAnswer(arg -> {
+ int[] uids = arg.getArgument(1);
+ int[] rules = arg.getArgument(2);
+ assertTrue(uids.length == rules.length);
+
+ for (int i = 0; i < uids.length; ++i) {
+ firewallUidRules.put(uids[i], rules[i]);
+ }
+ return null;
+ }).when(mNetworkManager).setFirewallUidRules(eq(FIREWALL_CHAIN_RESTRICTED),
+ any(int[].class), any(int[].class));
+
+ enableRestrictedMode(true);
+ assertEquals(FIREWALL_RULE_ALLOW, firewallUidRules.get(UID_A).intValue());
+ assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+ assertTrue(mService.isUidNetworkingBlocked(UID_B, false));
+
+ enableRestrictedMode(false);
+ assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+ assertFalse(mService.isUidNetworkingBlocked(UID_B, false));
+ }
+
+ @Test
+ public void testUpdateRestrictedModeForUid() throws Exception {
+ // initialization calls setFirewallChainEnabled, so we want to reset the invocations.
+ clearInvocations(mNetworkManager);
+ expectHasUseRestrictedNetworksPermission(UID_A, true);
+ expectHasUseRestrictedNetworksPermission(UID_B, false);
+ enableRestrictedMode(true);
+
+ // UID_D and UID_E are not part of installed applications list, so it won't have any
+ // firewall rules set yet
+ expectHasUseRestrictedNetworksPermission(UID_D, false);
+ mService.updateRestrictedModeForUidUL(UID_D);
+ verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, UID_D,
+ FIREWALL_RULE_DEFAULT);
+ assertTrue(mService.isUidNetworkingBlocked(UID_D, false));
+
+ expectHasUseRestrictedNetworksPermission(UID_E, true);
+ mService.updateRestrictedModeForUidUL(UID_E);
+ verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, UID_E,
+ FIREWALL_RULE_ALLOW);
+ assertFalse(mService.isUidNetworkingBlocked(UID_E, false));
+ }
+
private String formatBlockedStateError(int uid, int rule, boolean metered,
boolean backgroundRestricted) {
return String.format(
@@ -1888,12 +1965,27 @@
.build();
}
- private ApplicationInfo buildApplicationInfo(String label) {
+ private ApplicationInfo buildApplicationInfo(String label, int uid) {
final ApplicationInfo ai = new ApplicationInfo();
ai.nonLocalizedLabel = label;
+ ai.uid = uid;
return ai;
}
+ private List<ApplicationInfo> buildInstalledApplicationInfoList() {
+ final List<ApplicationInfo> installedApps = new ArrayList<>();
+ installedApps.add(buildApplicationInfo(PKG_NAME_A, UID_A));
+ installedApps.add(buildApplicationInfo(PKG_NAME_B, UID_B));
+ installedApps.add(buildApplicationInfo(PKG_NAME_C, UID_C));
+ return installedApps;
+ }
+
+ private List<UserInfo> buildUserInfoList() {
+ final List<UserInfo> users = new ArrayList<>();
+ users.add(new UserInfo(USER_ID, "user1", 0));
+ return users;
+ }
+
private NetworkInfo buildNetworkInfo() {
final NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_LTE, null, null);
@@ -1967,6 +2059,15 @@
hasIt ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
}
+ private void expectHasUseRestrictedNetworksPermission(int uid, boolean hasIt) throws Exception {
+ when(mIpm.checkUidPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, uid)).thenReturn(
+ hasIt ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
+ when(mIpm.checkUidPermission(NETWORK_STACK, uid)).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+ when(mIpm.checkUidPermission(PERMISSION_MAINLINE_NETWORK_STACK, uid)).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+ }
+
private void expectNetworkState(boolean roaming) throws Exception {
when(mCarrierConfigManager.getConfigForSubId(eq(TEST_SUB_ID)))
.thenReturn(mCarrierConfig);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 4d37eb2..81712c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -31,6 +31,8 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.WindowConfiguration;
@@ -196,8 +198,37 @@
mDisplayContent.mInputMethodWindow.setSurfaceControl(null);
// Verify no NPE happens when calling createTaskSnapshot.
try {
+ final TaskSnapshot.Builder builder = new TaskSnapshot.Builder();
mWm.mTaskSnapshotController.createTaskSnapshot(mAppWindow.mActivityRecord.getTask(),
- 1f /* scaleFraction */, PixelFormat.UNKNOWN, null /* outTaskSize */);
+ 1f /* scaleFraction */, PixelFormat.UNKNOWN, null /* outTaskSize */, builder);
+ } catch (NullPointerException e) {
+ fail("There should be no exception when calling createTaskSnapshot");
+ }
+ }
+
+ @UseTestDisplay(addWindows = {W_ACTIVITY, W_INPUT_METHOD})
+ @Test
+ public void testCreateTaskSnapshotWithIncludingIme() {
+ Task task = mAppWindow.mActivityRecord.getTask();
+ spyOn(task);
+ spyOn(mDisplayContent);
+ spyOn(mDisplayContent.mInputMethodWindow);
+ when(task.getDisplayContent().isImeAttachedToApp()).thenReturn(true);
+ // Intentionally set the IME window is in drawn state.
+ doReturn(true).when(mDisplayContent.mInputMethodWindow).isDrawn();
+ // Verify no NPE happens when calling createTaskSnapshot.
+ try {
+ final TaskSnapshot.Builder builder = new TaskSnapshot.Builder();
+ spyOn(builder);
+ mWm.mTaskSnapshotController.createTaskSnapshot(
+ mAppWindow.mActivityRecord.getTask(), 1f /* scaleFraction */,
+ PixelFormat.UNKNOWN, null /* outTaskSize */, builder);
+ // Verify the builder should includes IME surface.
+ verify(builder).setHasImeSurface(eq(true));
+ builder.setColorSpace(ColorSpace.get(ColorSpace.Named.SRGB));
+ builder.setTaskSize(new Point(100, 100));
+ final TaskSnapshot snapshot = builder.build();
+ assertTrue(snapshot.hasImeSurface());
} catch (NullPointerException e) {
fail("There should be no exception when calling createTaskSnapshot");
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index d9a794a..edf7056 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -207,7 +207,8 @@
// is always false. Low-res snapshots are only created when loading from
// disk.
false /* isLowResolution */,
- mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, mIsTranslucent);
+ mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, mIsTranslucent,
+ false /* hasImeSurface */);
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index aa638690..eb3a5e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -102,7 +102,7 @@
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
Surface.ROTATION_0, taskSize, contentInsets, false,
true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
- 0 /* systemUiVisibility */, false /* isTranslucent */);
+ 0 /* systemUiVisibility */, false /* isTranslucent */, false /* hasImeSurface */);
}
private static TaskDescription createTaskDescription(int background, int statusBar,
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 515d329..48a5ab6 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -405,6 +405,10 @@
*/
public static boolean checkCallingOrSelfUseIccAuthWithDeviceIdentifier(Context context,
String callingPackage, String callingFeatureId, String message) {
+ // The implementation follows PermissionChecker.checkAppOpPermission, but it cannot be
+ // used directly: because it uses noteProxyOpNoThrow which requires the phone process
+ // having the permission, which doesn't make sense since phone process is the ower of
+ // data/action.
// Cannot perform appop check if the calling package is null
if (callingPackage == null) {
return false;
@@ -413,7 +417,17 @@
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int opMode = appOps.noteOpNoThrow(AppOpsManager.OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
callingUid, callingPackage, callingFeatureId, message);
- return opMode == AppOpsManager.MODE_ALLOWED;
+ switch (opMode) {
+ case AppOpsManager.MODE_ALLOWED:
+ case AppOpsManager.MODE_FOREGROUND:
+ return true;
+ case AppOpsManager.MODE_DEFAULT:
+ return context.checkCallingOrSelfPermission(
+ Manifest.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER)
+ == PERMISSION_GRANTED;
+ default:
+ return false;
+ }
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 30b838e..60389e1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9338,6 +9338,35 @@
}
/**
+ * Get the mobile provisioning url that is used to launch a browser to allow users to manage
+ * their mobile plan.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}.
+ *
+ * TODO: The legacy design only supports single sim design. Ideally, this should support
+ * multi-sim design in current world.
+ *
+ * {@hide}
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @Nullable String getMobileProvisioningUrl() {
+ try {
+ final ITelephony service = getITelephony();
+ if (service != null) {
+ return service.getMobileProvisioningUrl();
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
+ return null;
+ }
+
+ /**
* Turns mobile data on or off.
* If this object has been created with {@link #createForSubscriptionId}, applies to the given
* subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index de4da38..74753ca 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2369,4 +2369,10 @@
* Gets the config of RCS VoLTE single registration enabled for the carrier/subscription.
*/
boolean getCarrierSingleRegistrationEnabled(int subId);
+
+ /**
+ * Return the mobile provisioning url that is used to launch a browser to allow users to manage
+ * their mobile plan.
+ */
+ String getMobileProvisioningUrl();
}