1 /* 2 * Copyright (C) 2015 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 package com.android.cts.deviceowner; 17 18 19 import android.app.admin.DevicePolicyManager; 20 import android.app.admin.FreezePeriod; 21 import android.app.admin.SystemUpdatePolicy; 22 import android.app.admin.SystemUpdatePolicy.ValidationFailedException; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.icu.util.Calendar; 28 import android.provider.Settings; 29 import android.provider.Settings.Global; 30 import android.util.Pair; 31 32 import java.time.LocalDate; 33 import java.time.MonthDay; 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.concurrent.Semaphore; 37 import java.util.concurrent.TimeUnit; 38 39 /** 40 * Test {@link SystemUpdatePolicy}, {@link DevicePolicyManager#setSystemUpdatePolicy} and 41 * {@link DevicePolicyManager#getSystemUpdatePolicy} 42 */ 43 public class SystemUpdatePolicyTest extends BaseDeviceOwnerTest { 44 45 private static final int TIMEOUT_MS = 20_000; 46 47 private final Semaphore mPolicyChangedSemaphore = new Semaphore(0); 48 private final Semaphore mTimeChangedSemaphore = new Semaphore(0); 49 private final BroadcastReceiver policyChangedReceiver = new BroadcastReceiver() { 50 @Override 51 public void onReceive(Context context, Intent intent) { 52 final String action = intent.getAction(); 53 if (DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED.equals(action)) { 54 mPolicyChangedSemaphore.release(); 55 } else if (Intent.ACTION_TIME_CHANGED.equals(action)) { 56 mTimeChangedSemaphore.release(); 57 } 58 } 59 }; 60 61 private int mSavedAutoTimeConfig; 62 private LocalDate mSavedSystemDate; 63 private boolean mRestoreDate; 64 65 @Override setUp()66 protected void setUp() throws Exception { 67 super.setUp(); 68 IntentFilter filter = new IntentFilter(); 69 filter.addAction(DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED); 70 filter.addAction(Intent.ACTION_TIME_CHANGED); 71 mContext.registerReceiver(policyChangedReceiver, filter); 72 clearFreezeRecord(); 73 mSavedAutoTimeConfig = Settings.Global.getInt(mContext.getContentResolver(), 74 Global.AUTO_TIME, 0); 75 executeShellCommand("settings put global auto_time 0"); 76 mSavedSystemDate = LocalDate.now(); 77 mRestoreDate = false; 78 } 79 80 @Override tearDown()81 protected void tearDown() throws Exception { 82 mDevicePolicyManager.setSystemUpdatePolicy(getWho(), null); 83 clearFreezeRecord(); 84 if (mRestoreDate) { 85 setSystemDate(mSavedSystemDate); 86 } 87 executeShellCommand("settings put global auto_time", 88 Integer.toString(mSavedAutoTimeConfig)); 89 // This needs to happen last since setSystemDate() relies on the receiver for 90 // synchronization. 91 mContext.unregisterReceiver(policyChangedReceiver); 92 super.tearDown(); 93 } 94 testSetEmptytInstallPolicy()95 public void testSetEmptytInstallPolicy() { 96 testPolicy(null); 97 } 98 testSetAutomaticInstallPolicy()99 public void testSetAutomaticInstallPolicy() { 100 testPolicy(SystemUpdatePolicy.createAutomaticInstallPolicy()); 101 } 102 testSetWindowedInstallPolicy()103 public void testSetWindowedInstallPolicy() { 104 testPolicy(SystemUpdatePolicy.createWindowedInstallPolicy(0, 720)); 105 } 106 testSetPostponeInstallPolicy()107 public void testSetPostponeInstallPolicy() { 108 testPolicy(SystemUpdatePolicy.createPostponeInstallPolicy()); 109 } 110 testShouldFailInvalidWindowPolicy()111 public void testShouldFailInvalidWindowPolicy() throws Exception { 112 try { 113 SystemUpdatePolicy.createWindowedInstallPolicy(24 * 60 + 1, 720); 114 fail("Invalid window start should not be accepted."); 115 } catch (IllegalArgumentException expected) { } 116 try { 117 SystemUpdatePolicy.createWindowedInstallPolicy(-1, 720); 118 fail("Invalid window start should not be accepted."); 119 } catch (IllegalArgumentException expected) { } 120 try { 121 SystemUpdatePolicy.createWindowedInstallPolicy(0, 24 * 60 + 1); 122 fail("Invalid window end should not be accepted."); 123 } catch (IllegalArgumentException expected) { } 124 try { 125 SystemUpdatePolicy.createWindowedInstallPolicy(0, -1); 126 fail("Invalid window end should not be accepted."); 127 } catch (IllegalArgumentException expected) { } 128 } 129 testFreezePeriodValidation()130 public void testFreezePeriodValidation() { 131 // Dates are in MM-DD format 132 validateFreezePeriodsSucceeds("01-01", "01-02"); 133 validateFreezePeriodsSucceeds("01-31", "01-31"); 134 validateFreezePeriodsSucceeds("11-01", "01-15"); 135 validateFreezePeriodsSucceeds("02-01", "02-29"); 136 validateFreezePeriodsSucceeds("03-01", "03-31", "09-01", "09-30"); 137 validateFreezePeriodsSucceeds("10-01", "10-31", "12-31", "01-31"); 138 validateFreezePeriodsSucceeds("01-01", "02-28", "05-01", "06-30", "09-01", "10-31"); 139 validateFreezePeriodsSucceeds("11-02", "01-15", "03-18", "04-30", "08-01", "08-30"); 140 141 // full overlap 142 validateFreezePeriodsFailsOverlap("12-01", "01-31", "12-25", "01-15"); 143 // partial overlap 144 validateFreezePeriodsFailsOverlap("03-01", "03-31", "03-15", "01-01"); 145 // touching interval 146 validateFreezePeriodsFailsOverlap("01-31", "01-31", "02-01", "02-01"); 147 validateFreezePeriodsFailsOverlap("12-01", "12-31", "04-01", "04-01", "01-01", "01-30"); 148 149 // entire year 150 validateFreezePeriodsFailsTooLong("01-01", "12-31"); 151 // Regular long period 152 validateFreezePeriodsSucceeds("01-01", "03-31", "06-01", "08-29"); 153 validateFreezePeriodsFailsTooLong("01-01", "03-31", "06-01", "08-30"); 154 // long period spanning across year end 155 validateFreezePeriodsSucceeds("11-01", "01-29"); 156 validateFreezePeriodsFailsTooLong("11-01", "01-30"); 157 // Leap year handling 158 validateFreezePeriodsSucceeds("12-01", "02-28"); 159 validateFreezePeriodsFailsTooLong("12-01", "03-01"); 160 161 // Regular short separation 162 validateFreezePeriodsFailsTooClose( "01-01", "01-01", "01-03", "01-03"); 163 // Short interval spans across end of year 164 validateFreezePeriodsSucceeds("01-31", "03-01", "11-01", "12-01"); 165 validateFreezePeriodsFailsTooClose("01-30", "03-01", "11-01", "12-01"); 166 // Short separation is after wrapped period 167 validateFreezePeriodsSucceeds("03-03", "03-31", "12-31", "01-01"); 168 validateFreezePeriodsFailsTooClose("03-02", "03-31", "12-31", "01-01"); 169 // Short separation including Feb 29 170 validateFreezePeriodsSucceeds("12-01", "01-15", "03-17", "04-01"); 171 validateFreezePeriodsFailsTooClose("12-01", "01-15", "03-16", "04-01"); 172 // Short separation including Feb 29 173 validateFreezePeriodsSucceeds("01-01", "02-28", "04-30", "06-01"); 174 validateFreezePeriodsSucceeds("01-01", "02-29", "04-30", "06-01"); 175 validateFreezePeriodsFailsTooClose("01-01", "03-01", "04-30", "06-01"); 176 } 177 testFreezePeriodCanBeSetAndChanged()178 public void testFreezePeriodCanBeSetAndChanged() throws Exception { 179 setPolicyWithFreezePeriod("11-02", "01-15", "03-18", "04-30"); 180 // Set to a different period should work 181 setPolicyWithFreezePeriod("08-01", "08-30"); 182 // Clear freeze period should work 183 setPolicyWithFreezePeriod(); 184 // Set to the original period should work 185 setPolicyWithFreezePeriod("11-02", "01-15", "03-18", "04-30"); 186 } 187 testFreezePeriodCannotSetIfTooCloseToPrevious()188 public void testFreezePeriodCannotSetIfTooCloseToPrevious() throws Exception { 189 setSystemDate(LocalDate.of(2018, 2, 28)); 190 setPolicyWithFreezePeriod("01-01", "03-01", "06-01", "06-30"); 191 // Clear policy 192 mDevicePolicyManager.setSystemUpdatePolicy(getWho(), null); 193 // Set to a conflict period (too close with previous period [2-28, 2-28]) should fail, 194 // despite the previous policy was cleared from the system just now. 195 try { 196 setPolicyWithFreezePeriod("04-29", "04-30"); 197 fail("Did no flag invalid period"); 198 } catch (ValidationFailedException e) { 199 assertEquals(e.getMessage(), 200 ValidationFailedException.ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE, 201 e.getErrorCode()); 202 } 203 // This should succeed as the new freeze period is exactly 60 days away. 204 setPolicyWithFreezePeriod("04-30", "04-30"); 205 } 206 testFreezePeriodCannotSetIfTooLongWhenCombinedWithPrevious()207 public void testFreezePeriodCannotSetIfTooLongWhenCombinedWithPrevious() throws Exception { 208 setSystemDate(LocalDate.of(2012, 4, 1)); 209 setPolicyWithFreezePeriod("03-01", "05-01"); 210 setSystemDate(LocalDate.of(2012, 4, 30)); 211 // Despite the wait for broadcast in setSystemDate(), TIME_CHANGED broadcast is asynchronous 212 // so give DevicePolicyManagerService more time to receive TIME_CHANGED and to update the 213 // freeze period record. 214 Thread.sleep(5000); 215 // Set to a conflict period (too long when combined with previous period [04-01, 04-30]) 216 // should fail 217 try { 218 setPolicyWithFreezePeriod("04-30", "06-30"); 219 fail("Did no flag invalid period"); 220 } catch (SystemUpdatePolicy.ValidationFailedException e) { 221 assertEquals(e.getMessage(), 222 ValidationFailedException.ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG, 223 e.getErrorCode()); 224 } 225 // This should succeed as the combined length (59 days) is just below threshold (90 days). 226 setPolicyWithFreezePeriod("05-01", "06-29"); 227 } 228 testFreezePeriodForOneYear()229 public void testFreezePeriodForOneYear() throws Exception { 230 // Set a normal period every day for 365 days 231 for (int i = 1; i <= 365; i++) { 232 // Add two days so the test date range wraps around year-end 233 setSystemDate(LocalDate.ofYearDay(2019, i).plusDays(2)); 234 testFreezePeriodCanBeSetAndChanged(); 235 } 236 } 237 testPolicy(SystemUpdatePolicy policy)238 private void testPolicy(SystemUpdatePolicy policy) { 239 mDevicePolicyManager.setSystemUpdatePolicy(getWho(), policy); 240 waitForPolicyChangedBroadcast(); 241 SystemUpdatePolicy newPolicy = mDevicePolicyManager.getSystemUpdatePolicy(); 242 if (policy == null) { 243 assertNull(newPolicy); 244 } else { 245 assertNotNull(newPolicy); 246 assertEquals(policy.toString(), newPolicy.toString()); 247 assertEquals(policy.getPolicyType(), newPolicy.getPolicyType()); 248 if (policy.getPolicyType() == SystemUpdatePolicy.TYPE_INSTALL_WINDOWED) { 249 assertEquals(policy.getInstallWindowStart(), newPolicy.getInstallWindowStart()); 250 assertEquals(policy.getInstallWindowEnd(), newPolicy.getInstallWindowEnd()); 251 } 252 } 253 } 254 setPolicyWithFreezePeriod(String...dates)255 private void setPolicyWithFreezePeriod(String...dates) { 256 SystemUpdatePolicy policy = SystemUpdatePolicy.createPostponeInstallPolicy(); 257 setFreezePeriods(policy, dates); 258 mDevicePolicyManager.setSystemUpdatePolicy(getWho(), policy); 259 260 List<FreezePeriod> loadedFreezePeriods = mDevicePolicyManager 261 .getSystemUpdatePolicy().getFreezePeriods(); 262 assertEquals(dates.length / 2, loadedFreezePeriods.size()); 263 for (int i = 0; i < dates.length; i += 2) { 264 assertEquals(parseMonthDay(dates[i]), loadedFreezePeriods.get(i / 2).getStart()); 265 assertEquals(parseMonthDay(dates[i + 1]), loadedFreezePeriods.get(i / 2).getEnd()); 266 } 267 } 268 validateFreezePeriodsSucceeds(String...dates)269 private void validateFreezePeriodsSucceeds(String...dates) { 270 SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); 271 setFreezePeriods(p, dates); 272 } 273 validateFreezePeriodsFails(int errorCode, String... dates)274 private void validateFreezePeriodsFails(int errorCode, String... dates) { 275 SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); 276 try { 277 setFreezePeriods(p, dates); 278 fail("Exception not thrown for dates: " + String.join(" ", dates)); 279 } catch (SystemUpdatePolicy.ValidationFailedException e) { 280 assertEquals("Exception not expected: " + e.getMessage(), 281 errorCode,e.getErrorCode()); 282 } 283 } 284 validateFreezePeriodsFailsOverlap(String... dates)285 private void validateFreezePeriodsFailsOverlap(String... dates) { 286 validateFreezePeriodsFails(ValidationFailedException.ERROR_DUPLICATE_OR_OVERLAP, dates); 287 } 288 validateFreezePeriodsFailsTooLong(String... dates)289 private void validateFreezePeriodsFailsTooLong(String... dates) { 290 validateFreezePeriodsFails(ValidationFailedException.ERROR_NEW_FREEZE_PERIOD_TOO_LONG, 291 dates); 292 } 293 validateFreezePeriodsFailsTooClose(String... dates)294 private void validateFreezePeriodsFailsTooClose(String... dates) { 295 validateFreezePeriodsFails(ValidationFailedException.ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE, 296 dates); 297 } 298 299 //dates are in MM-DD format setFreezePeriods(SystemUpdatePolicy policy, String... dates)300 private void setFreezePeriods(SystemUpdatePolicy policy, String... dates) { 301 List<FreezePeriod> periods = new ArrayList<>(); 302 for (int i = 0; i < dates.length; i+= 2) { 303 periods.add(new FreezePeriod(parseMonthDay(dates[i]), parseMonthDay(dates[i + 1]))); 304 } 305 policy.setFreezePeriods(periods); 306 } 307 parseMonthDay(String date)308 private MonthDay parseMonthDay(String date) { 309 return MonthDay.of(Integer.parseInt(date.substring(0, 2)), 310 Integer.parseInt(date.substring(3, 5))); 311 } 312 clearFreezeRecord()313 private void clearFreezeRecord() throws Exception { 314 executeShellCommand("dpm", "clear-freeze-period-record"); 315 } 316 setSystemDate(LocalDate date)317 private void setSystemDate(LocalDate date) throws Exception { 318 mRestoreDate = true; 319 Calendar c = Calendar.getInstance(); 320 c.set(Calendar.YEAR, date.getYear()); 321 c.set(Calendar.MONTH, date.getMonthValue() - 1); 322 c.set(Calendar.DAY_OF_MONTH, date.getDayOfMonth()); 323 mDevicePolicyManager.setTime(getWho(), c.getTimeInMillis()); 324 waitForTimeChangedBroadcast(); 325 } 326 waitForPolicyChangedBroadcast()327 private void waitForPolicyChangedBroadcast() { 328 try { 329 assertTrue("Timeout while waiting for broadcast.", 330 mPolicyChangedSemaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 331 } catch (InterruptedException e) { 332 fail("Interrupted while waiting for broadcast."); 333 } 334 } 335 waitForTimeChangedBroadcast()336 private void waitForTimeChangedBroadcast() { 337 try { 338 assertTrue("Timeout while waiting for broadcast.", 339 mTimeChangedSemaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 340 } catch (InterruptedException e) { 341 fail("Interrupted while waiting for broadcast."); 342 } 343 } 344 } 345