android.os.SystemProperties在哪里?

54
8个回答

67
如果您使用“reflection”选项,您可以使用下面的类。
package com.etc.etc;

import java.io.File;
import java.lang.reflect.Method;
import android.content.Context;
import dalvik.system.DexFile;


public class SystemPropertiesProxy
{

/**
 * This class cannot be instantiated
 */
private SystemPropertiesProxy(){

}

    /**
     * Get the value for the given key.
     * @return an empty string if the key isn't found
     * @throws IllegalArgumentException if the key exceeds 32 characters
     */
    public static String get(Context context, String key) throws IllegalArgumentException {

        String ret= "";

        try{

          ClassLoader cl = context.getClassLoader(); 
          @SuppressWarnings("rawtypes")
          Class SystemProperties = cl.loadClass("android.os.SystemProperties");

          //Parameters Types
          @SuppressWarnings("rawtypes")
              Class[] paramTypes= new Class[1];
          paramTypes[0]= String.class;

          Method get = SystemProperties.getMethod("get", paramTypes);

          //Parameters
          Object[] params= new Object[1];
          params[0]= new String(key);

          ret= (String) get.invoke(SystemProperties, params);

        }catch( IllegalArgumentException iAE ){
            throw iAE;
        }catch( Exception e ){
            ret= "";
            //TODO
        }

        return ret;

    }

    /**
     * Get the value for the given key.
     * @return if the key isn't found, return def if it isn't null, or an empty string otherwise
     * @throws IllegalArgumentException if the key exceeds 32 characters
     */
    public static String get(Context context, String key, String def) throws IllegalArgumentException {

        String ret= def;

        try{

          ClassLoader cl = context.getClassLoader(); 
          @SuppressWarnings("rawtypes")
          Class SystemProperties = cl.loadClass("android.os.SystemProperties");

          //Parameters Types
          @SuppressWarnings("rawtypes")
              Class[] paramTypes= new Class[2];
          paramTypes[0]= String.class;
          paramTypes[1]= String.class;          

          Method get = SystemProperties.getMethod("get", paramTypes);

          //Parameters
          Object[] params= new Object[2];
          params[0]= new String(key);
          params[1]= new String(def);

          ret= (String) get.invoke(SystemProperties, params);

        }catch( IllegalArgumentException iAE ){
            throw iAE;
        }catch( Exception e ){
            ret= def;
            //TODO
        }

        return ret;

    }

    /**
     * Get the value for the given key, and return as an integer.
     * @param key the key to lookup
     * @param def a default value to return
     * @return the key parsed as an integer, or def if the key isn't found or
     *         cannot be parsed
     * @throws IllegalArgumentException if the key exceeds 32 characters
     */
    public static Integer getInt(Context context, String key, int def) throws IllegalArgumentException {

        Integer ret= def;

        try{

          ClassLoader cl = context.getClassLoader(); 
          @SuppressWarnings("rawtypes")
          Class SystemProperties = cl.loadClass("android.os.SystemProperties");

          //Parameters Types
          @SuppressWarnings("rawtypes")
              Class[] paramTypes= new Class[2];
          paramTypes[0]= String.class;
          paramTypes[1]= int.class;  

          Method getInt = SystemProperties.getMethod("getInt", paramTypes);

          //Parameters
          Object[] params= new Object[2];
          params[0]= new String(key);
          params[1]= new Integer(def);

          ret= (Integer) getInt.invoke(SystemProperties, params);

        }catch( IllegalArgumentException iAE ){
            throw iAE;
        }catch( Exception e ){
            ret= def;
            //TODO
        }

        return ret;

    }

