1. System properties
System properties are key-value pairs with special meanings in the system. We sometimes need to use system properties during the development process, such as getting the system software version, getting the device name, etc. Sometimes we also need to set custom properties. System properties are global and easy to access.
2. Get and set
2.1 Architecture
2.2 Using the terminal
//Get system property values getprop my.prop.test //Set system property values setprop my.prop.test //Listen for system property changes watchprops my.prop.test
2.3 Java code
There is a hidden class under android.os in the Android source code: SystemProperties. System properties can be set and obtained through SystemProperties.set and SystemProperties.get.
Part of the source code of Systemproperties is as follows: frameworks\base\core\java\android\os\SystemProperties.java
... public class SystemProperties { ... //Get the value of the attribute key, if there is no such attribute, return the default value def @SystemApi public static String get(@NonNull String key, @Nullable String def) { if (TRACK_KEY_ACCESS) onKeyAccess(key); return native_get(key, def); } ... //Set the value of attribute key to val @SystemApi public static void set(@NonNull String key, @Nullable String val) { if (val != null & amp; & amp; !val.startsWith("ro.") & amp; & amp; val.length() > PROP_VALUE_MAX) { throw new IllegalArgumentException("value of system property '" + key + "' is longer than " + PROP_VALUE_MAX + " characters: " + val); } if (TRACK_KEY_ACCESS) onKeyAccess(key); native_set(key, val); } .... }
However, the interface of this class is not open to the outside world and needs to be used through reflection. Here is one of my SystemProperties utility classes:
public class SystemProperties { private final static String TAG = "SystemProperties"; public static String get(String key) { Class<?> SysProp = null; Method method = null; String value = null; try { SysProp = Class.forName("android.os.SystemProperties"); method = SysProp.getMethod("get", String.class); value = (String) method.invoke(null, key); Log.i(TAG, "value:" + value); } catch (Exception e) { Log.e(TAG,"read SystemProperties error",e); } return value; } public static String get(String key, String defaultValue) { Class<?> SysProp = null; Method method = null; String value = null; try { SysProp = Class.forName("android.os.SystemProperties"); method = SysProp.getMethod("get", String.class, String.class); value = (String) method.invoke(null, key, defaultValue); } catch (Exception e) { Log.e(TAG,"read SystemProperties error",e); } return value; } public static int getInt(String key, int defaultValue) { Class<?> SysProp = null; Method method = null; int value = 0; try { SysProp = Class.forName("android.os.SystemProperties"); method = SysProp.getMethod("getInt", String.class, int.class); value = (Integer) method.invoke(null, key, defaultValue); } catch (Exception e) { Log.e(TAG,"read SystemProperties error",e); } return value; } public static long getLong(String key, long defaultValue) { Class<?> SysProp = null; Method method = null; long value = 0; try { SysProp = Class.forName("android.os.SystemProperties"); method = SysProp.getMethod("getLong", String.class, long.class); value = (Long) method.invoke(null, key, defaultValue); } catch (Exception e) { Log.e(TAG,"read SystemProperties error",e); } return value; } public static boolean getBoolean(String key, boolean defaultValue) { Class<?> SysProp = null; Method method = null; boolean value = false; try { SysProp = Class.forName("android.os.SystemProperties"); method = SysProp.getMethod("getBoolean", String.class, boolean.class); value = (Boolean) method.invoke(null, key, defaultValue); } catch (Exception e) { Log.e(TAG,"read SystemProperties error",e); } return value; } public static void set(String key, String value) { Class<?> SysProp = null; Method method = null; try { SysProp = Class.forName("android.os.SystemProperties"); method = SysProp.getMethod("set", String.class, String.class); method.invoke(null, key, value); } catch (Exception e) { Log.e(TAG,"read SystemProperties error",e); } } public static void addChangeCallback(Runnable runnable) { Class<?> SysProp = null; Method method = null; try { SysProp = Class.forName("android.os.SystemProperties"); method = SysProp.getMethod("addChangeCallback", Runnable.class); method.invoke(null, runnable); } catch (Exception e) { Log.e(TAG,"read SystemProperties error",e); } } }
Take ActivityManagerService as an example below, frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
List examples of using prop in source code:
final void finishBooting() { ... //Set the boot completion flag attribute sys.boot_completed SystemProperties.set("sys.boot_completed", "1"); } ... private static void maybePruneOldTraces(File tracesDir) { ... //Get tombstoned.max_anr_count attribute value final int max = SystemProperties.getInt("tombstoned.max_anr_count", 64); }
2.4 C++ code
Take MPEG4Writer.cpp as an example below.
frameworks\av\media\libstagefright\MPEG4Writer.cpp
List examples of using prop in source code:
#include <cutils/properties.h> ... void MPEG4Writer::addDeviceMeta() { ... if (property_get("ro.build.version.release", val, NULL) ... if (property_get("ro.product.model", val, NULL) ... }
Using prop in C++ code requires:
- include
- Android.mk or Android.bp or Makefile needs to link the libcutils library frameworks\av\media\libstagefright\Android.bp
shared_libs: [ ... "libcutils", ...
The source code of properties.h is in: system/core/libcutils/include/cutils/properties.h
int property_get(const char* key, char* value, const char* default_value); int property_set(const char *key, const char *value); int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
3. Special attributes
3.1 ro read-only attribute
Attributes such as ro (read only) are usually system default attributes and are set during system compilation or initialization.
$ getprop ro.vendor.build.version.release 10 $ setprop ro.vendor.build.version.release 9 setprop: failed to set property 'ro.vendor.build.version.release' to '9'
3.2 persist persistent attributes
Set the properties starting with persist, which can still be saved after power failure, and the value is written to data/property/persistent_properties.
$ getprop persist.hello.test //The property is empty $ setprop persist.hello.test abc //Set the property persist.hello.test value to abc $ getprop persist.hello.test abc //Attribute get is normal abc $reboot //Restart the device $ getprop persist.hello.test //The attribute is abc abc
3.3 ctl control attribute
setprop ctl.start xxx //Start a service setprop ctl.stop xxx //Close a service setprop ctl.restart xxx //Restart a service
3.4 sys.powerctl attribute
The sys.powerctl attribute can control device restart and shutdown.
setprop sys.powerctl shutdown //Device shutdown setprop sys.powerctl reboot //Device reboot
3.5 Common attributes
Setting attributes starting with other formats cannot be saved after power off.
$ getprop hello.test //The attribute is empty $ setprop hello.test 123//Set the property persist.hello.test value to abc $ getprop hello.test 123//Attribute get is normal 123 $reboot //Restart the device $ getprop hello.test //The property is empty
3.7 Add system default attributes
When the system is powered on, the properties in the *.prop property configuration file will be loaded, so there will be default properties after booting. Analysis of the property_load_boot_defaults(load_debug_prop) function in the init process.
Location: system\core\init\property_service.cpp
void property_load_boot_defaults(bool load_debug_prop) { std::map<std::string, std::string> properties; //Load properties build.prop, default.prop to properties if (!load_properties_from_file("/system/etc/prop.default", nullptr, & amp;properties)) { // Try recovery path if (!load_properties_from_file("/prop.default", nullptr, & amp;properties)) { // Try legacy path load_properties_from_file("/default.prop", nullptr, & amp;properties); } } load_properties_from_file("/system/build.prop", nullptr, & amp;properties); load_properties_from_file("/vendor/default.prop", nullptr, & amp;properties); load_properties_from_file("/vendor/build.prop", nullptr, & amp;properties); if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) { load_properties_from_file("/odm/etc/build.prop", nullptr, & amp;properties); } else { load_properties_from_file("/odm/default.prop", nullptr, & amp;properties); load_properties_from_file("/odm/build.prop", nullptr, & amp;properties); } load_properties_from_file("/product/build.prop", nullptr, & amp;properties); load_properties_from_file("/product_services/build.prop", nullptr, & amp;properties); load_properties_from_file("/factory/factory.prop", "ro.*", & amp;properties); ... //Save the properties in properties into property properties through PropertySet for (const auto & amp; [name, value] : properties) { std::string error; if (PropertySet(name, value, & amp;error) != PROP_SUCCESS) { LOG(ERROR) << "Could not set '" << name << "' to '" << value << "' while loading .prop files" << error; } } property_initialize_ro_product_props();//Initialize the read-only properties of the ro_product prefix property_derive_build_props();//Initialize compilation related properties update_sys_usb_config();//Set the persist.sys.usb.config property to control USB debugging and file transfer functions }
As can be seen from the above code, system properties are loaded into the properties variable from multiple property files.prop, and then properties are added to the system through PropertySet(), and read-only, compiled, and USB-related property values are initialized. In PropertySet(), it communicates with the property service through Socket and stores props in shared memory.
Here is an example of adding system properties to device/google/marlin/system.prop:
# Add your own system default properties persist.hello.world=hello
Note: The attribute prefix added here must be defined in system/sepolicy/private/property_contexts, otherwise it will be invalid. After making android, you can find the added attribute persist.hello.world in out/target/product/xxx/system/build.prop or out/target/product/xxx/vendor/build.prop, which means the addition is basically successful.
4. Add customized *.prop
The code paths involved are summarized as follows:
device/qcom/qssi/hello.prop device/qcom/qssi/qssi.mk device/qcom/sepolicy/generic/private/property_contexts system/core/rootdir/init.rc system/core/init/property_service.cpp
In order to facilitate unified management of customized attributes, sometimes customized attributes are written in customized .prop files. The following takes adding hello.prop as an example to illustrate the adding process.
Add hello.prop under 4.1 device
device/qcom/qssi/hello.prop
# # system.prop for qssi # ro.hello.year=2022 //Add ro attribute persist.hello.month=07 //Add persist attribute hello.day=25 //Add hello attribute ro.product.model=HelloWorld //The customized system already has the ro.product.model attribute
4.2 Configure preset path
Modify device.mk under device to specify the preset path of hello.prop device/qcom/qssi/qssi.mk
#Preset hello.prop to system/hello.prop PRODUCT_COPY_FILES + = \ device/qcom/qssi/hello.prop:system/hello.prop
4.3 SELinux permission configuration
The properties starting with hello. are newly added configurations. You need to configure the corresponding SELinux rules, otherwise they will be invalid. The configuration method is as follows: device/qcom/sepolicy/generic/private/property_contexts
hello. u:object_r:system_prop:s0
4.4 Configure hello.prop permissions
This step can be omitted. If read and write permissions are not configured, the default system/prop is 644. Here, configure the same 600 permissions as system/build.prop system/core/rootdir/init.rc
on fs chmod 0600 /system/hello.prop
4.5 Load hello.prop
It is not enough to preset hello.prop to system/hello.prop. You need to load hello.prop when the system starts to make it effective system/core/init/property_service.cpp
load_properties_from_file("/system/build.prop", nullptr, & amp;properties); load_properties_from_file("/vendor/default.prop", nullptr, & amp;properties); load_properties_from_file("/vendor/build.prop", nullptr, & amp;properties); if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) { load_properties_from_file("/odm/etc/build.prop", nullptr, & amp;properties); } else { load_properties_from_file("/odm/default.prop", nullptr, & amp;properties); load_properties_from_file("/odm/build.prop", nullptr, & amp;properties); } load_properties_from_file("/product/build.prop", nullptr, & amp;properties); load_properties_from_file("/product_services/build.prop", nullptr, & amp;properties); load_properties_from_file("/factory/factory.prop", "ro.*", & amp;properties); //load the preset hello.prop. The last load ensures that its configuration properties have a higher priority. load_properties_from_file("/system/hello.prop", nullptr, & amp;properties);
4.6 Verification
After Android is fully compiled, the generated out/target/product/qssi/system/hello.prop can be found normally.
Check that its content should be consistent with the content of device/qcom/qssi/hello.prop.