• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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