android property实现路径

上层接口实现

system/core/libcutils/properties.cpp:

property_set/property_get:

#include <sys/_system_properties.h>

int property_set(const char *key, const char *value) {
    return __system_property_set(key, value);
}

int property_get(const char *key, char *value, const char *default_value) {
    int len = __system_property_get(key, value);
    if (len > 0) {
        return len;
    }
    if (default_value) {
        len = strnlen(default_value, PROPERTY_VALUE_MAX - 1);
        memcpy(value, default_value, len);
        value[len] = '\0';
    }
    return len;
}

可以看到实际上上述两个接口会调用__system_property_set/__system_property_get这两个函数来实现的,再进一步跟下去看看发生了什么?这两个函数的实现是在bionic库中,bionic/libc/bionic/system_properties.cpp:
初始化函数:

int __system_property_area_init() {
  free_and_unmap_contexts();
  mkdir(property_filename, S_IRWXU | S_IXGRP | S_IXOTH);
  if (!initialize_properties()) {
    return -1;
  }
  bool open_failed = false;
  bool fsetxattr_failed = false;
  list_foreach(contexts, [&fsetxattr_failed, &open_failed](context_node* l) {
    if (!l->open(true, &fsetxattr_failed)) {
      open_failed = true;
    }
  });
  if (open_failed || !map_system_property_area(true, &fsetxattr_failed)) {
    free_and_unmap_contexts();
    return -1;
  }
  initialized = true;
  return fsetxattr_failed ? -2 : 0;
}

在初始化函数中,会执行map_system_property_area,这个函数就会去打开设备文件/dev/__properties__properties_serial,并mmap到指针__system_property_area__上。后续只需要针对__system_property_area__这个全局指针操作就可以设置和读取对应property。通过初始化我们也可以看出,property的实现是需要kernel底层支持的,需要实现对应的设备文件和维护property存储区域。

查找函数:

 const prop_info* __system_property_find(const char* name) {
   if (!__system_property_area__) {
     return nullptr;
   }

   prop_area* pa = get_prop_area_for_name(name);
   if (!pa) {
     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
     return nullptr;
   }

   return pa->find(name);
 }

由上面的init初始化过程可知,最终我们获取到了__system_property_area__这个存储property的区域指针,那么如果我们想要操作一个特定的property,就首先要找到该property对应的存储地址,此find函数就是实现通过name查找对应存储地址的功能。

读取函数:

 int __system_property_read(const prop_info* pi, char* name, char* value) {
   while (true) {
     uint32_t serial = __system_property_serial(pi);  // acquire semantics
     size_t len = SERIAL_VALUE_LEN(serial);
     memcpy(value, pi->value, len + 1);
     // TODO: Fix the synchronization scheme here.
     // There is no fully supported way to implement this kind
     // of synchronization in C++11, since the memcpy races with
     // updates to pi, and the data being accessed is not atomic.
     // The following fence is unintuitive, but would be the
     // correct one if memcpy used memory_order_relaxed atomic accesses.
     // In practice it seems unlikely that the generated code would
     // would be any different, so this should be OK.
     atomic_thread_fence(memory_order_acquire);
     if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) {
       if (name != nullptr) {
         size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
         if (namelen >= PROP_NAME_MAX) {
           async_safe_format_log(ANDROID_LOG_ERROR, "libc",
                                 "The property name length for \"%s\" is >= %d;"
                                 " please use __system_property_read_callback"
                                 " to read this property. (the name is truncated to \"%s\")",
                                 pi->name, PROP_NAME_MAX - 1, name);
         }
       }
       return len;
     }
   }
 }

int __system_property_get(const char* name, char* value) {
  const prop_info* pi = __system_property_find(name);

  if (pi != 0) {
    return __system_property_read(pi, nullptr, value);
  } else {
    value[0] = 0;
    return 0;
  }
}

经过前面我们知道,利用find函数我们可以找到了property对应的地址,在__system_property_get的实现中,会先通过name调用find函数查找到对应地址,然后把该地址传递给__system_property_read,进一步读取到property的值。

