diff options
31 files changed, 723 insertions, 134 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e709a1ac2d36..30a2303a5e41 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3434,8 +3434,13 @@ public final class ActivityThread extends ClientTransactionHandler if (mLastProcessState == processState) { return; } + // Do not issue a transitional GC if we are transitioning between 2 cached states. + // Only update if the state flips between cached and uncached or vice versa + if (ActivityManager.isProcStateCached(mLastProcessState) + != ActivityManager.isProcStateCached(processState)) { + updateVmProcessState(processState); + } mLastProcessState = processState; - updateVmProcessState(processState); if (localLOGV) { Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState + (fromIpc ? " (from ipc" : "")); @@ -3444,12 +3449,16 @@ public final class ActivityThread extends ClientTransactionHandler } /** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */ + // Currently ART VM only uses state updates for Transitional GC, and thus + // this function initiates a Transitional GC for transitions into Cached apps states. private void updateVmProcessState(int processState) { - // TODO: Tune this since things like gmail sync are important background but not jank - // perceptible. - final int state = processState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND - ? VM_PROCESS_STATE_JANK_PERCEPTIBLE - : VM_PROCESS_STATE_JANK_IMPERCEPTIBLE; + // Only a transition into Cached state should result in a Transitional GC request + // to the ART runtime. Update VM state to JANK_IMPERCEPTIBLE in that case. + // Note that there are 4 possible cached states currently, all of which are + // JANK_IMPERCEPTIBLE from GC point of view. + final int state = ActivityManager.isProcStateCached(processState) + ? VM_PROCESS_STATE_JANK_IMPERCEPTIBLE + : VM_PROCESS_STATE_JANK_PERCEPTIBLE; VMRuntime.getRuntime().updateProcessState(state); } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index fad9e0e79899..42255bf3793e 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -1799,10 +1799,15 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, if (!is_system_server && getuid() == 0) { const int rc = createProcessGroup(uid, getpid()); if (rc != 0) { - fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing " - "CONFIG_CGROUP_CPUACCT?") - : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid, - /* pid= */ 0, strerror(-rc))); + if (rc == -ESRCH) { + // If process is dead, treat this as a non-fatal error + ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc)); + } else { + fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing " + "CONFIG_CGROUP_CPUACCT?") + : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid, + /* pid= */ 0, strerror(-rc))); + } } } diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS index 4b125904004a..852edef544b8 100644 --- a/libs/WindowManager/Shell/OWNERS +++ b/libs/WindowManager/Shell/OWNERS @@ -1,4 +1,4 @@ xutan@google.com # Give submodule owners in shell resource approval -per-file res*/*/*.xml = hwwang@google.com, lbill@google.com, madym@google.com +per-file res*/*/*.xml = hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/OWNERS new file mode 100644 index 000000000000..4417209b85ed --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/OWNERS @@ -0,0 +1 @@ +jorgegil@google.com diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java index 0704da4fb63d..c74490027e1d 100644 --- a/media/java/android/media/MediaCas.java +++ b/media/java/android/media/MediaCas.java @@ -436,7 +436,7 @@ public final class MediaCas implements AutoCloseable { if (mEventHandler != null) { mEventHandler.sendMessage( mEventHandler.obtainMessage( - EventHandler.MSG_CAS_EVENT, event, arg, data)); + EventHandler.MSG_CAS_EVENT, event, arg, toBytes(data))); } } diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index b51c018e3ca0..c33d206b77f7 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -1171,7 +1171,7 @@ public final class MediaFormat { /** * A key describing the desired bitrate mode to be used by an encoder. - * Constants are declared in {@link MediaCodecInfo.CodecCapabilities}. + * Constants are declared in {@link MediaCodecInfo.EncoderCapabilities}. * * @see MediaCodecInfo.EncoderCapabilities#isBitrateModeSupported(int) */ diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java index 162bb2c720e8..b8887ae872d5 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java @@ -49,6 +49,7 @@ public class GlobalSettings { Settings.Global.CHARGING_SOUNDS_ENABLED, Settings.Global.USB_MASS_STORAGE_ENABLED, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, + Settings.Global.NETWORK_AVOID_BAD_WIFI, Settings.Global.WIFI_WAKEUP_ENABLED, Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, Settings.Global.USE_OPEN_WIFI_PACKAGE, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index fbbdd32c5886..3bb76d20be10 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -17,6 +17,9 @@ package android.provider.settings.validators; import static android.media.AudioFormat.SURROUND_SOUND_ENCODING; +import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_AVOID; +import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE; +import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT; import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR; @@ -95,6 +98,14 @@ public class GlobalSettingsValidators { VALIDATORS.put( Global.NETWORK_RECOMMENDATIONS_ENABLED, new DiscreteValueValidator(new String[] {"-1", "0", "1"})); + VALIDATORS.put( + Global.NETWORK_AVOID_BAD_WIFI, + new DiscreteValueValidator( + new String[] { + String.valueOf(NETWORK_AVOID_BAD_WIFI_IGNORE), + String.valueOf(NETWORK_AVOID_BAD_WIFI_PROMPT), + String.valueOf(NETWORK_AVOID_BAD_WIFI_AVOID), + })); VALIDATORS.put(Global.WIFI_WAKEUP_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, BOOLEAN_VALIDATOR); VALIDATORS.put( @@ -338,4 +349,3 @@ public class GlobalSettingsValidators { VALIDATORS.put(Global.Wearable.COOLDOWN_MODE_ON, BOOLEAN_VALIDATOR); } } - diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index ce670d4d2162..2670852b7533 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -374,7 +374,6 @@ public class SettingsBackupTest { Settings.Global.NETPOLICY_QUOTA_FRAC_JOBS, Settings.Global.NETPOLICY_QUOTA_FRAC_MULTIPATH, Settings.Global.NETPOLICY_OVERRIDE_ENABLED, - Settings.Global.NETWORK_AVOID_BAD_WIFI, Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES, Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE, Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 73d9cc759b10..2aa93783c501 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -1483,6 +1483,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { public void setFirewallUidRules(int chain, int[] uids, int[] rules) { enforceSystemUid(); synchronized (mQuotaLock) { + final int[] applicableUidsForChain; synchronized (mRulesLock) { SparseIntArray uidFirewallRules = getUidFirewallRulesLR(chain); SparseIntArray newRules = new SparseIntArray(); @@ -1506,10 +1507,15 @@ public class NetworkManagementService extends INetworkManagementService.Stub { int uid = rulesToRemove.keyAt(index); updateFirewallUidRuleLocked(chain, uid, FIREWALL_RULE_DEFAULT); } + // Copy the keys for the firewall rules chain, which is guaranteed not to include + // default rules. We must not include default rules in the UIDs we send to + // ConnectivityManager#replaceFirewallChain, as this would have the opposite effect + // intended, leading such UIDs to be blocked or allowed erroneously. + applicableUidsForChain = uidFirewallRules.copyKeys(); } final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); try { - cm.replaceFirewallChain(chain, uids); + cm.replaceFirewallChain(chain, applicableUidsForChain); } catch (RuntimeException e) { Slog.w(TAG, "Error flushing firewall chain " + chain, e); } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 78cffa6f4f79..1d9fed767991 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -416,6 +416,8 @@ public class LockSettingsService extends ILockSettings.Stub { static class Injector { protected Context mContext; + private ServiceThread mHandlerThread; + private Handler mHandler; public Injector(Context context) { mContext = context; @@ -426,14 +428,20 @@ public class LockSettingsService extends ILockSettings.Stub { } public ServiceThread getServiceThread() { - ServiceThread handlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, - true /*allowIo*/); - handlerThread.start(); - return handlerThread; + if (mHandlerThread == null) { + mHandlerThread = new ServiceThread(TAG, + Process.THREAD_PRIORITY_BACKGROUND, + true /*allowIo*/); + mHandlerThread.start(); + } + return mHandlerThread; } public Handler getHandler(ServiceThread handlerThread) { - return new Handler(handlerThread.getLooper()); + if (mHandler == null) { + mHandler = new Handler(handlerThread.getLooper()); + } + return mHandler; } public LockSettingsStorage getStorage() { @@ -514,7 +522,8 @@ public class LockSettingsService extends ILockSettings.Stub { public RebootEscrowManager getRebootEscrowManager(RebootEscrowManager.Callbacks callbacks, LockSettingsStorage storage) { - return new RebootEscrowManager(mContext, callbacks, storage); + return new RebootEscrowManager(mContext, callbacks, storage, + getHandler(getServiceThread())); } public boolean hasEnrolledBiometrics(int userId) { diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 9b42cfca2e68..e1cd2c585146 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -205,6 +205,8 @@ class RebootEscrowManager { private final RebootEscrowKeyStoreManager mKeyStoreManager; + private final Handler mHandler; + PowerManager.WakeLock mWakeLock; private ConnectivityManager.NetworkCallback mNetworkCallback; @@ -399,19 +401,21 @@ class RebootEscrowManager { } } - RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage) { - this(new Injector(context, storage), callbacks, storage); + RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage, + Handler handler) { + this(new Injector(context, storage), callbacks, storage, handler); } @VisibleForTesting RebootEscrowManager(Injector injector, Callbacks callbacks, - LockSettingsStorage storage) { + LockSettingsStorage storage, Handler handler) { mInjector = injector; mCallbacks = callbacks; mStorage = storage; mUserManager = injector.getUserManager(); mEventLog = injector.getEventLog(); mKeyStoreManager = injector.getKeyStoreManager(); + mHandler = handler; } /** Wrapper function to set error code serialized through handler, */ @@ -937,7 +941,7 @@ class RebootEscrowManager { private void setRebootEscrowReady(boolean ready) { if (mRebootEscrowReady != ready) { - mRebootEscrowListener.onPreparedForReboot(ready); + mHandler.post(() -> mRebootEscrowListener.onPreparedForReboot(ready)); } mRebootEscrowReady = ready; } diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 2c0e909a5cc0..ea07fe77e588 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -42,6 +42,7 @@ import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Pair; import android.view.Display; +import android.view.IWindow; import android.view.IWindowManager; import android.view.ViewDebug; @@ -553,6 +554,22 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } + private void dumpLocalWindowAsync(IWindow client, ParcelFileDescriptor pfd) { + // Make it asynchronous to avoid writer from being blocked + // by waiting for the buffer to be consumed in the same process. + IoThread.getExecutor().execute(() -> { + synchronized (mInternal.mGlobalLock) { + try { + client.executeCommand(ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null, pfd); + } catch (Exception e) { + // Ignore RemoteException for local call. Just print trace for other + // exceptions caused by RC with tolerable low possibility. + e.printStackTrace(); + } + } + }); + } + private int runDumpVisibleWindowViews(PrintWriter pw) { if (!mInternal.checkCallingPermission(android.Manifest.permission.DUMP, "runDumpVisibleWindowViews()")) { @@ -575,16 +592,7 @@ public class WindowManagerShellCommand extends ShellCommand { pipe = new ByteTransferPipe(); final ParcelFileDescriptor pfd = pipe.getWriteFd(); if (w.isClientLocal()) { - // Make it asynchronous to avoid writer from being blocked - // by waiting for the buffer to be consumed in the same process. - IoThread.getExecutor().execute(() -> { - try { - w.mClient.executeCommand( - ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null, pfd); - } catch (RemoteException e) { - // Ignore for local call. - } - }); + dumpLocalWindowAsync(w.mClient, pfd); } else { w.mClient.executeCommand( ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null, pfd); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java index ce6bd6ccbe51..bb12d699a15c 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java @@ -74,6 +74,8 @@ import org.mockito.ArgumentCaptor; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import javax.crypto.SecretKey; @@ -327,16 +329,30 @@ public class RebootEscrowManagerTests { mInjected = mock(MockableRebootEscrowInjected.class); mMockInjector = new MockInjector(mContext, mUserManager, mRebootEscrow, mKeyStoreManager, mStorage, mInjected); - mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage); HandlerThread thread = new HandlerThread("RebootEscrowManagerTest"); thread.start(); mHandler = new Handler(thread.getLooper()); + mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage, mHandler); + } private void setServerBasedRebootEscrowProvider() throws Exception { mMockInjector = new MockInjector(mContext, mUserManager, mServiceConnection, mKeyStoreManager, mStorage, mInjected); - mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage); + mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage, mHandler); + } + + private void waitForHandler() throws InterruptedException { + // Wait for handler to complete processing. + CountDownLatch latch = new CountDownLatch(1); + mHandler.post(latch::countDown); + assertTrue(latch.await(5, TimeUnit.SECONDS)); + + } + + private void callToRebootEscrowIfNeededAndWait(int userId) throws InterruptedException { + mService.callToRebootEscrowIfNeeded(userId, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + waitForHandler(); } @Test @@ -346,7 +362,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); } @@ -358,8 +374,7 @@ public class RebootEscrowManagerTests { mService.setRebootEscrowListener(mockListener); mService.prepareRebootEscrow(); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); - verify(mockListener).onPreparedForReboot(eq(true)); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); assertFalse(mStorage.hasRebootEscrowServerBlob()); } @@ -369,7 +384,7 @@ public class RebootEscrowManagerTests { RebootEscrowListener mockListener = mock(RebootEscrowListener.class); mService.setRebootEscrowListener(mockListener); mService.prepareRebootEscrow(); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); clearInvocations(mRebootEscrow); @@ -393,7 +408,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); @@ -417,7 +432,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -438,7 +453,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); @@ -456,10 +471,9 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); - mService.callToRebootEscrowIfNeeded(SECURE_SECONDARY_USER_ID, FAKE_SP_VERSION, - FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(SECURE_SECONDARY_USER_ID); verify(mRebootEscrow, never()).storeKey(any()); assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); @@ -491,7 +505,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); @@ -514,7 +528,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); @@ -557,7 +571,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -601,7 +615,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -646,7 +660,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -692,7 +706,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -741,7 +755,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -794,7 +808,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -849,7 +863,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -896,7 +910,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -952,7 +966,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -1011,7 +1025,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -1071,7 +1085,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -1127,7 +1141,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mServiceConnection); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); @@ -1179,7 +1193,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); @@ -1210,7 +1224,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); @@ -1238,7 +1252,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); @@ -1277,7 +1291,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); @@ -1312,7 +1326,7 @@ public class RebootEscrowManagerTests { mService.prepareRebootEscrow(); clearInvocations(mRebootEscrow); - mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); verify(mockListener).onPreparedForReboot(eq(true)); assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); verify(mRebootEscrow, never()).storeKey(any()); diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 49ad58550db8..7c60f81259c7 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -82,7 +82,7 @@ import java.util.concurrent.ConcurrentHashMap; * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no * longer used and associated resources may be recovered. * <p> - * Subclasses of {@code Connection} override the {@code on*} methods to provide the the + * Subclasses of {@code Connection} override the {@code on*} methods to provide the * {@link ConnectionService}'s implementation of calling functionality. The {@code on*} methods are * called by Telecom to inform an instance of a {@code Connection} of actions specific to that * {@code Connection} instance. diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 6fe9bf97c5c3..ac740166a024 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -1207,13 +1207,8 @@ public class ServiceState implements Parcelable { /** * Initialize the service state. Set everything to the default value. - * - * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is - * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device - * is on AP-assisted mode, where IWLAN should be reported through WLAN. - * {@link NetworkRegistrationInfo}. */ - private void init(boolean legacyMode) { + private void init() { if (DBG) Rlog.d(LOG_TAG, "init"); mVoiceRegState = STATE_OUT_OF_SERVICE; mDataRegState = STATE_OUT_OF_SERVICE; @@ -1245,13 +1240,11 @@ public class ServiceState implements Parcelable { .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN) .build()); - if (!legacyMode) { - addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN) - .build()); - } + addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN) + .build()); } mOperatorAlphaLongRaw = null; mOperatorAlphaShortRaw = null; @@ -1260,11 +1253,11 @@ public class ServiceState implements Parcelable { } public void setStateOutOfService() { - init(true); + init(); } public void setStateOff() { - init(true); + init(); mVoiceRegState = STATE_POWER_OFF; mDataRegState = STATE_POWER_OFF; } @@ -1272,14 +1265,11 @@ public class ServiceState implements Parcelable { /** * Set the service state to out-of-service * - * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is - * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device - * is on AP-assisted mode, where IWLAN should be reported through WLAN. * @param powerOff {@code true} if this is a power off case (i.e. Airplane mode on). * @hide */ - public void setOutOfService(boolean legacyMode, boolean powerOff) { - init(legacyMode); + public void setOutOfService(boolean powerOff) { + init(); if (powerOff) { mVoiceRegState = STATE_POWER_OFF; mDataRegState = STATE_POWER_OFF; diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 59b822ebecbf..46cf979fa8e3 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2586,18 +2586,41 @@ public class SubscriptionManager { } /** - * Set a field in the subscription database. Note not all fields are supported. + * Returns a constant indicating the state of sim for the slot index. * - * @param subscriptionId Subscription Id of Subscription. - * @param columnName Column name in the database. Note not all fields are supported. - * @param value Value to store in the database. + * @param slotIndex * - * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not - * exposed. - * @throws SecurityException if callers do not hold the required permission. - * - * @see android.provider.Telephony.SimInfo for all the columns. + * {@See TelephonyManager#SIM_STATE_UNKNOWN} + * {@See TelephonyManager#SIM_STATE_ABSENT} + * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED} + * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED} + * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED} + * {@See TelephonyManager#SIM_STATE_READY} + * {@See TelephonyManager#SIM_STATE_NOT_READY} + * {@See TelephonyManager#SIM_STATE_PERM_DISABLED} + * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} * + * {@hide} + */ + public static int getSimStateForSlotIndex(int slotIndex) { + int simState = TelephonyManager.SIM_STATE_UNKNOWN; + + try { + ISub iSub = TelephonyManager.getSubscriptionService(); + if (iSub != null) { + simState = iSub.getSimStateForSlotIndex(slotIndex); + } + } catch (RemoteException ex) { + } + + return simState; + } + + /** + * Store properties associated with SubscriptionInfo in database + * @param subId Subscription Id of Subscription + * @param propKey Column name in database associated with SubscriptionInfo + * @param propValue Value to store in DB for particular subId & column name * @hide */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 9d418e144f4c..7a19d36ba743 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -3504,7 +3504,7 @@ public class TelephonyManager { "state as absent"); return SIM_STATE_ABSENT; } - return getSimStateForSlotIndex(slotIndex); + return SubscriptionManager.getSimStateForSlotIndex(slotIndex); } /** @@ -3651,7 +3651,9 @@ public class TelephonyManager { @Deprecated public @SimState int getSimApplicationState(int physicalSlotIndex) { int activePort = getFirstActivePortIndex(physicalSlotIndex); - int simState = getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex, activePort)); + int simState = + SubscriptionManager.getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex, + activePort)); return getSimApplicationStateFromSimState(simState); } @@ -3677,7 +3679,9 @@ public class TelephonyManager { @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @SimState int getSimApplicationState(int physicalSlotIndex, int portIndex) { - int simState = getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex, portIndex)); + int simState = + SubscriptionManager.getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex, + portIndex)); return getSimApplicationStateFromSimState(simState); } @@ -3746,7 +3750,7 @@ public class TelephonyManager { */ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @SimState int getSimState(int slotIndex) { - int simState = getSimStateForSlotIndex(slotIndex); + int simState = SubscriptionManager.getSimStateForSlotIndex(slotIndex); if (simState == SIM_STATE_LOADED) { simState = SIM_STATE_READY; } @@ -17002,30 +17006,4 @@ public class TelephonyManager { } return false; } - - /** - * Returns a constant indicating the state of sim for the slot index. - * - * @param slotIndex Logical SIM slot index. - * - * @see TelephonyManager.SimState - * - * @hide - */ - @SimState - public static int getSimStateForSlotIndex(int slotIndex) { - try { - ITelephony telephony = ITelephony.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getTelephonyServiceRegisterer() - .get()); - if (telephony != null) { - return telephony.getSimStateForSlotIndex(slotIndex); - } - } catch (RemoteException e) { - Log.e(TAG, "Error in getSimStateForSlotIndex: " + e); - } - return TelephonyManager.SIM_STATE_UNKNOWN; - } } diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index c5f6902062ff..2cf5e67ad287 100644 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -272,6 +272,11 @@ interface ISub { boolean isSubscriptionEnabled(int subId); int getEnabledSubscriptionId(int slotIndex); + /** + * Get the SIM state for the slot index + * @return SIM state as the ordinal of IccCardConstants.State + */ + int getSimStateForSlotIndex(int slotIndex); boolean isActiveSubId(int subId, String callingPackage, String callingFeatureId); diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index ecafe702ea4e..da1ffcdea812 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2564,11 +2564,4 @@ interface ITelephony { * @hide */ boolean isRemovableEsimDefaultEuicc(String callingPackage); - - /** - * Get the SIM state for the logical SIM slot index. - * - * @param slotIndex Logical SIM slot index. - */ - int getSimStateForSlotIndex(int slotIndex); } diff --git a/tests/EnforcePermission/Android.bp b/tests/EnforcePermission/Android.bp new file mode 100644 index 000000000000..719a89817a9d --- /dev/null +++ b/tests/EnforcePermission/Android.bp @@ -0,0 +1,22 @@ +// Copyright (C) 2023 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 { + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "frameworks-enforce-permission-test-aidl", + srcs: ["aidl/**/*.aidl"], +} diff --git a/tests/EnforcePermission/aidl/android/tests/enforcepermission/INested.aidl b/tests/EnforcePermission/aidl/android/tests/enforcepermission/INested.aidl new file mode 100644 index 000000000000..1eb773dc19b8 --- /dev/null +++ b/tests/EnforcePermission/aidl/android/tests/enforcepermission/INested.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 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.tests.enforcepermission; + +interface INested { + @EnforcePermission("ACCESS_NETWORK_STATE") + void ProtectedByAccessNetworkState(); + + @EnforcePermission("READ_SYNC_SETTINGS") + void ProtectedByReadSyncSettings(); +} diff --git a/tests/EnforcePermission/aidl/android/tests/enforcepermission/IProtected.aidl b/tests/EnforcePermission/aidl/android/tests/enforcepermission/IProtected.aidl new file mode 100644 index 000000000000..18e3aecfa832 --- /dev/null +++ b/tests/EnforcePermission/aidl/android/tests/enforcepermission/IProtected.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 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.tests.enforcepermission; + +interface IProtected { + @EnforcePermission("INTERNET") + void ProtectedByInternet(); + + @EnforcePermission("VIBRATE") + void ProtectedByVibrate(); + + @EnforcePermission("INTERNET") + void ProtectedByInternetAndVibrateImplicitly(); + + @EnforcePermission("INTERNET") + void ProtectedByInternetAndAccessNetworkStateImplicitly(); + + @EnforcePermission("INTERNET") + void ProtectedByInternetAndReadSyncSettingsImplicitly(); +} diff --git a/tests/EnforcePermission/service-app/Android.bp b/tests/EnforcePermission/service-app/Android.bp new file mode 100644 index 000000000000..a4ac1d7c6134 --- /dev/null +++ b/tests/EnforcePermission/service-app/Android.bp @@ -0,0 +1,32 @@ +// Copyright (C) 2023 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test_helper_app { + name: "EnforcePermissionTestHelper", + srcs: [ + "src/**/*.java", + ":frameworks-enforce-permission-test-aidl", + ], + platform_apis: true, + certificate: "platform", +} diff --git a/tests/EnforcePermission/service-app/AndroidManifest.xml b/tests/EnforcePermission/service-app/AndroidManifest.xml new file mode 100644 index 000000000000..ddafe15ab88f --- /dev/null +++ b/tests/EnforcePermission/service-app/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.tests.enforcepermission.service"> + <application> + <service + android:name=".TestService" + android:exported="true" /> + + <service + android:name=".NestedTestService" + android:exported="true" /> + </application> +</manifest> diff --git a/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/NestedTestService.java b/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/NestedTestService.java new file mode 100644 index 000000000000..7879a1214c01 --- /dev/null +++ b/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/NestedTestService.java @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2023 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.tests.enforcepermission.service; + +import android.annotation.EnforcePermission; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.tests.enforcepermission.INested; +import android.util.Log; + +public class NestedTestService extends Service { + private static final String TAG = "EnforcePermission.NestedTestService"; + + @Override + public IBinder onBind(Intent intent) { + Log.i(TAG, "onBind"); + return mBinder; + } + + private final INested.Stub mBinder = new INested.Stub() { + @Override + @EnforcePermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public void ProtectedByAccessNetworkState() { + ProtectedByAccessNetworkState_enforcePermission(); + } + + @Override + @EnforcePermission(android.Manifest.permission.READ_SYNC_SETTINGS) + public void ProtectedByReadSyncSettings() { + ProtectedByReadSyncSettings_enforcePermission(); + } + }; +} diff --git a/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/TestService.java b/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/TestService.java new file mode 100644 index 000000000000..e9b897db1294 --- /dev/null +++ b/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/TestService.java @@ -0,0 +1,119 @@ +/** + * Copyright (C) 2023 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.tests.enforcepermission.service; + +import android.annotation.EnforcePermission; +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.os.RemoteException; +import android.tests.enforcepermission.INested; +import android.tests.enforcepermission.IProtected; +import android.util.Log; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class TestService extends Service { + + private static final String TAG = "EnforcePermission.TestService"; + private volatile ServiceConnection mNestedServiceConnection; + + @Override + public void onCreate() { + mNestedServiceConnection = new ServiceConnection(); + Intent intent = new Intent(this, NestedTestService.class); + boolean bound = bindService(intent, mNestedServiceConnection, Context.BIND_AUTO_CREATE); + if (!bound) { + Log.wtf(TAG, "bindService() on NestedTestService failed"); + } + } + + @Override + public void onDestroy() { + unbindService(mNestedServiceConnection); + } + + private static final class ServiceConnection implements android.content.ServiceConnection { + private volatile CompletableFuture<INested> mFuture = new CompletableFuture<>(); + + public INested get() { + try { + return mFuture.get(1, TimeUnit.SECONDS); + } catch (ExecutionException | InterruptedException | TimeoutException e) { + throw new RuntimeException("Unable to reach NestedTestService: " + e.getMessage()); + } + } + + public void onServiceConnected(ComponentName className, IBinder service) { + mFuture.complete(INested.Stub.asInterface(service)); + } + + public void onServiceDisconnected(ComponentName className) { + mFuture = new CompletableFuture<>(); + } + }; + + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + private final IProtected.Stub mBinder = new IProtected.Stub() { + @Override + @EnforcePermission(android.Manifest.permission.INTERNET) + public void ProtectedByInternet() { + ProtectedByInternet_enforcePermission(); + } + + @Override + @EnforcePermission(android.Manifest.permission.VIBRATE) + public void ProtectedByVibrate() { + ProtectedByVibrate_enforcePermission(); + } + + @Override + @EnforcePermission(android.Manifest.permission.INTERNET) + public void ProtectedByInternetAndVibrateImplicitly() { + ProtectedByInternetAndVibrateImplicitly_enforcePermission(); + + ProtectedByVibrate(); + } + + @Override + @EnforcePermission(android.Manifest.permission.INTERNET) + public void ProtectedByInternetAndAccessNetworkStateImplicitly() throws RemoteException { + ProtectedByInternetAndAccessNetworkStateImplicitly_enforcePermission(); + + mNestedServiceConnection.get().ProtectedByAccessNetworkState(); + + } + + @Override + @EnforcePermission(android.Manifest.permission.INTERNET) + public void ProtectedByInternetAndReadSyncSettingsImplicitly() throws RemoteException { + ProtectedByInternetAndReadSyncSettingsImplicitly_enforcePermission(); + + mNestedServiceConnection.get().ProtectedByReadSyncSettings(); + } + }; +} diff --git a/tests/EnforcePermission/test-app/Android.bp b/tests/EnforcePermission/test-app/Android.bp new file mode 100644 index 000000000000..305ed8f0dadc --- /dev/null +++ b/tests/EnforcePermission/test-app/Android.bp @@ -0,0 +1,38 @@ +// Copyright (C) 2023 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 { + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "EnforcePermissionTests", + srcs: [ + "src/**/*.java", + ":frameworks-enforce-permission-test-aidl", + ], + static_libs: [ + "androidx.test.rules", + ], + libs: [ + "android.test.base", + "android.test.runner", + ], + data: [ + ":EnforcePermissionTestHelper", + ], + platform_apis: true, + certificate: "platform", + test_suites: ["general-tests"], +} diff --git a/tests/EnforcePermission/test-app/AndroidManifest.xml b/tests/EnforcePermission/test-app/AndroidManifest.xml new file mode 100644 index 000000000000..4a0c6a86628f --- /dev/null +++ b/tests/EnforcePermission/test-app/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.tests.enforcepermission.tests"> + + <!-- Expected for the tests (not actually used) --> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> + + <queries> + <package android:name="android.tests.enforcepermission.service" /> + </queries> + + <application> + <uses-library android:name="android.test.runner" /> + </application> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.tests.enforcepermission.tests"/> +</manifest> diff --git a/tests/EnforcePermission/test-app/AndroidTest.xml b/tests/EnforcePermission/test-app/AndroidTest.xml new file mode 100644 index 000000000000..120381a7fb83 --- /dev/null +++ b/tests/EnforcePermission/test-app/AndroidTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 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. +--> +<configuration description="Runs EnforcePermission End-to-End Tests"> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="EnforcePermissionTestHelper.apk"/> + <option name="test-file-name" value="EnforcePermissionTests.apk"/> + <option name="cleanup-apks" value="true" /> + </target_preparer> + + <option name="test-tag" value="EnforcePermissionTests"/> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="android.tests.enforcepermission.tests"/> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/> + </test> +</configuration> diff --git a/tests/EnforcePermission/test-app/src/android/tests/enforcepermission/tests/ServiceTest.java b/tests/EnforcePermission/test-app/src/android/tests/enforcepermission/tests/ServiceTest.java new file mode 100644 index 000000000000..d2a4a037f125 --- /dev/null +++ b/tests/EnforcePermission/test-app/src/android/tests/enforcepermission/tests/ServiceTest.java @@ -0,0 +1,129 @@ +/** + * Copyright (C) 2023 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.tests.enforcepermission.tests; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.tests.enforcepermission.IProtected; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +@RunWith(AndroidJUnit4.class) +public class ServiceTest { + + private static final String TAG = "EnforcePermission.Tests"; + private static final String SERVICE_NAME = "android.tests.enforcepermission.service"; + private static final int SERVICE_TIMEOUT_SEC = 5; + + private Context mContext; + private volatile ServiceConnection mServiceConnection; + + @Before + public void bindTestService() throws Exception { + Log.d(TAG, "bindTestService"); + mContext = InstrumentationRegistry.getTargetContext(); + mServiceConnection = new ServiceConnection(); + Intent intent = new Intent(); + intent.setClassName(SERVICE_NAME, SERVICE_NAME + ".TestService"); + assertTrue(mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)); + } + + @After + public void unbindTestService() throws Exception { + mContext.unbindService(mServiceConnection); + } + + private static final class ServiceConnection implements android.content.ServiceConnection { + private volatile CompletableFuture<IProtected> mFuture = new CompletableFuture<>(); + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + mFuture.complete(IProtected.Stub.asInterface(service)); + } + + @Override + public void onServiceDisconnected(ComponentName className) { + mFuture = new CompletableFuture<>(); + } + + public IProtected get() { + try { + return mFuture.get(SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS); + } catch (ExecutionException | InterruptedException | TimeoutException e) { + throw new RuntimeException("Unable to reach TestService: " + e.toString()); + } + } + } + + @Test + public void testImmediatePermissionGranted_succeeds() + throws RemoteException { + mServiceConnection.get().ProtectedByInternet(); + } + + @Test + public void testImmediatePermissionNotGranted_fails() + throws RemoteException { + final Exception ex = assertThrows(SecurityException.class, + () -> mServiceConnection.get().ProtectedByVibrate()); + assertThat(ex.getMessage(), containsString("VIBRATE")); + } + + @Test + public void testImmediatePermissionGrantedButImplicitLocalNotGranted_fails() + throws RemoteException { + final Exception ex = assertThrows(SecurityException.class, + () -> mServiceConnection.get().ProtectedByInternetAndVibrateImplicitly()); + assertThat(ex.getMessage(), containsString("VIBRATE")); + } + + @Test + public void testImmediatePermissionGrantedButImplicitNestedNotGranted_fails() + throws RemoteException { + final Exception ex = assertThrows(SecurityException.class, + () -> mServiceConnection.get() + .ProtectedByInternetAndAccessNetworkStateImplicitly()); + assertThat(ex.getMessage(), containsString("ACCESS_NETWORK_STATE")); + } + + @Test + public void testImmediatePermissionGrantedAndImplicitNestedGranted_succeeds() + throws RemoteException { + mServiceConnection.get().ProtectedByInternetAndReadSyncSettingsImplicitly(); + } +} |