无法调用android.os.SystemProperties.set方法设置系统属性的问题研究

com.test.testservice 无法调用android.os.SystemProperties.set方法的问题研究

error log:
E AndroidRuntime: java.lang.RuntimeException: Unable to create service com.test.testservice.testService: java.lang.RuntimeException: Can not invoke android.os.SystemProperties.set method

crash log:
--------- beginning of crash
 23927 23927 E AndroidRuntime: FATAL EXCEPTION: main
 23927 23927 E AndroidRuntime: Process: com.test.testservice, PID: 23927
 23927 23927 E AndroidRuntime: java.lang.RuntimeException: Unable to create service com.test.testservice.testService: java.lang.RuntimeException: Can not invoke android.os.SystemProperties.set method
 23927 23927 E AndroidRuntime:     at android.app.ActivityThread.handleCreateService(ActivityThread.java:4134)
 23927 23927 E AndroidRuntime:     at android.app.ActivityThread.access$1800(ActivityThread.java:229)
 23927 23927 E AndroidRuntime:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1993)
 23927 23927 E AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:107)
 23927 23927 E AndroidRuntime:     at android.os.Looper.loop(Looper.java:214)
 23927 23927 E AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:7582)
 23927 23927 E AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
 23927 23927 E AndroidRuntime:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
 23927 23927 E AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:960)
 23927 23927 E AndroidRuntime: Caused by: java.lang.RuntimeException: Can not invoke android.os.SystemProperties.set method
 23927 23927 E AndroidRuntime:     at com.test.testservice.SystemProperties.set(SystemProperties.java:32)
 23927 23927 E AndroidRuntime:     at com.test.testservice.testService.onCreate(testService.java:593)
 23927 23927 E AndroidRuntime:     at android.app.ActivityThread.handleCreateService(ActivityThread.java:4122)
 23927 23927 E AndroidRuntime:     ... 8 more
 23927 23927 E AndroidRuntime: Caused by: java.lang.reflect.InvocationTargetException
 23927 23927 E AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
 23927 23927 E AndroidRuntime:     at com.test.testservice.SystemProperties.set(SystemProperties.java:28)
 23927 23927 E AndroidRuntime:     ... 10 more
 23927 23927 E AndroidRuntime: Caused by: java.lang.RuntimeException: failed to set system property
 23927 23927 E AndroidRuntime:     at android.os.SystemProperties.native_set(Native Method)
 23927 23927 E AndroidRuntime:     at android.os.SystemProperties.set(SystemProperties.java:196)
 23927 23927 E AndroidRuntime:     ... 12 more
  1496  6228 V RescueParty: Disabled because of active USB connection
  1496  6228 W ActivityManager: Process com.test.testservice has crashed too many times: killing!
 23927 23927 I Process : Sending signal. PID: 23927 SIG: 9
  1496  6227 I ActivityManager: Process com.test.testservice (pid 23927) has died: pers PER 
======

SystemProperties.set()调查:
在对Android操作系统进行开发的过程中,经常需要使用到Android的隐藏API SystemProperties.set(String key, String value) 这个接口,写入一些属性值存放到系统共享内存,配合SystemProperties.get(String key) 这个接口可以很方便的实现某些功能。由于是android:sharedUserId=“android.uid.system” 的系统级应用,有权限操作类似的隐藏接口。比如可以定义一个persist.test.meid 的属性来保存系统的MEID号,以方便第三方应用开发者获取。
在Android5.0之前,系统级应用可以很方便的写入规范(比如属性key、value的长度有一定限制等)的属性,在这之后,Android系统引入了SELinux,所有的操作都有相应的权限组,任意写入一个属性也会抛出错误,即使是系统级应用.

源代码中关于testservice的权限设置如下:
1. 定义服务名称和属性

sepolicy/property_contexts:    test.                  u:object_r:test_prop:s0
sepolicy/property.te:          type test_prop, property_type;
sepolicy/system_app.te:       #set_prop(system_app, test_prop)

2. 在代码文件sepolicy/system_app.te中做如下修改尝试解决问题

diff --git a/sepolicy/system_app.te b/common/sepolicy/system_app.te
 # test_START