    /**
     * Get the value for the given key, and return as a long.
     * @param key the key to lookup
     * @param def a default value to return
     * @return the key parsed as a long, or def if the key isn't found or
     *         cannot be parsed
     * @throws IllegalArgumentException if the key exceeds 32 characters
     */
    public static Long getLong(Context context, String key, long def) throws IllegalArgumentException {

        Long ret= def;

        try{

          ClassLoader cl = context.getClassLoader();
          @SuppressWarnings("rawtypes")
              Class SystemProperties= cl.loadClass("android.os.SystemProperties");

          //Parameters Types
          @SuppressWarnings("rawtypes")
              Class[] paramTypes= new Class[2];
          paramTypes[0]= String.class;
          paramTypes[1]= long.class;  

          Method getLong = SystemProperties.getMethod("getLong", paramTypes);

          //Parameters
          Object[] params= new Object[2];
          params[0]= new String(key);
          params[1]= new Long(def);

          ret= (Long) getLong.invoke(SystemProperties, params);

        }catch( IllegalArgumentException iAE ){
            throw iAE;
        }catch( Exception e ){
            ret= def;
            //TODO
        }

        return ret;

    }

    /**
     * Get the value for the given key, returned as a boolean.
     * Values 'n', 'no', '0', 'false' or 'off' are considered false.
     * Values 'y', 'yes', '1', 'true' or 'on' are considered true.
     * (case insensitive).
     * If the key does not exist, or has any other value, then the default
     * result is returned.
     * @param key the key to lookup
     * @param def a default value to return
     * @return the key parsed as a boolean, or def if the key isn't found or is
     *         not able to be parsed as a boolean.
     * @throws IllegalArgumentException if the key exceeds 32 characters
     */
    public static Boolean getBoolean(Context context, String key, boolean def) throws IllegalArgumentException {

        Boolean ret= def;

        try{

          ClassLoader cl = context.getClassLoader(); 
          @SuppressWarnings("rawtypes")
          Class SystemProperties = cl.loadClass("android.os.SystemProperties");

          //Parameters Types
          @SuppressWarnings("rawtypes")
              Class[] paramTypes= new Class[2];
          paramTypes[0]= String.class;
          paramTypes[1]= boolean.class;  

          Method getBoolean = SystemProperties.getMethod("getBoolean", paramTypes);

          //Parameters         
          Object[] params= new Object[2];
          params[0]= new String(key);
          params[1]= new Boolean(def);

          ret= (Boolean) getBoolean.invoke(SystemProperties, params);

        }catch( IllegalArgumentException iAE ){
            throw iAE;
        }catch( Exception e ){
            ret= def;
            //TODO
        }

        return ret;

    }

    /**
     * Set the value for the given key.
     * @throws IllegalArgumentException if the key exceeds 32 characters
     * @throws IllegalArgumentException if the value exceeds 92 characters
     */
    public static void set(Context context, String key, String val) throws IllegalArgumentException {

        try{

          @SuppressWarnings("unused")
          DexFile df = new DexFile(new File("/system/app/Settings.apk"));
          @SuppressWarnings("unused")
          ClassLoader cl = context.getClassLoader(); 
          @SuppressWarnings("rawtypes")
          Class SystemProperties = Class.forName("android.os.SystemProperties");

          //Parameters Types
          @SuppressWarnings("rawtypes")
              Class[] paramTypes= new Class[2];
          paramTypes[0]= String.class;
          paramTypes[1]= String.class;  

          Method set = SystemProperties.getMethod("set", paramTypes);

          //Parameters         
          Object[] params= new Object[2];
          params[0]= new String(key);
          params[1]= new String(val);

          set.invoke(SystemProperties, params);

        }catch( IllegalArgumentException iAE ){
            throw iAE;
        }catch( Exception e ){
            //TODO
        }

    }
}

这个可行吗?我尝试了SystemPropertiesProxy.get(this, "android.telephony.TelephonyProperties.PROPERTY_IMSI"); 但是返回为空。 - bruno.braga
@bruno.braga,这不是从SystemProperties获取的那种属性。要查看您可以通过此方式从设备获取哪些属性,请运行adb shell getprop - lapis
@Psycho,是的,我知道...这就是问题所在...对于我测试过的所有设备来说,getprop中都没有这个选项。这就是为什么我认为这根本不起作用。 - bruno.braga
运行得很顺畅!谢谢。 - NitZRobotKoder
5
根据您的代码,我无法通过set方法设置系统属性。我可以获取属性值,但无法设置。调用set方法时,并未抛出任何异常。我错过了什么?需要权限或其他设置吗? - Gino

39

这是Android源代码中的一个类:

