一 一般步骤
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 层的设计。但基本的分层思想仍然保持不变。