+set_prop(system_app, test_prop)
 # test_END
 
diff --git a/sepolicy/system_server.te b/sepolicy/system_server.te
 # test_START
+set_prop(system_server, test_prop)
 # test_END
//set_prop(system_server, test_prop) 和 allow system_server test_prop:property_service set;意义相等

但是这个方法在android Q上会有编译错误,如下:
[ 21% 1176/5556] build out/target/×/precompiled_sepolicy_intermediates/precompiled_sepolicy
FAILED: out/target/×/precompiled_sepolicy_intermediates/precompiled_sepolicy
/bin/bash -c "out/host/linux-x86/bin/secilc -m -M true -G -c 30          out/target/×/plat_sepolicy.cil_intermediates/plat_sepolicy.cil out/target/×/plat_mapping_file_intermediates/29.0.cil out/target/×/plat_pub_versioned.cil_intermediates/plat_pub_versioned.cil out/target/×/vendor_sepolicy.cil_intermediates/vendor_sepolicy.cil -o out/target/×/precompiled_sepolicy_intermediates/precompiled_sepolicy -f /dev/null"
neverallow check failed at out/target/×/plat_pub_versioned.cil_intermediates/plat_pub_versioned.cil
  (neverallow base_typeattr_470_29_0 base_typeattr_471_29_0 (property_service (set)))
    <root>
    allow at out/target/×/vendor_sepolicy.cil_intermediates/vendor_sepolicy.cil:8995
      (allow system_app_29_0 test_prop (property_service (set)))

neverallow check failed at out/target/×/plat_sepolicy.cil_intermediates/plat_sepolicy.cil:11946 from system/sepolicy/public/property.te
  (neverallow base_typeattr_470 base_typeattr_471 (property_service (set)))
    <root>
    allow at out/target/×/vendor_sepolicy.cil_intermediates/vendor_sepolicy.cil:8995
      (allow system_app_29_0 test_prop (property_service (set)))

Failed to generate binary
Failed to build policydb
ninja: build stopped: subcommand failed.


3. 最终的解决方法:  添加exported_system_prop到property_contexts文件

diff --git a/sepolicy/property_contexts
 # test_START
+test.                  u:object_r:exported_system_prop:s0 exact string
 # test_END
 //关于exported_system_prop目前的资料较少,有待进行深入研究

4.SELinux的基本介绍
SELinux非常繁杂,8.0开始的Treble Project后,为了实现system、vendor分区的隔离,selinux的机制变的更加繁琐。

语法:rule_name source_type target_type : class perm_set
allow system_app misc_user_data_file:file create_file_perms;
get_prop(system_app, system_prop) 其实是一个宏,展开如下:
allow system_app system_prop:file r_file_perms; #/dev/__properties__/system_prop