https://android.googlesource.com/platform/frameworks/base/+/eclair-release/core/java/android/os/SystemProperties.java

在类JavaDoc中看到了{@hide}?这意味着该类不会作为公共SDK的一部分导出。

相机应用将其用作内部应用,他们不会使用公共SDK来构建它。

您仍然可以通过反射或获取源代码,删除@hide并制作自己的定制SDK来获取此类。

  1. 但几乎可以肯定地说,您现在已经“离开SDK”,因此您的应用可能会出现故障或在操作系统版本上产生不同的行为,因为Android团队很少努力在版本之间更改此类。


4
如果以上源代码链接无法使用,您可以尝试这个链接:http://androidxref.com/4.3_r2.1/xref/frameworks/base/core/java/android/os/SystemProperties.java - Vins
@Jim Blackler:您能详细解释一下第二种解决方案吗?我如何制作自己的SDK? - Milad Faridnia
在我的情况下,setProperty() 抛出异常 => https://stackoverflow.com/questions/71161044/android-os-systemproperties-does-not-save-values-during-junit-testing - Tajuddin Khandaker

28

用户Void发布的答案中有很多不必要的东西。这是我的类,它在android.os.SystemProperties上使用反射:

/*
 * Copyright (C) 2015 Jared Rummler
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Gives access to the system properties store. The system properties store contains a list of
 * string key-value pairs.
 */
public class SystemProperties {

  private static final Class<?> SP = getSystemPropertiesClass();

