无法连接到 android 5.1 上的本机本地套接字

Posted

技术标签:

【中文标题】无法连接到 android 5.1 上的本机本地套接字【英文标题】:Cannot connect to native local socket on android 5.1 【发布时间】:2015-06-26 08:26:55 【问题描述】:

我有命令行工具,可以发送广播和等待结果。

服务器代码(省略错误处理):

    int makeAddr(const char* name, struct sockaddr_un* pAddr, socklen_t* pSockLen)
    
        int nameLen = strlen(name);
        pAddr->sun_path[0] = '\0';
        strcpy(pAddr->sun_path+1, name);
        pAddr->sun_family = AF_LOCAL;
        *pSockLen = 1 + nameLen + offsetof(struct sockaddr_un, sun_path);
        return 0;
    

    int main(int argc, char* argv[])
    
        //...

        // Create socket in abstract namespace
        struct sockaddr_un sockAddr = 0;
        socklen_t sockLen;
        makeAddr("SOCKET_NAME", &sockAddr, &sockLen);

        int serverFd = socket(AF_LOCAL, SOCK_STREAM, PF_UNIX));

        bind(serverFd, (const struct sockaddr*) &sockAddr, sockLen);

        listen(serverFd, 5);

        //set socket non-blocking
        int flags = fcntl(serverFd, F_GETFL, 0);
        fcntl(serverFd, F_SETFL, flags | O_NONBLOCK);

        pollfd pollFd = 0;
        pollFd.fd = serverFd;
        pollFd.events = POLLIN | POLLRDHUP;

        // Send brodcast 
        system("am broadcast ...");

        for(;;)
        
            // Wait result 
            int pollResult = poll(&pollFd, 1, timeout);
        // Process result

Java 客户端代码:

public class CommandReceiver extends BroadcastReceiver

    @Override
    public void onReceive(Context context, Intent intent) 

            LocalSocket socket = new LocalSocket();
            LocalSocketAddress address = new LocalSocketAddress("SOCKET_NAME", LocalSocketAddress.Namespace.ABSTRACT);
            socket.connect(address);

            // Do something and send result asynchronously 

这一切都适用于 5.1 之前的 android

在 android 5.1 上 connect() 抛出异常:

java.io.IOException: 权限被拒绝

在 android.net.LocalSocketImpl.connectLocal(Native Method)

在 android.net.LocalSocketImpl.connect(LocalSocketImpl.java:290)

在 android.net.LocalSocket.connect(LocalSocket.java:130)

日志中有错误:

9月7日至27日:56:08.179:W:类型= 1400审计(0.0:3675):AVC:拒绝connectto为路径= 00636F6D2E6B6173706572736B792E6B617368656C6C2E534F434B45542D36313838363731373231343337393833373637 scontext = U:R:untrusted_app:S0 tcontext = U:R:壳:s0 tclass=unix_stream_socket 许可=0

我找到了相关的 android 修复: https://android.googlesource.com/device/moto/shamu/+/b2db40f

那么,从 android 5.1 开始,它就不再工作了吗? 我能做什么(也许以某种方式设置权限)? 或者是否有另一种机制可以从本机命令行工具发送数据并等待结果?

【问题讨论】:

【参考方案1】:

使用管道代替套接字: O_RDWR on named pipes with poll()

在java进程中创建管道:

        mkfifo(cpath, 0);
        chmod(cpath, S_IRWXU|S_IROTH|S_IRGRP);

在本机进程中打开管道:

int serverFd = open(PIPE_NAME, O_RDONLY | O_NONBLOCK);
pollfd pollFd = 0;
pollFd.fd = serverFd.get();
pollFd.events = POLLIN | POLLRDHUP;

// send command
....

for(;;)

    int pollResult = poll(&pollFd, 1, timeout);

【讨论】:

【参考方案2】:

根据我在 Android 10 上的经验,抽象命名空间 unix 域套接字和未命名管道在同一个应用程序中工作,但不能跨不同的应用程序工作。不过,我同时实现了客户端和服务器 natively。

对于命名管道,您必须在具有写入权限的地方创建文件。基本上是您应用的数据文件夹。

对于进程间通信,您可以尝试将文件描述符从一个进程发送到另一个进程以根据this 授予访问权限,但我不确定它是如何工作的。我最终为此使用了网络套接字。

【讨论】:

以上是关于无法连接到 android 5.1 上的本机本地套接字的主要内容,如果未能解决你的问题,请参考以下文章

Android 模拟器无法连接到本地服务器(未指定输入文件)

Laravel 5.1 SSH - 无法连接到远程服务器

我已经创建了 React 本机应用程序并将其构建为独立的 android apk 文件,但如果不连接到同一网络,我将无法使用它

无法在 iOS 15 上将本机应用程序连接到后端

Android LocalSocket客户端无法连接到抽象命名空间中的本机服务套接字

如何从不同网络上的android连接到本地apache服务器?(端口转发)