安卓驱动是如何绕过linux GPL许可的

一 一般步骤

Android 驱动和 Linux GPL(GNU通用公共许可证)的关系确实存在一些争议和技术上的复杂性。让我们来深入探讨一下这个问题:

1. Linux 内核和 GPL:

Linux 内核是在 GPL v2 许可下发布的。根据 GPL 的要求,任何对 Linux 内核的修改或派生作品都必须以相同的许可证(GPL)发布源代码。

2. Android 和 Linux:

Android 使用了修改版的 Linux 内核作为其操作系统的核心。理论上,这意味着 Android 的内核修改应该遵循 GPL。

3. Android 驱动的特殊性:

然而,Android 设备制造商和芯片供应商经常需要为其硬件开发专有驱动程序,他们不愿意公开这些驱动的源代码。

4. 绕过 GPL 的方法:

Android 生态系统采用了几种方法来处理这个问题:

   a) 内核模块:
   - 许多 Android 驱动被实现为可加载的内核模块,而不是直接集成到内核中。
   - 有争议的观点认为,这些模块可以被视为独立的程序,不受 GPL 的约束。

   b) 用户空间驱动:
   - 一些功能被移到用户空间,通过库和服务来实现,而不是作为内核驱动。
   - 用户空间的代码不受 GPL 的约束。

   c) 稳定的二进制接口:
   - Google 尝试维护一个稳定的内核接口,允许设备制造商提供二进制驱动而不需要修改内核源代码。

   d) 法律解释:
   - 一些公司认为,只要不分发修改后的内核源代码,就不违反 GPL。
   - 这种解释存在争议,并未得到开源社区的广泛认可。

5. 争议和讨论:

这种做法在开源社区中引发了很多争议。一些人认为这违反了 GPL 的精神,而另一些人认为这是在现实商业需求和开源理念之间的必要妥协。

6. 法律灰色地带:

目前,这个问题仍然处于法律的灰色地带。尚未有重大的法律案例来明确界定这些做法的合法性。

7. 开源倡导:

一些组织,如自由软件基金会(FSF),一直在倡导更严格地遵守 GPL,但在实践中改变现状面临着挑战。

总的来说,Android 生态系统在处理驱动程序和 GPL 兼容性问题上采取了一种实用主义的方法。这种方法允许了 Android 的广泛采用和商业成功,但也引发了关于开源软件许可和商业利益之间平衡的持续讨论。

这个话题涉及技术、法律和商业多个方面,仍在不断演变中。如果您对这个话题特别感兴趣,我建议深入研究相关的法律文献和技术讨论,以获得更全面的理解。
 

二 抽象举例分析

一些 Android 驱动程序如何在实践中"绕过" GPL 的具体方法。请注意,这些方法在法律和道德上可能存在争议,我们这里只是从技术角度进行讨论。

1. 用户空间驱动实现

这是一种常见的方法,将驱动程序的大部分功能移到用户空间,只在内核中保留最小的接口。
```

// kernel_driver.c (GPL许可的内核模块)
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "mydevice"

static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);

static struct file_operations fops = {
    .read = device_read,
    .write = device_write,
    .open = device_open,
    .release = device_release
};

static int major_num;

static int __init mydevice_init(void) {
    major_num = register_chrdev(0, DEVICE_NAME, &fops);
    if (major_num < 0) {
        printk(KERN_ALERT "Failed to register a major number\n");
        return major_num;
    }
    printk(KERN_INFO "mydevice: registered successfully with major number %d\n", major_num);
    return 0;
}

static void __exit mydevice_exit(void) {
    unregister_chrdev(major_num, DEVICE_NAME);
    printk(KERN_INFO "mydevice: unregistered successfully\n");
}

module_init(mydevice_init);
module_exit(mydevice_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver");

// userspace_driver.cpp (专有代码,不受GPL约束)
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>

class MyDeviceDriver {
public:
    MyDeviceDriver() {
        fd = open("/dev/mydevice", O_RDWR);
    }

    ~MyDeviceDriver() {
        if (fd >= 0) close(fd);
    }

    bool doSomething() {
        // 实现专有的驱动功能
        char buffer[256];
        return read(fd, buffer, sizeof(buffer)) > 0;
    }

private:
    int fd;
};

// 在Android应用中使用
void someAndroidFunction() {
    MyDeviceDriver driver;
    if (driver.doSomething()) {
        // 处理结果
    }
}

```
在这个例子中,内核模块(`kernel_driver.c`)提供了一个最小的接口,而实际的驱动功能在用户空间(`userspace_driver.cpp`)中实现。这样,专有的驱动代码就不受 GPL 的约束。

