1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.app.cts.broadcasts; 18 19 import static org.junit.Assert.assertTrue; 20 import static org.junit.Assume.assumeTrue; 21 22 import android.app.BroadcastOptions; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.os.Bundle; 26 import android.os.SystemClock; 27 import android.provider.DeviceConfig; 28 29 import androidx.test.filters.FlakyTest; 30 31 import com.android.app.cts.broadcasts.ICommandReceiver; 32 import com.android.compatibility.common.util.AmUtils; 33 import com.android.compatibility.common.util.DeviceConfigStateChangerRule; 34 35 import org.junit.ClassRule; 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 39 import java.util.List; 40 41 @FlakyTest(bugId = 288323707) 42 @RunWith(BroadcastsTestRunner.class) 43 public class BroadcastDeferralTest extends BaseBroadcastTest { 44 45 @ClassRule 46 public static final DeviceConfigStateChangerRule sFreezerTimeoutRule = 47 new DeviceConfigStateChangerRule(getContext(), 48 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 49 KEY_FREEZE_DEBOUNCE_TIMEOUT, 50 String.valueOf(SHORT_FREEZER_TIMEOUT_MS)); 51 52 @Test testFgBroadcastDeliveryToFrozenApp_withDeferUntilActive()53 public void testFgBroadcastDeliveryToFrozenApp_withDeferUntilActive() throws Exception { 54 assumeTrue(isAppFreezerEnabled()); 55 56 final TestServiceConnection connection1 = bindToHelperService(HELPER_PKG1); 57 try { 58 final Intent intent = new Intent(TEST_ACTION1) 59 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 60 .putExtra(TEST_EXTRA1, TEST_VALUE1) 61 .setPackage(HELPER_PKG2); 62 final Bundle options = BroadcastOptions.makeBasic() 63 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) 64 .toBundle(); 65 int testPid = -1; 66 TestServiceConnection connection2 = bindToHelperService(HELPER_PKG2); 67 ICommandReceiver cmdReceiver1; 68 ICommandReceiver cmdReceiver2; 69 try { 70 cmdReceiver1 = connection1.getCommandReceiver(); 71 cmdReceiver2 = connection2.getCommandReceiver(); 72 testPid = cmdReceiver2.getPid(); 73 final IntentFilter filter = new IntentFilter(TEST_ACTION1); 74 cmdReceiver2.clearCookie(TEST_ACTION1); 75 cmdReceiver2.monitorBroadcasts(filter, TEST_ACTION1); 76 77 cmdReceiver1.sendBroadcast(intent, options); 78 verifyReceivedBroadcasts(cmdReceiver2, TEST_ACTION1, 79 List.of(intent), true, null); 80 cmdReceiver2.clearCookie(TEST_ACTION1); 81 } finally { 82 connection2.unbind(); 83 } 84 85 // Verify the test app process is frozen 86 waitForProcessFreeze(testPid, SHORT_FREEZER_TIMEOUT_MS * 2); 87 cmdReceiver1.sendBroadcast(intent, options); 88 89 // Flush all broadcasts but broadcast to the frozen shouldn't be delivered, so 90 // verify that test process is still frozen. 91 AmUtils.waitForBroadcastBarrier(); 92 assertTrue("Process should still be frozen; pid=" + testPid, isProcessFrozen(testPid)); 93 94 final long timestampMs = SystemClock.elapsedRealtime(); 95 connection2 = bindToHelperService(HELPER_PKG2); 96 try { 97 cmdReceiver2 = connection2.getCommandReceiver(); 98 99 // TODO: Add a UidImportanceListener to listen for cached state change 100 // as a proxy to know that BroadcastProcessQueue received that state change. 101 verifyReceivedBroadcasts(cmdReceiver2, TEST_ACTION1, 102 List.of(intent), true, 103 receipt -> { 104 if (receipt.timestampMs < timestampMs) { 105 return "Broadcast should have been received after service bind;" 106 + " receipt.timestampMs=" + receipt.timestampMs 107 + ", timestampMs=" + timestampMs; 108 } 109 return null; 110 }); 111 } finally { 112 connection2.unbind(); 113 } 114 } finally { 115 connection1.unbind(); 116 } 117 } 118 119 @Test testFgBroadcastDeliveryToFrozenApp()120 public void testFgBroadcastDeliveryToFrozenApp() throws Exception { 121 assumeTrue(isAppFreezerEnabled()); 122 123 final TestServiceConnection connection1 = bindToHelperService(HELPER_PKG1); 124 ICommandReceiver cmdReceiver1; 125 ICommandReceiver cmdReceiver2; 126 try { 127 final Intent intent = new Intent(TEST_ACTION1) 128 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 129 .putExtra(TEST_EXTRA1, TEST_VALUE1) 130 .setPackage(HELPER_PKG2); 131 int testPid = -1; 132 TestServiceConnection connection2 = bindToHelperService(HELPER_PKG2); 133 try { 134 cmdReceiver1 = connection1.getCommandReceiver(); 135 cmdReceiver2 = connection2.getCommandReceiver(); 136 testPid = cmdReceiver2.getPid(); 137 final IntentFilter filter = new IntentFilter(TEST_ACTION1); 138 cmdReceiver2.clearCookie(TEST_ACTION1); 139 cmdReceiver2.monitorBroadcasts(filter, TEST_ACTION1); 140 } finally { 141 connection2.unbind(); 142 } 143 144 // Verify the test app process is frozen 145 waitForProcessFreeze(testPid, SHORT_FREEZER_TIMEOUT_MS * 2); 146 cmdReceiver1.sendBroadcast(intent, null); 147 148 // Flush all broadcasts and verify that the broadcast was delivered to the process 149 // before we bind to it. 150 AmUtils.waitForBroadcastBarrier(); 151 152 // Adding a small delay before binding to the service to give opportunity for the 153 // broadcast to be received. We can't use a finish callback or flush the application 154 // threads to ensure broadcast delivery is completed as that would interfere with 155 // what we are trying to verify. 156 SystemClock.sleep(100); 157 final long timestampMs = SystemClock.elapsedRealtime(); 158 connection2 = bindToHelperService(HELPER_PKG2); 159 try { 160 cmdReceiver2 = connection2.getCommandReceiver(); 161 162 verifyReceivedBroadcasts(cmdReceiver2, TEST_ACTION1, 163 List.of(intent), true, 164 receipt -> { 165 if (receipt.timestampMs > timestampMs) { 166 return "Broadcast should have been received before service bind;" 167 + " receipt.timestampMs=" + receipt.timestampMs 168 + ", timestampMs=" + timestampMs; 169 } 170 return null; 171 }); 172 } finally { 173 connection2.unbind(); 174 } 175 } finally { 176 connection1.unbind(); 177 } 178 } 179 } 180