android shell hello world,Android Framework 之HelloWorld(三)

本来是要写一个linux驱动,用于控制led灯的,但考虑到nanopc-T4的内核已经帮我们配置好设备树,已经可以利用/sys/class/gpio操作gpio了,所以没必要再造轮子了!

在shell里,可以利用下面的命令控制Led灯的亮与灭:

#导出GPIO0_A0管脚

echo 32 > /sys/class/gpio/export

#让GPIO0_A0管脚作为输出使用

echo out > /sys/class/gpio/gpio32/direction

#GPIO0_A0输出高电平

echo 1 > /sys/class/gpio/gpio32/value

#GPIO0_A0输出低电平

echo 0 > /sys/class/gpio/gpio32/value

接上串口或者adb shell进去shell终端,先来看下export的用户和组:

nanopc-t4:/ $ ls -l /sys/class/gpio/

total 0

--w--w---- 1 root system 4096 2020-08-22 04:50 export

lrwxrwxrwx 1 root root 0 2020-08-22 07:48 gpio156 -> ../../devices/platform/pinctrl/gpio/gpio156

lrwxrwxrwx 1 root root 0 2020-08-22 07:48 gpiochip0 -> ../../devices/platform/pinctrl/gpio/gpiochip0

lrwxrwxrwx 1 root root 0 2020-08-22 07:48 gpiochip128 -> ../../devices/platform/pinctrl/gpio/gpiochip128

lrwxrwxrwx 1 root root 0 2020-08-22 07:48 gpiochip32 -> ../../devices/platform/pinctrl/gpio/gpiochip32

lrwxrwxrwx 1 root root 0 2020-08-22 07:48 gpiochip64 -> ../../devices/platform/pinctrl/gpio/gpiochip64

lrwxrwxrwx 1 root root 0 2020-08-22 07:48 gpiochip96 -> ../../devices/platform/pinctrl/gpio/gpiochip96

--w--w---- 1 root system 4096 2020-08-22 04:50 unexport

可以看出,export是普通文件,拥有者具有“写”权限,组内其他成员具有“写”权限,其他用户则没有任何权限,export属于root用户,所属组为system。

android8.1定义了很多用户,我们可以在shell里使用“ps -ef”,随机截取了几个就有root,shell,system、u0_a59等用户了。

#随机截取了几个

$ps -ef

...

webview_zygote 660 1 0 04:50:44 ? 00:00:00 webview_zygote32

radio 689 363 0 04:50:44 ? 00:00:00 com.android.phone

system 1120 363 0 04:50:48 ? 00:00:00 android.rockchip.update.service

root 3694 1 0 05:08:17 ? 00:00:03 adbd --root_seclabel=u:r:su:s0

root 13893 3694 0 07:45:05 136:0 00:00:00 logcat -v long -v epoch

u0_a59 13962 363 1 07:45:22 ? 00:00:02 com.demo.helloworld

shell 14478 14087 36 07:53:04 ttyFIQ0 00:00:00 ps -ef

...

所以我们要操作/sys/class/gpio/export,至少也要将app提升至system用户权限,apk在安装时,会根据AndroidManifest.xml的android:sharedUserId="android.uid.system"属性进行分配用户权限,查了一些资料,如果要让app具有system权限,有两种方法,一是将app放进android源码上使用mm DEX_PREOPT_DEFAULT=nostripping编译,还有就是使用签名,我们这里使用签名的方式:

先设置AndroidManifest.xml的android:sharedUserId="android.uid.system"属性

在编译android源码后,在此处得到如下文件:

./build/make/target/product/security/platform.pk8

./build/make/target/product/security/platform.x509.pem

每次编译android源码这两个文件都不变,可以拷贝出来使用。

而signapk.jar则存在于这两个地方:

./out/host/linux-x86/framework/signapk.jar和./prebuilts/sdk/tools/lib/signapk.jar,这两个signapk.jar的区别我不清楚,不过猜测使用前者会好一点,毕竟是编译输出的。

把上面的三个文件拷贝出来,如果使用./out/host/linux-x86/framework/signapk.jar,则使用如下命令生成签名后的apk安装包:

java -Djava.library.path=rk3399-android-8.1/out/host/linux-x86/lib64 -jar signapk.jar platform.x509.pem platform.pk8 app-debug.apk system.apk

如果使用./prebuilts/sdk/tools/lib/signapk.jar,则使用如下命令生成签名后的apk安装包:

java -Djava.library.path=../rk3399-android-8.1/prebuilts/sdk/tools/linux/lib64/ -jar signapk.jar platform.x509.pem platform.pk8 app-debug.apk system.apk

我在ibledctrl.so里加入WriteFileValue()函数用于操作gpio:

#include

#include

static int WriteFileValue(const char *pPath, char *pValue, int len)

{

int fd = -1;

if(!pPath || !pValue)

{

return -1;

}

PRINT_DEBUG("open %s value = %s, len = %d", pPath, pValue, len);

fd = open(pPath, O_RDWR);

if (fd < 0)

{

PRINT_DEBUG("open %s error: %d,%s", pPath, fd, strerror(errno));

return fd;

}

if (len != write(fd, pValue, len))

{

PRINT_DEBUG("write error: %d,%s", fd, strerror(errno));

close(fd);

return -1;

}

close(fd);

return 0;

}

jint LedInit(JNIEnv *env, jobject cls)

{

PRINT_DEBUG("Entry LedInit ...");

char *export = "32";

char *direction = "out";

WriteFileValue("/sys/class/gpio/export", export, strlen(export)+1);

WriteFileValue("/sys/class/gpio/gpio32/direction", direction, strlen(direction)+1);

return 0;

}

可惜的是,即使app以system用户运行也没权限操控/sys/class/gpio/export,使用chown system:system /sys/class/gpio/export使之处于同一“owner”也不够权限。可能是SElinux的权限管理问题,android源码中允许对某些驱动文件节点进行更细化的权限管理,这块我还需要好好学习。因为我使用下面的命令"whoami”或者“dumpsys activity top”获取到当前界面所处用户确实是system用户了,这说明使用签名的方式提升到system权限是没问题的:

import android.util.Log;

import java.io.BufferedReader;

import java.io.DataOutputStream;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

private void Run(String cmd)

{

try {

Process process = Runtime.getRuntime().exec("sh"); //su

// 获取输出流

OutputStream outputStream = process.getOutputStream();

InputStream is = process.getInputStream();

InputStream es = process.getErrorStream();

DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

dataOutputStream.writeBytes(cmd);

dataOutputStream.flush();

dataOutputStream.close();

outputStream.close();

int code = process.waitFor();

Log.d("TAG", "Run:\"" + cmd +"\", "+"process.waitFor() = " + code);

String line;

BufferedReader br;

br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

while ((line = br.readLine()) != null) {

Log.d("TAG", line);

}

br = new BufferedReader(new InputStreamReader(es, "UTF-8"));

while ((line = br.readLine()) != null) {

Log.e("TAG", line);

}

} catch (Throwable t) {

Log.e("TAG", "Throwable = " + t.getMessage());

t.printStackTrace();

}

}

...

...

Run("whoami"); //获取当前进程是属于哪个用户

//或者在shell中使用dumpsys

我发现如果在root用户下预先运行chmod 777 /sys/class/gpio/export和chown system:system /sys/class/gpio/export命令后,再重启app,就能操控led灯了,这我就不理解了。

如你所见,这个HelloWorld是失败的,没能达到要求,同时在android的权限管理方面没能解释清楚!

来源:oschina

链接:https://my.oschina.net/u/4345458/blog/4525802

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值