通过android permission获取Linux guid权限

先来看一个实例,通过BLUETOOTH_STACK和DIAGNOSTIC permission获取linux的net_bt_stack和input guid权限

1.在app的AndroidManifest中声明如下permission,BLUETOOTH_STACK将应用加入到net_bt_stack用户组,可读写/dev/uinput设备,DIAGNOSTIC将应用加入到input组,可读写/dev/input/下的event设备

<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
<uses-permission android:name="android.permission.DIAGNOSTIC" />

2.用platform签名给应用apk签名
以上两个权限都是要platform签名的

java -jar out/host/linux-x86/framework/signapk.jar build/target/product/security/platform.x509.pem  build/target/product/security/platform.pk8  your_app.apk  your_app_signed.apk

3.安装应用apk,不需要安装到/system/app目录,按照普通app安装方式即可
当app运行起来的时候,app已经是input、net_bt_stack组了,可以操作对应的linux设备文件

用ps查看app运行时的进程号PID,查看/proc/PID/status文件,可以看到app所属的guid

添加自定义permission获取guid


为了使用方便,可能需要自定义permission
比如我们需要添加一个叫做“android.permission.CONTROL”的permission,可以在frameworks/base/data/etc/platform.xml,添加

<permission name="android.permission.CONTROL" >
    <group gid="net_bt_stack" />
    <group gid="input" />
</permission>

然后在app的AndroidManifest.xml中声明该permission,可参考frameworks/base/core/res/AndroidManifest.xml进行声明

<permission android:name="android.permission.CONTROL"
    android:protectionLevel="normal" />
protectionLevel可以使用normal、dangerous、signature、system以及signature|system的组合 如果需要添加新的guid,可以修改system/core/include/private/android_filesystem_config.h 可以将app的源代码集成到package/app/下与android代码一起编译,也可以使用app生成好的apk集成 参考《如何预置Android 手机 APK
如何将无源码的 APK 预置进系统? 1) 在 packages/apps 下面以需要预置的 APK 名字创建文件夹,以预置一个名为Test的APK为例 2) 将 Test.apk 放到 packages/apps/Test 下面 3) 在 packages/apps/Test 下面创建文件 Android.mk,文件内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Module name should match apk name to be installed
LOCAL_MODULE := Test
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
include $(BUILD_PREBUILT)
这样Test.apk将预制到/system/app/目录下 如果想预制到/data/data/下,可添加一行LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Module name should match apk name to be installed
LOCAL_MODULE := Test
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
include $(BUILD_PREBUILT)

在cubieboard2的android源码中,只需要将apk添加到android/device/softwinner/wing-common/preinstallapk/目录即可

烧写image到设备上,运行我们的app,就能获取到net_bt_stack和input guid权限了(经测试,预制到/data/分区不能成功,在/system/下可以成功;也可以单独写一个声明permission的app,预制到/system/app/下,其他app使用这个permission就能成功了)

注意:通过修改android设备中的/etc/permissions/platform.xml,并将app安装到设备(push到/system/app/或者安装到/data/data/)的方式不能成功,出现如下错误:

W/PackageManager(2330): Removing dangling permission: android.permission.CONTROL from package null
但通过在android源码中build的方式可以成功,可能跟没有清除数据有关
更新:直接修改android设备中的/etc/permissions/platform.xml,需要删除/data/system/packages.xml、/data/system/packages-backup.xml,重启之后重新扫描重构packages信息,这样就能成功获取permission对应的guid权限了 "packages.xml"在frameworks/base/services/java/com/android/server/pm/Settings.java中定义:
Settings(Context context, File dataDir) {
    mContext = context;
    mSystemDir = new File(dataDir, "system");
    mSystemDir.mkdirs();
    FileUtils.setPermissions(mSystemDir.toString(),
            FileUtils.S_IRWXU|FileUtils.S_IRWXG
            |FileUtils.S_IROTH|FileUtils.S_IXOTH,
            -1, -1);
    mSettingsFilename = new File(mSystemDir, "packages.xml");
    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
    mPackageListFilename = new File(mSystemDir, "packages.list");
    FileUtils.setPermissions(mPackageListFilename, 0660, SYSTEM_UID, PACKAGE_INFO_GID);

    // Deprecated: Needed for migration
    mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
    mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}

frameworks/base/services/java/com/android/server/pm/PackageManagerService.java中定义了isFirstBoot()


public PackageManagerService(Context context, boolean factoryTest, boolean onlyCore) {

mRestoredSettings = mSettings.readLPw(getUsers());

}

public boolean isFirstBoot() {
return !mRestoredSettings;
}

PMS会调用mSettings的readLPw,读取packages-backup.xml和packages.xml,如果不存在返回false,进而isFirstBoot()返回true

与抛出”Removing dangling permission”异常相关的代码位于PackageManagerService.java的updatePermissionsLPw()