2. 稳定的二进制接口

Google 尝试通过维护稳定的内核接口来允许使用闭源的二进制驱动。
```

// In the Linux kernel (GPL)
struct mydevice_ops {
    int (*init)(void);
    void (*cleanup)(void);
    ssize_t (*read)(char __user *buf, size_t count);
    ssize_t (*write)(const char __user *buf, size_t count);
};

extern int register_mydevice(struct mydevice_ops *ops);
extern void unregister_mydevice(void);

// In the proprietary binary driver (not GPL)
#include "mydevice_interface.h"

static int my_init(void) {
    // Proprietary initialization code
}

static void my_cleanup(void) {
    // Proprietary cleanup code
}

static ssize_t my_read(char __user *buf, size_t count) {
    // Proprietary read implementation
}

static ssize_t my_write(const char __user *buf, size_t count) {
    // Proprietary write implementation
}

static struct mydevice_ops my_ops = {
    .init = my_init,
    .cleanup = my_cleanup,
    .read = my_read,
    .write = my_write
};

int init_module(void) {
    return register_mydevice(&my_ops);
}

void cleanup_module(void) {
    unregister_mydevice();
}

```
在这个例子中,内核提供了一个稳定的接口(`struct mydevice_ops`),专有驱动可以实现这个接口而不需要修改内核源代码。

3. 使用 HIDL (Hardware Interface Definition Language)

Android 还引入了 HIDL 来定义硬件抽象层,进一步分离专有实现和开源代码。
```

// IMyDevice.hal (HIDL interface definition)
package android.hardware.mydevice@1.0;

interface IMyDevice {
    doSomething() generates (bool success);
};

// MyDevice.cpp (Proprietary implementation)
#include <android/hardware/mydevice/1.0/IMyDevice.h>

namespace android {
namespace hardware {
namespace mydevice {
namespace V1_0 {
namespace implementation {

struct MyDevice : public IMyDevice {
    Return<bool> doSomething() override {
        // Proprietary implementation
        return true;
    }
};

}  // namespace implementation
}  // namespace V1_0
}  // namespace mydevice
}  // namespace hardware
}  // namespace android

// Usage in Android framework (open source)
#include <android/hardware/mydevice/1.0/IMyDevice.h>

void useMyDevice() {
    android::sp<IMyDevice> myDevice = IMyDevice::getService();
    if (myDevice != nullptr) {
        bool result = myDevice->doSomething();
        // Handle result
    }
}

```
这种方法使用 HIDL 定义了一个接口(`IMyDevice.hal`),专有实现(`MyDevice.cpp`)可以实现这个接口,而 Android 框架使用这个通用接口而不需要知道具体实现。

这些例子展示了 Android 生态系统如何在技术层面上处理专有驱动和开源内核之间的关系。然而,需要再次强调的是,这些方法的法律地位仍然存在争议,并且可能不完全符合 GPL 的精神。在实际应用中,公司需要仔细考虑法律和道德影响。
 

三 以摄像头驱动举例所有层次分析

安卓驱动封装和调用 Linux 驱动是一个多层次的过程,涉及几个不同的抽象层。让我们逐层解析这个过程:

1. Linux 内核层

首先,最底层是 Linux 内核驱动。这些驱动直接与硬件交互,并遵循标准的 Linux 驱动模型。

2. HAL (Hardware Abstraction Layer) 层

HAL 是 Android 特有的一层,它位于 Linux 内核驱动之上。HAL 的主要目的是为上层提供一个统一的接口,同时隐藏底层硬件的具体细节。