写入函数:

 int __system_property_set(const char* key, const char* value) {
   if (key == nullptr) return -1;
   if (value == nullptr) value = "";
   if (strlen(value) >= PROP_VALUE_MAX) return -1;

   if (g_propservice_protocol_version == 0) {
     detect_protocol_version();
   }

   if (g_propservice_protocol_version == kProtocolVersion1) {
     // Old protocol does not support long names
     if (strlen(key) >= PROP_NAME_MAX) return -1;

     prop_msg msg;
     memset(&msg, 0, sizeof msg);
     msg.cmd = PROP_MSG_SETPROP;
     strlcpy(msg.name, key, sizeof msg.name);
     strlcpy(msg.value, value, sizeof msg.value);

     return send_prop_msg(&msg);
   } else {
     // Use proper protocol
     PropertyServiceConnection connection;
     if (!connection.IsValid()) {
       errno = connection.GetLastError();
       async_safe_format_log(ANDROID_LOG_WARN,
                             "libc",
                             "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)",
                             key,
                             value,
                             errno,
                             strerror(errno));
       return -1;
     }

     SocketWriter writer(&connection);
     if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
       errno = connection.GetLastError();
       async_safe_format_log(ANDROID_LOG_WARN,
                             "libc",
                             "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
                             key,
                             value,
                             errno,
                             strerror(errno));
       return -1;
     }

     int result = -1;
     if (!connection.RecvInt32(&result)) {
       errno = connection.GetLastError();
       async_safe_format_log(ANDROID_LOG_WARN,
                             "libc",
                             "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
                             key,
                             value,
                             errno,
                             strerror(errno));
       return -1;
     }

     if (result != PROP_SUCCESS) {
       async_safe_format_log(ANDROID_LOG_WARN,
                             "libc",
                             "Unable to set property \"%s\" to \"%s\": error code: 0x%x",
                             key,
                             value,
                             result);
       return -1;
     }

     return 0;
   }
 }

__system_property_set的实现相对于__system_property_get要更加复杂,因为要保证写入权限的安全,所以要受SElinux的限制,从上面的代码可以看到,实际上会利用socket进程间通信方式与Property Service进行交互,并最终由Property Service完成SElinux权限检查,并最终进行设置动作。上面有写到两种通信protocol,第一种会发送PROP_MSG_SETPROP命令码,第二种会发送PROP_MSG_SETPROP2命令码,我们会进一步跟一下看看这个命令到底是做什么。

property service服务的实现代码在如下文件中:

system/core/init/property_service.cpp:

 static void handle_property_set_fd() {
 ......

     switch (cmd) {
     case PROP_MSG_SETPROP: {
         char prop_name[PROP_NAME_MAX];
         char prop_value[PROP_VALUE_MAX];

         if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
             !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
           PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
           return;
         }

         prop_name[PROP_NAME_MAX-1] = 0;
         prop_value[PROP_VALUE_MAX-1] = 0;

         handle_property_set(socket, prop_value, prop_value, true);
         break;
       }

     case PROP_MSG_SETPROP2: {
         std::string name;
         std::string value;
         if (!socket.RecvString(&name, &timeout_ms) ||
             !socket.RecvString(&value, &timeout_ms)) {
           PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
           socket.SendUint32(PROP_ERROR_READ_DATA);
           return;
         }

         handle_property_set(socket, name, value, false);
         break;

Property Service类似与一个普通的网络通信服务实现一样,利用socket API来实现,只不过使用的是是UNIX socket:AF_LOCAL(也就是AF_UNIX)。它listen(监听)socket并接收解包客户端发来的请求。这里看到上面的两个命令码实际上是会通过handle_property_set来进行处理的。

handle_property_set --> check_mac_perms (检测SElinux权限)
                        PropertySetImpl (设置Property实例)-->__system_property_find
                                                              __system_property_update/__system_property_add

猜你喜欢

转载自blog.csdn.net/rikeyone/article/details/80856429