Android系统10 RK3399 init进程启动(三十六) 属性property操作API

 配套系列教学视频链接:

      安卓系列教程之ROM系统开发-百问100ask

说明

系统:Android10.0

设备: FireFly RK3399 (ROC-RK3399-PC-PLUS)

前言

前面几篇文章介绍的属性基本框架和属性的基本概念, 在Android中,各种代码场景下都会对属性进行代码操作, 所以需要了解一下常见的C, C++,java中属性的各种API。


一, API调用层次

Android系统10 RK3399 init进程启动(三十六) 属性property操作API_第1张图片

二, C语言客户端API

头文件在: system/core/include/cutils/properties.h

实现在: system/core/libcutils/properties.cpp

int8_t property_get_bool(const char *key, int8_t default_value);
int64_t property_get_int64(const char *key, int64_t default_value);
int property_get(const char* key, char* value, const char* default_value);
int32_t property_get_int32(const char *key, int32_t default_value);
int property_set(const char *key, const char *value);

 例子:

#include  
#include 
property_set("persist.sys.language", "zh"); 
property_get("persist.sys.language", propLang, "en"); 

三, C++客户端API

头文件声明在: system/core/base/include/android-base/properties.h

实现代: system/core/base/properties.cpp

namespace android {
namespace base {
// 获取bool类型的属性值,如果属性为空或者不存在, 返回参数2的默认值
bool GetBoolProperty(const std::string& key, bool default_value);
template  
//获取int类型的属性值, 如果属性为空或不存在,并且不在最小值和最大值之间,返回参数2的默认值
T GetIntProperty(const std::string& key, T default_value, T min, T max);
//获取unsignd int类型的属性值,如果属性为空或不存在,并且不在0和最大值之间,返回参数2的默认值
template 
T GetUintProperty(const std::string& key, T default_value, T max);
// 获取默认类型( 字符串)属性值 
std::string GetProperty(const std::string& key, const std::string& default_value);
//设置属性值
bool SetProperty(const std::string& key, const std::string& value);
#if defined(__BIONIC__)
// 等待属性的值变成预定值, relative_timeout参数设置超时时间, 成功返回true。
bool WaitForProperty(const std::string& key, const std::string& expected_value,
                     std::chrono::milliseconds relative_timeout = std::chrono::milliseconds::max());
#endif
}
}

 例子:

#include 

std::string prop_val = android::base::GetProperty("sys.boot_completed", "");
if (!android::base::SetProperty("ctl.stop", "mpdecision")){
    LOG(ERROR) << "setprop ctl.start mpdecision failed";
}

四, 服务端C++修改属性的实现API

C和C ++客户端的设置都是通过socket和服务端通信, 服务端中会实现对应的接口,一般我们开发的时候不需要关注这个, 想了解原理的话, 可以看看这部分代码:

在proerty_service端(init进程)在响应客户端修改属性值的时候,会使用如下API:

system/core/init/property_service.cpp

uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error)

因为只有设置属性才会调用到init进程中来,所以get相关接口就不是在这里实现了,另外在init进程中经常会用如下接口:

property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
该接口在init.cpp有如下定义: 
uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;

 其实最终都会调用到PropertySet()去。而PropertySet()再会调用bionic相关API:

bionic/libc/bionic/system_property_api.cpp

修改属性会调用如下接口来完成:

//1, 根据属性名,获取到prop_info树叶指针
const prop_info* __system_property_find(const char* name)
//2, 更新prop_info树叶中属性的值,其实就是修改属性
int __system_property_update(prop_info* pi, const char* value, unsigned int len)
//3, 如果属性为系统中新增属性
int __system_property_add(const char* name, unsigned int namelen, const char* value,
                          unsigned int valuelen)

最后不管是客户端还是服务端, set和get都是通过一个类来实现:

bionic/libc/system_properties/system_properties.cpp

static SystemProperties system_properties;
int __system_property_get(const char* name, char* value) {
  return system_properties.Get(name, value);
}
int __system_property_update(prop_info* pi, const char* value, unsigned int len) {
  return system_properties.Update(pi, value, len);
}

 调用过程就是前面提到的: 

Android系统10 RK3399 init进程启动(三十六) 属性property操作API_第2张图片

五, JAVA API

Android系统中提供类frameworks/base/core/java/android/os/SystemProperties.java来操作属性,需要注意的是,这些接口只针对系统APP, Android API从21后开始,不再支持普通APP直接支持通过SystemProperties.get/set方式来获取/设置系统属性。一般通过反射机制可以获取。但是Android11之后,又不允许使用反射机制了,所以很多时候会通过jni的方式来获取。

public class SystemProperties {
	public static String get(@NonNull String key, @Nullable String def);
	public static int getInt(@NonNull String key, int def);
	public static long getLong(@NonNull String key, long def) ;
	public static boolean getBoolean(@NonNull String key, boolean def);
	public static void set(@NonNull String key, @Nullable String val);
	public static void addChangeCallback(@NonNull Runnable callback);
}

 例子: 

import android.os.SystemProperties; 
SystemProperties.set("persist.sys.language", zone.getID()); 
String lang= SystemProperties.get("persist.sys.language"); 

Android系统提供的现成的key用来获取系统信息: android.os.Build类

frameworks/base/core/java/android/os/Build.java

Build.BOARD // 主板  

Build.CPU_ABI // cpu指令集  

Build.DEVICE // 设备参数  

Build.DISPLAY // 显示屏参数  

Build.FINGERPRINT // 硬件名称

该类就是系统获取好了系统属性,然后封装起来给应用使用: 

package android.os;
public class Build {
 /** The manufacturer of the product/hardware. */
      public static final String MANUFACTURER = getString("ro.product.manufacturer");
 
      /** The consumer-visible brand with which the product/hardware will be associated, if any. */
      public static final String BRAND = getString("ro.product.brand");
 
     /** The end-user-visible name for the end product. */
     public static final String MODEL = getString("ro.product.model");
  
      /** The system bootloader version number. */
     public static final String BOOTLOADER = getString("ro.bootloader");

 @UnsupportedAppUsage
      private static String getString(String property) {
         return SystemProperties.get(property, UNKNOWN);
     }

}

例子:

public static String getDeviceListing() {
        return "Build.PRODUCT: " + Build.PRODUCT + "\n" +
            "Build.MANUFACTURER: " + Build.MANUFACTURER + "\n" +
            "Build.BRAND: " + Build.BRAND + "\n" +
            "Build.DEVICE: " + Build.DEVICE + "\n" +
            "Build.MODEL: " + Build.MODEL + "\n" +
            "Build.HARDWARE: " + Build.HARDWARE + "\n" +
            "Build.FINGERPRINT: " + Build.FINGERPRINT + "\n" +
            "Build.TAGS: " + Build.TAGS + "\n" 
    }

 在应用开发中因为systemproperties的hide属性,所以无法直接访问到get和set函数。通过反射机制来获取get和set函数:

public static String getProperty(String key, String defaultValue) {
        String value = defaultValue;
        try {
            Class c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("get", String.class, String.class);
            value = (String)(get.invoke(c, key, defaultValue));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            return value;
        }
    }

六,总结

以上就是C, C++, JAVA各个语言中操作属性的相关API, 在开发中,我们掌握使用这些接口就足够了。

你可能感兴趣的:(Android属性,Android驱动,Android系统,RK3399,Android,init进程)