3. JNI (Java Native Interface) 层

JNI 层允许 Java 代码调用 C/C++ 代码,反之亦然。它是连接 Java 框架和底层 native 代码的桥梁。

4. Java 框架层

这是大多数 Android 应用开发者直接交互的层。它提供了高级 API 供应用使用。

让我们通过一个具体的例子来说明这个过程,以相机驱动为例:
```

// 1. Linux Kernel Driver (camera.c)
#include <linux/module.h>
#include <linux/fs.h>

static int camera_open(struct inode *inode, struct file *file) {
    // 实现相机硬件初始化
    return 0;
}

static int camera_release(struct inode *inode, struct file *file) {
    // 实现相机硬件关闭
    return 0;
}

static long camera_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    // 实现相机控制命令
    switch(cmd) {
        case CAMERA_TAKE_PICTURE:
            // 拍照逻辑
            break;
        // 其他命令...
    }
    return 0;
}

static struct file_operations camera_fops = {
    .owner = THIS_MODULE,
    .open = camera_open,
    .release = camera_release,
    .unlocked_ioctl = camera_ioctl,
};

// 2. HAL Layer (camera_hal.cpp)
#include <hardware/camera.h>

static camera_device_t *camera_device = NULL;

static int camera_device_open(const hw_module_t* module, const char* name,
                              hw_device_t** device) {
    camera_device = (camera_device_t*)malloc(sizeof(camera_device_t));
    // 初始化 camera_device
    *device = (hw_device_t*)camera_device;
    return 0;
}

static int camera_take_picture(camera_device_t *dev) {
    // 调用内核驱动拍照
    int fd = open("/dev/camera", O_RDWR);
    ioctl(fd, CAMERA_TAKE_PICTURE, 0);
    close(fd);
    return 0;
}

static camera_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .module_api_version = CAMERA_MODULE_API_VERSION_2_0,
        .hal_api_version = HARDWARE_HAL_API_VERSION,
        .id = CAMERA_HARDWARE_MODULE_ID,
        .name = "Camera HAL",
        .author = "Android Open Source Project",
        .methods = &camera_module_methods,
    },
    .get_number_of_cameras = camera_get_number_of_cameras,
    .open = camera_device_open,
};

// 3. JNI Layer (android_hardware_Camera.cpp)
#include <jni.h>
#include <camera/Camera.h>

static jint android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) {
    sp<Camera> camera = Camera::getCamera();
    return camera->takePicture();
}

static JNINativeMethod camMethods[] = {
    {"_takePicture", "()I", (void*)android_hardware_Camera_takePicture},
};

// 4. Java Framework (Camera.java)
public class Camera {
    private static native final int _takePicture();
    
    public void takePicture() {
        int result = _takePicture();
        // 处理结果
    }
}

// 5. Android Application
public class CameraActivity extends Activity {
    private Camera mCamera;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mCamera = Camera.open();
    }

    public void onCaptureClick(View view) {
        mCamera.takePicture();
    }
}

```
这个例子展示了从 Android 应用到 Linux 内核驱动的整个调用链:

1. 应用层调用 `Camera.takePicture()`
2. 这个调用通过 JNI 传递到 native 代码
3. Native 代码通过 HAL 接口与相机 HAL 交互
4. 相机 HAL 最终通过系统调用(如 `open()`, `ioctl()`)与 Linux 内核驱动交互

这种分层设计有几个优点:

1. 抽象:上层代码不需要了解底层硬件的具体细节。
2. 兼容性:不同的硬件可以使用相同的上层接口。
3. 安全性:应用无法直接访问硬件,需要通过系统 API。
4. 灵活性:硬件制造商可以提供自己的 HAL 实现,而不影响上层代码。

需要注意的是,随着 Android 版本的演进,这个架构也在不断发展。例如,较新的 Android 版本引入了 HIDL (Hardware Interface Definition Language) 来进一步改进 HAL 层的设计。但基本的分层思想仍然保持不变。
 

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值