ROM:
selinux编译生成的策略文件sepolicy,8.0之前在boot.img中,8.0由于treble的原因,system和vendor分区各放置一部分,加载的时候会进行合并。8.0之后单刷userdebug版本的boot不再能获取root权限,要刷userdebug版的system.img才行。
/system/etc/selinux:
plat_file_contexts
plat_property_contexts
plat_sepolicy.cil
/vendor/etc/selinux:
vendor_file_contexts
vendor_property_contexts
vendor_sepolicy.cil

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是Scala编写的Spark代码,可以实现将MySQL数据库中表的增量数据抽取到Hive中对应的表中: ```scala import org.apache.spark.sql.{DataFrame, SaveMode, SparkSession} import java.util.Properties object MySQLToHiveIncremental { def main(args: Array[String]): Unit = { // Initialize Spark Session val spark = SparkSession.builder() .appName("MySQL To Hive Incremental") .master("local[*]") .enableHiveSupport() .getOrCreate() // Define MySQL connection properties val mysqlUrl = "jdbc:mysql://localhost:3306/shtd_store" val mysqlUser = "root" val mysqlPassword = "password" // Define Hive database and table names val databaseName = "ods" val userTable = "user_info" val skuTable = "sku_info" val provinceTable = "base_province" val regionTable = "base_region" val orderTable = "order_info" val orderDetailTable = "order_detail" // Load the latest timestamp from Hive tables val userLatestTimestamp = getLatestTimestampFromHive(spark, databaseName, userTable) val skuLatestTimestamp = getLatestTimestampFromHive(spark, databaseName, skuTable) val provinceLatestTimestamp = getLatestTimestampFromHive(spark, databaseName, provinceTable) val regionLatestTimestamp = getLatestTimestampFromHive(spark, databaseName, regionTable) val orderLatestTimestamp = getLatestTimestampFromHive(spark, databaseName, orderTable) val orderDetailLatestTimestamp = getLatestTimestampFromHive(spark, databaseName, orderDetailTable) // Define MySQL query to fetch new records val userQuery = s"SELECT * FROM user_info WHERE updated_at > '$userLatestTimestamp'" val skuQuery = s"SELECT * FROM sku_info WHERE updated_at > '$skuLatestTimestamp'" val provinceQuery = s"SELECT * FROM base_province WHERE updated_at > '$provinceLatestTimestamp'" val regionQuery = s"SELECT * FROM base_region WHERE updated_at > '$regionLatestTimestamp'" val orderQuery = s"SELECT * FROM order_info WHERE updated_at > '$orderLatestTimestamp'" val orderDetailQuery = s"SELECT * FROM order_detail WHERE updated_at > '$orderDetailLatestTimestamp'" // Define MySQL connection properties val mysqlProperties = new Properties() mysqlProperties.setProperty("user", mysqlUser) mysqlProperties.setProperty("password", mysqlPassword) // Load data from MySQL using JDBC val userDF = loadDataFromMySQL(spark, mysqlUrl, userQuery, mysqlProperties) val skuDF = loadDataFromMySQL(spark, mysqlUrl, skuQuery, mysqlProperties) val provinceDF = loadDataFromMySQL(spark, mysqlUrl, provinceQuery, mysqlProperties) val regionDF = loadDataFromMySQL(spark, mysqlUrl, regionQuery, mysqlProperties) val orderDF = loadDataFromMySQL(spark, mysqlUrl, orderQuery, mysqlProperties) val orderDetailDF = loadDataFromMySQL(spark, mysqlUrl, orderDetailQuery, mysqlProperties) // Write data to Hive tables writeDataToHive(spark, userDF, databaseName, userTable) writeDataToHive(spark, skuDF, databaseName, skuTable) writeDataToHive(spark, provinceDF, databaseName, provinceTable) writeDataToHive(spark, regionDF, databaseName, regionTable) writeDataToHive(spark, orderDF, databaseName, orderTable) writeDataToHive(spark, orderDetailDF, databaseName, orderDetailTable) // Stop Spark Session spark.stop() } /** * Load data from MySQL using JDBC * * @param spark Spark Session object * @param mysqlUrl MySQL connection URL * @param query MySQL query to fetch data * @param properties MySQL connection properties * @return DataFrame containing the fetched data */ def loadDataFromMySQL(spark: SparkSession, mysqlUrl: String, query: String, properties: Properties): DataFrame = { spark.read.jdbc(mysqlUrl, s"($query) as tmp", properties) } /** * Write data to Hive table * * @param spark Spark Session object * @param df DataFrame containing the data to write * @param database Hive database name * @param table Hive table name */ def writeDataToHive(spark: SparkSession, df: DataFrame, database: String, table: String): Unit = { df.write.mode(SaveMode.Append).insertInto(s"$database.$table") } /** * Get the latest timestamp from a Hive table * * @param spark Spark Session object * @param database Hive database name * @param table Hive table name * @return Latest timestamp as a string */ def getLatestTimestampFromHive(spark: SparkSession, database: String, table: String): String = { val sql = s"SELECT MAX(updated_at) as latest_ts FROM $database.$table" val result = spark.sql(sql).collect()(0).getString(0) if (result == null) "1970-01-01 00:00:00" else result } } ``` 在此代码中,我们首先初始化了Spark Session,并定义了MySQL的连接参数和Hive数据库和表的名称。然后,我们从Hive中获取了表中的最新时间戳,并根据这些最新时间戳构建了MySQL查询来获取增量数据。接下来,我们使用JDBC从MySQL中加载数据,并将其写入到Hive表中。最后,我们停止Spark Session并完成了整个过程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值