  /**
   * Get the value for the given key.
   */
  public static String get(String key) {
    try {
      return (String) SP.getMethod("get", String.class).invoke(null, key);
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * Get the value for the given key.
   *
   * @return if the key isn't found, return def if it isn't null, or an empty string otherwise
   */
  public static String get(String key, String def) {
    try {
      return (String) SP.getMethod("get", String.class, String.class).invoke(null, key, def);
    } catch (Exception e) {
      return def;
    }
  }

  /**
   * Get the value for the given key, returned as a boolean. Values 'n', 'no', '0', 'false' or
   * 'off' are considered false. Values 'y', 'yes', '1', 'true' or 'on' are considered true. (case
   * sensitive). If the key does not exist, or has any other value, then the default result is
   * returned.
   *
   * @param key
   *     the key to lookup
   * @param def
   *     a default value to return
   * @return the key parsed as a boolean, or def if the key isn't found or is not able to be
   * parsed as a boolean.
   */
  public static boolean getBoolean(String key, boolean def) {
    try {
      return (Boolean) SP.getMethod("getBoolean", String.class, boolean.class)
          .invoke(null, key, def);
    } catch (Exception e) {
      return def;
    }
  }

  /**
   * Get the value for the given key, and return as an integer.
   *
   * @param key
   *     the key to lookup
   * @param def
   *     a default value to return
   * @return the key parsed as an integer, or def if the key isn't found or cannot be parsed
   */
  public static int getInt(String key, int def) {
    try {
      return (Integer) SP.getMethod("getInt", String.class, int.class).invoke(null, key, def);
    } catch (Exception e) {
      return def;
    }
  }

  /**
   * Get the value for the given key, and return as a long.
   *
   * @param key
   *     the key to lookup
   * @param def
   *     a default value to return
   * @return the key parsed as a long, or def if the key isn't found or cannot be parsed
   */
  public static long getLong(String key, long def) {
    try {
      return (Long) SP.getMethod("getLong", String.class, long.class).invoke(null, key, def);
    } catch (Exception e) {
      return def;
    }
  }

  private static Class<?> getSystemPropertiesClass() {
    try {
      return Class.forName("android.os.SystemProperties");
    } catch (ClassNotFoundException shouldNotHappen) {
      return null;
    }
  }

  private SystemProperties() {
    throw new AssertionError("no instances");
  }

}

我发现set方法不起作用了。我的设备已经被root了。当我运行你的代码时,SuperSU应用程序没有出现获取权限的对话框。因此,我认为你的代码并没有真正触发su权限。 - hqt
@hqt 你需要在 shell 中运行 setprop。我应该删除 setprop 方法。 - Jared Rummler

17

您可以执行 getprop 命令:

String line = "";
try {
 Process ifc = Runtime.getRuntime().exec("getprop ro.hardware");
 BufferedReader bis = new BufferedReader(new InputStreamReader(ifc.getInputStream()));
 line = bis.readLine();
} catch (java.io.IOException e) {
}
ifc.destroy();

在getprop中没有IMEI/IMSI:https://guardianproject.info/wiki/Google_Nexus_S_I9023_running_stock_4.0.4 - bruno.braga
这是一个由accuya提供的示例:https://dev59.com/-2865IYBdhLWcg3wkfYW#11623309 - jk7

15

经过一番折腾,我终于让上面的反射代码能够设置并创建新的本机系统属性,但需要注意以下几点:

  1. 你需要成为系统用户,将android:sharedUserId="android.uid.system"添加到清单中。

  2. 你需要使用平台密钥签署APK,我作弊了,在eclipse中重写了默认的debug签名密钥,如下所示: http://stoned-android.blogspot.co.uk/2012_01_01_archive.html

  3. 本机系统属性服务有一个ACL来控制对属性的所有写访问权限,你可以规避键空间(例如sys.或debug.)。请参阅 /system/core/init/property_service.c:

    { "net.", AID_SYSTEM, 0 }, { "dev.", AID_SYSTEM, 0 }, { "runtime.", AID_SYSTEM, 0 }, { "hw.", AID_SYSTEM, 0 }, { "sys.", AID_SYSTEM, 0 }, { "service.", AID_SYSTEM, 0 }, { "wlan.", AID_SYSTEM, 0 }, { "dhcp.", AID_SYSTEM, 0 },

或者如果您正在自己构建系统,您可以添加自己的密钥,但似乎更容易重用上述密钥之一。


我已经完成了第1和第2项,但是它没有起作用。我需要做第3项吗?@Cakey - ziLk

8

以下是如何读取系统属性的方法,我还包含了一个后备方案:

import android.annotation.SuppressLint
import java.io.*
import java.lang.reflect.Method

object SystemProperties {
    private var failedUsingReflection = false
    private var getPropMethod: Method? = null

    @SuppressLint("PrivateApi")
    fun getProp(propName: String, defaultResult: String = ""): String {
        if (!failedUsingReflection) try {
            if (getPropMethod == null) {
                val clazz = Class.forName("android.os.SystemProperties")
                getPropMethod = clazz.getMethod("get", String::class.java, String::class.java)
            }
            return getPropMethod!!.invoke(null, propName, defaultResult) as String? ?: defaultResult
        } catch (e: Exception) {
            getPropMethod = null
            failedUsingReflection = true
        }
        var process: Process? = null
        try {
            process = Runtime.getRuntime().exec("getprop \"$propName\" \"$defaultResult\"")
            val reader = BufferedReader(InputStreamReader(process.inputStream))
            return reader.readLine()
        } catch (e: IOException) {
        } finally {
            process?.destroy()
        }
        return defaultResult
    }
}

使用反射比从进程输出中读取要快得多。 在我测试的某些设备上(小米Redmi 8),速度提高了约30倍。因此,值得尝试。

2

在进行大量搜索后,我找到了一种设置Android系统属性的方法。对于Android Lollipop版本,我无法找到解决方案。但是我成功地完成了此操作。要设置系统属性,我们需要使用:

import android.os.SystemProperties
SystemProperties.set(key, value).

例如:SystemProperties.set("sys.android", 5.0)

现在您需要为新系统属性授予权限。 前往 /home/inkkashy04/Android_Lollypop/external/sepolicy/property_contexts 并为您的属性授予适当的权限。

sys.android u:object_r:system_prop:s0

刷入映像后,您可以通过以下命令查看列出的系统属性:

adb shell getprop

0

Gradle 方法:

String SDK_DIR = System.getenv("ANDROID_SDK_HOME")
if(SDK_DIR == null) {
    Properties props = new Properties()
    props.load(new FileInputStream(project.rootProject.file("local.properties")))
    SDK_DIR = props.get('sdk.dir');
}
dependencies {
    compileOnly files("${SDK_DIR}/platforms/android-25/data/layoutlib.jar")
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接