1 /* 2 * Copyright (C) 2025 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.util; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.os.SystemProperties; 22 23 /** 24 * This class provides a single, static function to set a system property. The function retries on 25 * error. System properties should be reliable but there have been reports of failures in the set() 26 * command on lower-end devices. Clients may want to use this method instead of calling 27 * {@link SystemProperties.set} directly. 28 * @hide 29 */ 30 public class SystemPropertySetter { 31 32 /** 33 * The default retryDelayMs for {@link #setWithRetry}. This value has been found to give 34 * reasonable behavior in the field. 35 */ 36 public static final int PROPERTY_FAILURE_RETRY_DELAY_MILLIS = 200; 37 38 /** 39 * The default retryLimit for {@link #setWithRetry}. This value has been found to give 40 * reasonable behavior in the field. 41 */ 42 public static final int PROPERTY_FAILURE_RETRY_LIMIT = 5; 43 44 /** 45 * Set the value for the given {@code key} to {@code val}. This method retries using the 46 * standard parameters, above, if the native method throws a RuntimeException. 47 * 48 * @param key The name of the property to be set. 49 * @param val The new string value of the property. 50 * @throws IllegalArgumentException for non read-only properties if the {@code val} exceeds 51 * 91 characters. 52 * @throws RuntimeException if the property cannot be set, for example, if it was blocked by 53 * SELinux. libc will log the underlying reason. 54 */ setWithRetry(@onNull String key, @Nullable String val)55 public static void setWithRetry(@NonNull String key, @Nullable String val) { 56 setWithRetry(key, val,PROPERTY_FAILURE_RETRY_DELAY_MILLIS, PROPERTY_FAILURE_RETRY_LIMIT); 57 } 58 59 /** 60 * Set the value for the given {@code key} to {@code val}. This method retries if the native 61 * method throws a RuntimeException. If the {@code maxRetry} count is exceeded, the method 62 * throws the first RuntimeException that was seen. 63 * 64 * @param key The name of the property to be set. 65 * @param val The new string value of the property. 66 * @param maxRetry The maximum number of times; must be non-negative. 67 * @param retryDelayMs The number of milliseconds to wait between retries; must be positive. 68 * @throws IllegalArgumentException for non read-only properties if the {@code val} exceeds 69 * 91 characters, or if the retry parameters are invalid. 70 * @throws RuntimeException if the property cannot be set, for example, if it was blocked by 71 * SELinux. libc will log the underlying reason. 72 */ setWithRetry(@onNull String key, @Nullable String val, int maxRetry, long retryDelayMs)73 public static void setWithRetry(@NonNull String key, @Nullable String val, int maxRetry, 74 long retryDelayMs) { 75 if (maxRetry < 0) { 76 throw new IllegalArgumentException("invalid retry count: " + maxRetry); 77 } 78 if (retryDelayMs <= 0) { 79 throw new IllegalArgumentException("invalid retry delay: " + retryDelayMs); 80 } 81 82 RuntimeException failure = null; 83 for (int attempt = 0; attempt < maxRetry; attempt++) { 84 try { 85 SystemProperties.set(key, val); 86 return; 87 } catch (RuntimeException e) { 88 if (failure == null) { 89 failure = e; 90 } 91 try { 92 Thread.sleep(retryDelayMs); 93 } catch (InterruptedException x) { 94 // Ignore this exception. The desired delay is only approximate and 95 // there is no issue if the sleep sometimes terminates early. 96 } 97 } 98 } 99 // This point is reached only if SystemProperties.set() fails at least once. 100 // Rethrow the first exception that was received. 101 throw failure; 102 } 103 } 104