精华内容
下载资源
问答
  • 竞品分析五层分析

    千次阅读 2021-01-12 16:06:04
    调研竞品和市场,找到自己的赛道 一.竞品分析的意义 做产品是一件如履薄冰的事情,需要摸着石头过河 过河:目标 水:不确定性,液态 ...三,产品五层分析法 战略层:企业愿景,产品定位,需求把控,用户习惯;商业

    调研竞品和市场,找到自己的赛道

    一.竞品分析的意义

    做产品是一件如履薄冰的事情,需要摸着石头过河
    过河:目标
    水:不确定性,液态
    石头:不确定性中难能可贵的确定性

    竞品分析的意义:
    确定的需求,成为河水中的石头
    验证失败的,会成为河水中的枯骨
    确定性足够了,石头多了,就成了桥

    二,九大维度

    市场趋势,业界现状
    竞争对手的企业愿景,产品定位以及发展战略
    目标用户
    市场数据
    核心功能
    交互设计
    产品优缺点
    运营以及推广策略
    总结和行动点

    三,产品五层分析法

    产品五层分析法
    战略层:企业愿景,产品定位,需求把控,用户习惯;商业模式
    范围层:主要功能,核心功能,次级功能,功能架构,业务流程设计
    结构层:信息架构层,常规功能,特色功能,实现情况,用户流程分析
    框架层:操作情况,刷新,页面跳转,查询,交互框架,界面设计,导航设计,标签设计,细节点
    表现层:视觉表现,布局,配色,排版

    案例:长视频产品
    战略层:
    1.企业目标:会员收益比广告收益更好;会员有更高粘性
    2.用户需求:更优质的观看体验;更快的更新

    范围层:
    1.内容需求:更多用户喜欢的视频资源
    2.功能结构:会员去不去广告,体验清晰度和是否有蓝光

    结构层:
    1.特色功能:爱奇艺推荐有礼返现金;腾讯视频,开会员送红包

    框架层:
    1.用户操作流程:是否一个界面就完成会员充值

    表现层:
    1.UI设计

    参考资料:高玮《产品经理思维训练营》

    展开全文
  • 产品设计的个层次 1、战略:明确商业目标和用户需求,找准方向,重点是解决两者之间的冲突,找到平衡点。产品经理要进行调研,包括用户调研、市场调研、竞品分析等,这也是所有产品的开端。做产品战略调研时,...

    用户体验五要素

    分为 功能型产品信息型产品
    在这里插入图片描述

    1. 战略层

    (1)产品目标

    • 很多人称之为 “商业目标” 或 “商业驱动因素”;
    • 对于任何一个网站,需要明确描述的基础之一是品牌识别品牌识别——可以是概念系统,也可以是情绪反应——重要的原因在于它无法不被用户注意,深深地印在用户脑海中。
    • 成功标准——是否满足自己的目标和用户需求。

    (2)用户需求

    • 进行用户调研(首先根据不同的用户群体进行用户细分
    • 方法:
      市场调研(问卷调查、用户访谈、焦点小组)——获取用户基本信息;
      现场调查——用户了解用户行为;
      用户测试——可进行产品优化改版。

    产出:战略文档——简洁明了并切入重点,帮助其他人(设计师、程序员、信息架构师、项目经理)做出正确的决定


    1. 范围层
      分为两个部分:功能规格内容需求

    (1)功能型产品

    • 需求定义
    • 功能规格说明——不需要包含细节,只包含在设计或开发中出现有可能出现混淆的功能定义,只记录创建产品时 已经确定下来的决议。
    • 撰写规则:乐观(不允许XXX改为引导XXX)、具体(解释清楚)、明确(避免歧义)。

    (2)信息型产品

    • 内容需求——内容清单(明确每个人负责的部分)
    • 确定需求的优先级——评估需求是否能满足战略目标(战略目标对需求是一对多的关系)

    1. 结构层
      两部分:交互设计信息架构
      交互设计和信息架构都强调一个重点:确定各个将要呈现给用户的元素的 “模式” 和 “顺序”。交互设计关注于将影响用户执行和完成任务的元素,信息架构则关注如何用户表达给用户的元素。

    (1)功能型产品

    • 交互设计——可能的用户行为,系统如何配合与响应。
    • 概念模型——交互组件如何工作。
    • 错误处理—— “ 撤销 ” 功能、提示信息等。

    (2)信息型产品

    • 信息架构——呈现给用户的信息是否合理并有意义。
    • 结构方法:基本单位是节点。层级结构(树或中心辐射)、矩阵结构、自然结构、线性结构。
    • 组织原则:节点编组、命名规则等。

    1. 框架层
      对于功能型产品通过界面设计来确定框架,对于信息型产品要解决唯一问题:导航设计信息设计两种产品都要做。
    • 界面设计——让用户一眼看出“最重要东西”。第一次呈现给用户时指定默认值。

    • 导航设计
      三个目标:
      ① 必须提供给用户在网站间跳转的方法;
      ② 必须传达出这些元素和他们所包含内容之间的联系;
      ③ 必须传达出它的内容的用户当前浏览页面之间的关系。
      几种导航系统:
      全局导航、局部导航、辅助导航、上下文导航、友好导航、远程导航(网站地图、索引表)

    • 信息设计——如何呈现信息,使用户更好的理解。
      信息设计和导航设计结合到一起的作用: 指示标识
      线框图:(原型图)——完成详细文档。


    1. 视觉层
      感知设计
      对比和一致性
      配色和排版

    各个层次之间界限模糊,彼此交叉,需要反复迭代


    参考
    在这里插入图片描述

    展开全文
  • Android HAL 层框架分析以及代码示例

    千次阅读 多人点赞 2019-02-22 16:04:53
    本文参考 《Android系统源代码情景分析》 一 硬件抽象概述 二 开发Android硬件驱动程序 三 开发Android硬件抽象模块 3.1 硬件抽象模块文件 命名规范 3.2 硬件抽象模块结构体 以及 硬件抽象设备...

    本文拜读参考自罗升杨老师的 《Android系统源代码情景分析》

    本文代码实验平台为 Android7.1

    一 硬件抽象层概述
    二 开发Android硬件驱动程序
    三 开发Android硬件抽象层模块
    • 3.1 硬件抽象层模块文件 命名规范
    • 3.2 硬件抽象层模块结构体 以及 硬件抽象层设备结构体 定义规范
    • 3.3 编写硬件抽象层模块接口
    为Android硬件抽象层编写JNI方法供硬件服务程序调用
    • 4.1 JNI实现
    • 4.2 声明JNI注册方法
    • 4.3 添加JNI方法代码
    五 开发Android硬件访问服务
    • 5.1 定义硬件访问服务接口
    • 5.2 实现硬件访问服务 最后 启动硬件访问服务
    六 开发Android应用程序来使用硬件访问服务

    一 硬件抽象层概述

    Android系统的硬件抽象层(Hardware Abstract Layer, HAL)运行在用户空间中,它向下屏蔽硬件驱动模块的实现细节,向上提供硬件访问服务。通过硬件抽象层,Android系统分为两层来支持硬件设备,其中一层实现在用户空间(User Space),另外一层是现在内核空间(Kernel Space)。传统的Linux系统把对硬件的支持完全是现在在内核空间,即把对硬件的支持完全实现在硬件驱动模块中。

    问题:Android系统为什么要把对硬件的支持划分为两层来实现呢?把硬件抽象层和内核驱动整合在一起放在内核空间不可行吗?从技术实现的角度来看,是可以的,然而从商业的角度来看,把对硬件的支持逻辑都放在内核空间,可能会损害厂家的利益。我们知道Linux内核源代码是遵循GPL协议的,如果我们在Android系统所使用的Linux内核中添加或者修改了代码,那么就必须将其公开,所以,如果Android系统想Linux系统一样,把对硬件的支持完全完全是现在linux硬件驱动中,那么就是说这些实现是开源的,相当于暴露的硬件的实现细节和参数,损伤了厂商的利益。因此,Android才会想到把对硬件的支持分成硬件抽象层和内核驱动层,内核驱动层只提供简单的访问硬件逻辑,例如读写硬件寄存器的通道,至于从硬件中读到了什么值或者写了什么值到硬件中的逻辑,都放在硬件抽象层中去了,这样就可以把商业秘密隐藏起来了。也正是由于这个分层的原因,Android被踢出了Linux内核主线代码树中。

    先来一张代码概览图镇楼:

    在这里插入图片描述

    在这里插入图片描述

    二 开发Android硬件驱动程序

    为了方便描述,我们将为一个虚拟的字符硬件设备开发去驱动程序,这个虚拟的字符硬件设备只有一个寄存器,它的大小为4个字节,可读可写,由于这个字符设备是虚拟的,而且只有一个寄存器,因此我们将它命名为 fake register,并且将其对应的驱动名称命名为 freg。

    具体驱动程序 :

    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/ioctl.h>
    #include <linux/mm.h>
    #include <asm/uaccess.h>
    #include <linux/blkdev.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/kdev_t.h>
    #include <linux/slab.h>
    #include <linux/string.h>
    #include <linux/major.h>
    #include <linux/errno.h>
    #include <linux/module.h>
    #include <linux/seq_file.h>
    #include <linux/kobject.h>
    #include <linux/kobj_map.h>
    #include <linux/cdev.h>
    #include <linux/mutex.h>
    #include <linux/backing-dev.h>
    #include <linux/tty.h> 
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/delay.h>
    #include <linux/hrtimer.h>
    #include <linux/i2c.h>
    #include <linux/input.h>
    #include <linux/interrupt.h>
    #include <linux/io.h>
    #include <linux/platform_device.h>
    #include <linux/async.h>
    #include <linux/irq.h>
    #include <linux/workqueue.h>
    #include <linux/proc_fs.h>
    #include <linux/input/mt.h>
    #include <linux/of_gpio.h>
    #include <linux/gpio.h>
    #include <linux/slab.h>
    #include <linux/device.h>
    
    int CDRIVER_MAJOR=0;
    int CDRIVER_MINOR=0;
    static struct class *freg_class = NULL;
    
    static ssize_t freg_read(struct file *filp, char *buffer, size_t count, loff_t *ppos);
    static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);
    static int freg_open(struct inode *inode,struct file *filp);
    static int freg_release(struct inode* inode, struct file* filp);
    
    
    static ssize_t freg_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
    static ssize_t freg_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n);
    
    
    struct Freg_struct{
    	//struct semaphore sem;//信号量
    	struct mutex mutex;//互斥锁
    	struct cdev freg_cdev;
    	char val;
    };
    struct Freg_struct *freg_struct = NULL; /*设备结构体指针*/
    
    static struct kobject *freg_kobj;
    
    struct  Freg_Attribute0 {
    	struct attribute	attr;
    	ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
    			char *buf);
    	ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
    			const char *buf, size_t n);
    };
    
    static struct  Freg_Attribute0 freg_attribute[] = {
      //__ATTR(device name,	S_IRUGO | S_IWUSR,	hdmiin_test_show,	hdmiin_test_store),
    	__ATTR(freg_dev, 0660,	freg_show, freg_store),
    };
    
    
    static ssize_t freg_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
    {
    	int val = 0;
    	struct Freg_struct dev;
    	
    	mutex_lock(&dev.mutex);
    	val = dev.val;
    	mutex_unlock(&dev.mutex);
    	return snprintf(buf, PAGE_SIZE, "%d\n", val);
    }
    
    static ssize_t freg_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n)
    {
    	struct Freg_struct dev;
    	
    	mutex_lock(&dev.mutex);
    	dev.val = *buf;  
    	mutex_unlock(&dev.mutex);
    	
    	return 0;
    }
    
    
    
    static ssize_t freg_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
    {
        int ret;
    	struct Freg_struct* freg_str = filp->private_data;
    
    	mutex_lock(&freg_str->mutex);
     
        ret=copy_to_user(buffer, (char *)&freg_str->val, sizeof(freg_str->val)); 
        if(ret<0)
        {
            printk("ret =%d \n",ret);
            return ret;
        }
    	
    	mutex_unlock(&freg_str->mutex);
    	
       return 0;
    }
    
    static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos)
    {
    	struct Freg_struct* freg_str = filp->private_data;
    	int err;
    	
    	mutex_lock(&freg_str->mutex);
    	
    	err=copy_from_user(&(freg_str->val), buf, count);
        if(err<0)
        {
            printk("ret =%d \n",err);
            return err;
        }
    	
    	mutex_unlock(&freg_str->mutex);
    	return 0;
    }
     
    static int freg_open(struct inode *inode,struct file *filp)
    {
    	struct Freg_struct* freg_str;
    	
    	//对于一个字符设备文件, 其inode->i_cdev 指向字符驱动对象cdev,已知 inode->i_cdev(freg_cdev)字符设备地址,以及名称freg_cdev,返回 类型为 Freg_struct 的结构的首地址
    	// 需要注意的是 container_of 第三个参数是一个普通变量,并非指针。所以本程序中的字符设备的 struct cdev 定义的是一个普通的 cdev变量,
    	 //  而初始化cdev 的方式也必须是静态方法,因为动态方式使用的是 cdev 的指针变量。
    	freg_str = container_of(inode->i_cdev, struct Freg_struct, freg_cdev);
    	
    	//将自定义设备结构体保存在文件指针的私有数据中,以便后面读写的时候用
    	filp->private_data = freg_str;
    	
        return 0;
    }
    
    static int freg_release(struct inode* inode, struct file* filp)
    {
    	return 0;
    }
    
     
    struct file_operations simple_fops={
    	
     .owner=THIS_MODULE,
     .open=freg_open,
     .read=freg_read,
     .write=freg_write,
     .release = freg_release,
    }; 
    
    static int hello_init(void)
    {
        int ret;
    	dev_t freg_dev_t; 
    	
    
    printk("start freg_init2\n" );
    
    	if(CDRIVER_MAJOR!=0){
    		//静态申请设备编号
    		freg_dev_t = MKDEV(CDRIVER_MAJOR,CDRIVER_MINOR);
    		ret = register_chrdev_region(freg_dev_t,1,"freg_chrdev");
        }else{
            //动态分配设备号
            ret = alloc_chrdev_region(&freg_dev_t,0,1,"freg_chrdev");
            CDRIVER_MAJOR = MAJOR(freg_dev_t);
        }
    	
    	if(ret < 0){
    		printk(KERN_ERR"cannot get major %d \n",CDRIVER_MAJOR);
    		printk(KERN_INFO "cannot get major1\n");
    		return ret;
    	}
     
    
    	//申请设备结构体内存
    	freg_struct = kmalloc(sizeof(struct Freg_struct), GFP_KERNEL);
    	if(!freg_struct){
    		printk(KERN_INFO "freg_struct kmalloc failed \n");
    	}
    	
    	//赋值申请内存空间全部为0
    	memset(freg_struct, 0, sizeof(struct Freg_struct));
     
    	/*
    	//动态申请、初始化 cdev 
    	 freg_struct->freg_cdev = cdev_alloc();
    	  freg_struct->freg_cdev->ops=&simple_fops;
          freg_struct->freg_cdev->owner=THIS_MODULE;
    	*/
    
    printk(KERN_INFO "init cdev start\n");	
    	/*初始化 注册 cdev*/
    	cdev_init(&freg_struct->freg_cdev, &simple_fops);//静态申请cdev
        freg_struct->freg_cdev.owner = THIS_MODULE;
    	freg_struct->freg_cdev.ops = &simple_fops;
    	ret = cdev_add(&freg_struct->freg_cdev,freg_dev_t,1);
        if(ret)
        {
            printk(KERN_INFO "cdev_add err!\n");
        }
        
    	// 在/sys/class/目录下创建设备类别目录 freg
        freg_class = class_create(THIS_MODULE, "freg");
    
    	// 在/dev/目录和/sys/class/freg 目录下分别创建设备文件 freg
        device_create(freg_class, NULL, freg_dev_t,NULL,"freg");
    	
    	//freg_kobj = kobject_create_and_add("freg_kobj", NULL); //在 sys下生成 freg_kobj属性目录
    	freg_kobj = kobject_create_and_add("freg_kobj", kernel_kobj);//在 /sys/kernel下生成  freg_kobj属性目录
    	ret = sysfs_create_file(freg_kobj, &freg_attribute[0].attr);		
    	
    	mutex_init(&freg_struct->mutex);
    	 return 0;
    }
    
    static void freg_exit(void)
    {
    	dev_t freg_dev_t;
    	freg_dev_t=MKDEV(CDRIVER_MAJOR,0);
    	
        printk( KERN_DEBUG "Module skeleton exit\n" );
        device_destroy(freg_class, freg_dev_t);
        class_destroy(freg_class);
     
        cdev_del(&freg_struct->freg_cdev);
        unregister_chrdev_region(MKDEV(CDRIVER_MAJOR,0),1);
    }
     
    module_init(hello_init);
    module_exit(freg_exit);
    
    MODULE_LICENSE("GPL");
    

    测试程序:

    external\freg\freg.c

    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/mman.h>
    
    #define DEVICE_NAME "/dev/freg" 
     
    int main()
    {
      int val = 0;
      int fd = -1;
      
      fd = open(DEVICE_NAME, O_RDWR);
      if (fd == -1)
        {
    		printf("Failed to open device %s.\n", DEVICE_NAME);
    		return -1;
        }
      
      printf("Read original value:\n");
      read(fd, &val, sizeof(val));
      printf("%d.\n\n", val);
      
      val = 5;
      printf("Write value %d to %s.\n\n", val, DEVICE_NAME);
      write(fd, &val, sizeof(val));
      
      printf("Read the value again:\n");
      read(fd, &val, sizeof(val));
      printf("%d.\n\n", val);
      
      close(fd);
      return 0;
    }
    

    external\freg\Android.mk

    LOCAL_PATH:= $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
    LOCAL_MODULE_TAGS := debug
    LOCAL_SRC_FILES := freg.c
    LOCAL_MODULE := freg
    LOCAL_SYSTEM_SHARED_LIBRARIES := libc
    include $(BUILD_EXECUTABLE)
    

    三 开发Android硬件抽象层模块

    Android系统为硬件抽象层中的模块接口定义了编写规范,Android系统的硬件抽象层以模块的形式来管理各个硬件访问接口,每一个硬件模块都对应有一个动态链接库文件。这些动态链接库文件的命名符合一定的命名规范,同时在系统内部,每个硬件抽象层模块都使用结构体 hw_module_t 来描述,而硬件设备则结构体 hw_device_t 来描述。下面分别介绍硬件抽象层模块文件的命名规范以及结构体 hw_module_t 和 hw_device_t的定义。

    在上面我们完成了内核的驱动程序,我们可以通过内核生成的 /dev 目录下的设备节点来连接 Android系统硬件抽象层和Linux底层驱动层。

    3.1 硬件抽象层模块文件 命名规范

    硬件抽象层模块文件 命名规范在 hardware/libhardware/hardware.c文件中

    hardware/libhardware/hardware.c

    /**
     * There are a set of variant filename for modules. The form of the filename
     * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 
     * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
     *
     * led.trout.so
     * led.msm7k.so
     * led.ARMV6.so
     * led.default.so
     */
    
    static const char *variant_keys[] = {
        "ro.hardware",  /* This goes first so that it can pick up a different
                           file on the emulator. */
        "ro.product.board",
        "ro.board.platform",
        "ro.arch"
    };
    

    硬件抽象层模块文件的命名规范为 “<MODULE_ID>.variant.so”,其中 MODULE_ID 表示模块的ID,variant表示系统的四个属性,ro.hardware, ro.product.board, ro.board.platform,ro.arch 之一。系统在加载硬件抽象层模块时,依次按照 ro.hardware、ro.product.board、ro.board.platform、ro.arch的顺序来取他们的属性值。如果其中一个属性值存在,那么就把它的值作为variant值,然后再检查对应的文件是否存在,如果存在,那么就找到要加载的硬件抽象层模块了,否则就继续查找下一个系统属性,如果这四个系统属性都不存在,或者对应于这四个系统属性硬件抽象层模块文件都不存在,那么就是用 <MODULE_ID>.default.so来作为要加载的硬件抽象层模块文件的名称。

    注意:
    系统属性 ro.hardware : 表示在系统启动时,由init进程负责设置的。它首先会读取 /proc/cmdline文件,检查里面有没有一个名称为 androidboot.hardware的属性,如果有,就把他作为属性 ro.hardware的值,否则,就将 /proc/cpuinfo文件的内容读取出来,并且将里面的硬件信息解析出来,,即将 Hardware字段的内容作为属性 ro.hardware的值。

    系统属性 ro.product.board、ro.board.platform、ro.arch 是从 /system/build.prop文件读取出来的

    3.2 硬件抽象层模块结构体 以及 硬件抽象层设备结构体 定义规范

    结构体 hw_module_t 和 hw_device_t 以及相关的其他结构体定义在文件 hardware/libhardware/include/hardware/hardware.h中。

    #define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')
    #define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')
    
    struct hw_module_t;
    struct hw_module_methods_t;
    struct hw_device_t;
    
    
    typedef struct hw_module_t {
    
       /** tag must be initialized to HARDWARE_MODULE_TAG */
        uint32_t tag;
    	
        uint16_t module_api_version;
    #define version_major module_api_version
        uint16_t hal_api_version;
    #define version_minor hal_api_version
    
        /** Identifier of module */
        const char *id;
    
        /** Name of this module */
        const char *name;
    
        /** Author/owner/implementor of the module */
        const char *author;
    
        /** Modules methods */
        struct hw_module_methods_t* methods;
    
        /** module's dso */
        void* dso;
    
    #ifdef __LP64__
        uint64_t reserved[32-7];
    #else
        /** padding to 128 bytes, reserved for future use */
        uint32_t reserved[32-7];
    #endif
    
    } hw_module_t;
    
    typedef struct hw_module_methods_t {
        /** Open a specific device */
        int (*open)(const struct hw_module_t* module, const char* id,
                struct hw_device_t** device);
    
    } hw_module_methods_t;
    
    
    typedef struct hw_device_t {
        /** tag must be initialized to HARDWARE_DEVICE_TAG */
        uint32_t tag;
    
        uint32_t version;
    
        /** reference to the module this device belongs to */
        struct hw_module_t* module;
    
        /** padding reserved for future use */
    #ifdef __LP64__
        uint64_t reserved[12];
    #else
        uint32_t reserved[12];
    #endif
    
        /** Close this device */
        int (*close)(struct hw_device_t* device);
    
    } hw_device_t;
    
    #define HAL_MODULE_INFO_SYM         HMI
    

    struct hw_module_t 注意:

    • 1.硬件抽象层中的中的每一个模块都必须自定义一个硬件抽象层模块结构体,而且它的第一个成员变量的类型必须是 hw_module_t。

    • 2.硬件抽象层中的每一个模块都必须存在一个导出符号 HAL_MODULE_INFO_SYM ,即"HMI",他指向一个自定义的硬件抽象层模块结构体。

    • 3.结构体 hw_module_t的成员变量tag的值必须设置为 HARDWARE_MODULE_TAG ,用来标志这是一个硬件抽象层模块结构体。

    • 4.结构体 hw_module_t的成员变量dso用来保存加载硬件抽象层模块后得到的句柄值。因为每一个硬件抽象层模块都对应有一个动态链接库文件,加载硬件抽象层模块的过程实际就是加载与其对应的动态链接库文件的过程。在调用 dlclose 函数来卸载这个硬件抽象层模块时,需要用到这个句柄值。

    • 5.结构体 hw_module_t的成员变量 methods定义了一个硬件抽象层模块的操作方法列表,类型为 hw_module_methods_t。

    struct hw_module_methods_t 注意:

    *1. 结构体 hw_module_methods_t 只有一个成员变量,一个函数指针,用来打来硬件抽象层模块中的硬件设备,参数module表示要打开的硬件设备所在的模块,id表示要打开的硬件设备的id,参数device是一个输出参数,用来描述一个已经打开的硬件设备。由于一个硬件抽象层模块可能包含多个硬件设备,因此,在调用 hw_module_methods_t的成员变量open来打开一个硬件设备时,我们需要指定一个id,硬件抽象层模块中的硬件设备使用结构体 he_device_t来描述。

    struct hw_device_t 注意:

    • 1.硬件抽象层模块中的每一个硬件设备都必须自定义一个硬件设备结构体,而且他的第一个成员变量的类型必须是 hw_device_t。

    • 2.结构体 hw_device_t的成员变量 tag的值必须设置为 HARDWARE_DEVICE_TAG,用来标志这是一个硬件抽象层中的硬件设备结构体

    • 3.成员变量 close 函数指针用来关闭一个硬件设备

    • 4.硬件抽象层中的硬件设备是由其所在的模块提供的接口来打开的,而关闭则是由硬件设备本身提供接口来完成。

    3.3 编写硬件抽象层模块接口

    每一个硬件抽象层模块在内核中都有一个对应的驱动程序,硬件抽象层模块就是通过这些驱动程序来访问硬件设备的。硬件抽象层中模块接口源文件一般保存在 hardware/libhardware目录中,我们将虚拟硬件设备freg在硬件抽象层中的模块名称定义为 freg,目录结构如下:

    hardware/libhardware
    --------include
    ------------hardware
    ----------------freg.h
    
    
    hardware/libhardware/Modules
    --------freg
    ---------------freg.cpp
    ---------------Android.mk
    

    它由三个文件组成,其中freg.h 和 freg.cpp 是源代码文件,而Android.mk是模块的编译脚本文件,三个文件内容如下:

    hardware/libhardware/include/hardware/freg.h
    freg.h 内容如下

    #ifndef ANDROID_FREF_INTERFACE_H
    #define ANDROID_FREF_INTERFACE_H
    
    #include <hardware/hardware.h>
    
    __BEGIN_DECLS
    
    //定义模块ID
    #define FREG_HARDWARE_MODULE_ID "freg"
    
    //定义设备ID
    #define FREG_HARDWARE_DEVICE_ID "freg"
    
    //自定义模块结构体
    struct freg_module_t{
    	struct hw_module_t common;
    };
    
    //自定义设备结构体
    struct freg_device_t{
    	struct hw_device_t common;
    	int fd;
    	int(*set_val)(struct freg_device_t* dev, int val);
    	int(*get_val)(struct freg_device_t* dev, int* val);
    };
    
    __END_DECLS
    #endif
    

    这个文件中的常量和结构体都是按照硬件抽象层模块编写规范来定义的,宏 FREG_HARDWARE_MODULE_ID 和 FREG_HARDWARE_DEVICE_ID 分别代表模块ID和设备ID,结构体freg_module_t用来描述自定义的模块结构体,他的第一个成员变量的类型是hw_module_t。 结构体freg_device_t是自定义的设备结构体,他的第一个成员变量的类型是hw_device_t 用来描述我们的虚拟硬件设备,其中的fd代表文件描述符,表示需要打开的/dev/xxx 设备结点。其余两个函数指针用来读写 /dev/xxx 设备。

    hardware/libhardware/Modules/freg/freg.cpp

    freg.cpp 内容如下

    #define LOG_TAG "FregHALStub"
    
    #include <hardware/hardware.h>
    #include <hardware/freg.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <cutils/log.h>
    #include <cutils/atomic.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define DEVICE_NAME "/dev/freg"
    #define MODULE_NAME "Freg"
    #define MODULE_AUTHOR "MHR"
    
    //设备打开和关闭接口
    static int freg_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
    static int freg_device_close(struct hw_device_t* device);
    
    //设备读写接口
    static int freg_set_val(struct freg_device_t* dev, int val);
    static int freg_get_val(struct freg_device_t* dev, int* val);
    
    //定义模块操作方式结构体变量
    static struct hw_module_methods_t freg_module_methods = {
    open: freg_device_open
    };
    
    //定义模块结构体变量
    struct freg_module_t HAL_MODULE_INFO_SYM = {
    	common: {
    		tag: HARDWARE_MODULE_TAG,
    		version_major: 1,
    		version_minor: 0,
    		id: FREG_HARDWARE_MODULE_ID,
    		name: MODULE_NAME,
    		author: MODULE_AUTHOR,
    		methods: &freg_module_methods,
    	}
    
    };
    
    //虚拟硬件设备freg的打开和关闭分别由  freg_device_open、freg_device_close来实现
    static int freg_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device)
    {	
    	
    	struct freg_device_t* dev;
    	dev = (struct freg_device_t*)malloc(sizeof(struct freg_device_t));
    	
    	if(!dev) {
    		ALOGI("%s Freg Stub: failed to alloc space", __func__);
    		return -EFAULT;
    	}
    	
    	memset(dev, 0, sizeof(struct freg_device_t));
    	dev->common.tag = HARDWARE_DEVICE_TAG;
    	dev->common.version = 0;
    	dev->common.module = (hw_module_t*)module;
    	dev->common.close = freg_device_close;
    	dev->set_val = freg_set_val;
    	dev->get_val = freg_get_val;
    	
    	if((dev->fd = open(DEVICE_NAME,  O_RDWR)) == -1){
    			ALOGI("%s Freg Stub: open /dev/freg Failed.", __func__);
    			free(dev);
    		}
    	
    	*device = &(dev->common);
    	ALOGI("%s Freg Stub: open /dev/freg successfully.", __func__);
    	return 0;
    
    }
    
    static int freg_device_close(struct hw_device_t* device)
    {
    	struct freg_device_t* freg_device = (struct freg_device_t*)device;
     
    	if(freg_device) {
    		close(freg_device->fd);
    		free(freg_device);
    	}
    	
    	return 0;
    }
    
    //虚拟硬件设备 freg的读写函数
    static int freg_set_val(struct freg_device_t* dev, int val) {
     
    	write(dev->fd, &val, sizeof(val));
    	return 0;
    }
    
    static int freg_get_val(struct freg_device_t* dev, int* val) {
     
    	read(dev->fd, val, sizeof(*val));
    	return 0;
    }
    

    freg.cpp 代码分析:

    //定义模块结构体变量
    struct freg_modules_t HAL_MODULE_INFO_SYM = {
    	common: {
    		tag: HARDWARE_MODULE_TAG,
    		version_major: 1,
    		version_minor: 0,
    		id: FREG_HARDWARE_MODULE_ID,
    		name: MODULE_NAME,
    		author: MODULE_AUTHOR,
    		methods: &freg_module_methods,
    	}
    
    };
    

    这段代码中, HAL_MODULE_INFO_SYM 是模块变量,按照硬件抽象层的编写规范,每一个硬件抽象层模块必须导出一个名称为 HAL_MODULE_INFO_SYM 的符号,它指向一个自定义的硬件抽象层模块结构体,而且它的第一个类型为 hw_module_t 的成员变量tag值必须设置为 HARDWARE_MODULE_TAG . 除此之外,还初始化了这个硬件抽象层模块结构体的版本号, ID,名称,作者,操作放大列表等。所以,这里,实例变量名必须为 HAL_MODULE_INFO_SYM ,tag也必须为 HARDWARE_MODULE_TAG ,这是Android硬件抽象层规范规定的。

    static int freg_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device)
    static int freg_device_close(struct hw_device_t* device)

    前面提到,一个硬件抽象层模块可能包含多个硬件设备,而这些硬件设备的打开操作都是由函freg_device_open来完成的,因此,函数freg_device_open会根据传递进来的参数id来判断要打开哪一个硬件设备。在本利硬件抽象层模块freg中,只有一个虚拟硬件设备freg,它使用 freg_device_t来描述,因此,函数 freg_device_open 发现参数id与虚拟硬件设备freg的ID值匹配以后,就会分配一个 freg_device_t结构体,并对其成员变量进行初始化,按照硬件抽象层模块的编写规范,硬件抽象层中的硬件设备标签 (dev->common.tag)必须设置为HARDWARE_DEVICE_TAG,除此之外,我们还将虚拟硬件设备freg的关闭函数设置为 freg_device_close。

    hardware/libhardware/Modules/freg/Android.mk

    Android.mk 内容如下

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE_TAGS := optional
    LOCAL_PRELINK_MODULE := false
    LOCAL_SHARED_LIBRARIES := liblog
    LOCAL_MODULE_RELATIVE_PATH := hw
    LOCAL_SRC_FILES := freg.cpp
    LOCAL_MODULE := freg.default
    include $(BUILD_SHARED_LIBRARY)
    

    这个是硬件抽象层模块freg的编译脚本文件,include $(BUILD_SHARED_LIBRARY) 表示要将该硬件模块抽象层编译成一个动态链接库文件, 名称为 freg.default,并且保存在 $(TARGET_OUT_SHARED_LIBRARIES)/hw (out/target/product/generic/system/lib/hw )目录下。LOCAL_MODULE的定义规则,freg后面跟有default,freg.default能够保证我们的模块总能被硬象抽象层加载到。

    mmm hardware/libhardware/modules/
    

    生成 out/target/product/m282a/obj/lib/freg.default.so

    注意:
    我们将硬件抽象层模块 freg 对应的文件名称定义为 freg.default,编译成功后,系统会自动在后面加后缀.so, 于是就得到了一个 freg.default.so文件。根据硬件抽象层模块文件的命名规范,当我们要加载硬件抽象层模块freg时,只需要指定它的ID值,即 “freg”,系统会根据一定的规则成功的找到要加载啊 freg.default.so文件。硬件抽象层模块 freg 都准备好后,就可以编译打包了,最终会在 out/target/product/generic/system/lib/hw 下得到 freg.default.so文件。硬件抽象层模块文件实际上是一个动态链接库文件,即so文件。另外为了能直接编译,需要在 build\target\product\embedded.mk 中添加 : freg.default
    才能编译我们所添加的 hardware模块。最后在 out/target/product/generic/system/lib/hw 下生成 freg.default.so
    在这里插入图片描述
    至此, 虽然我们在Android系统为我们自己的硬件增加了一个硬件抽象层模块,但是现在Java应用程序还不能访问到我们的硬件。我们还必须编写JNI方法和在Android的Application Frameworks层增加API接口,才能让上层Application访问我们的硬件。

    四 为Android硬件抽象层编写JNI方法供硬件服务程序调用
    4.1 JNI实现

    在Android系统中,通常把硬件访问服务的JNI方法实现在frameworks\base\services\core\jni 目录中,因此,我们把实现了硬件访问服务FregService的JNI方法 com_android_service_FregService.cpp 放在该目录下,com_android_server前缀表示的是包名 , 表示硬件服务FregService是放在frameworks/base/services/java目录下的com/android/server目录的, 即存在一个命令为com.android.server.FregService的类 内如如下:

    #define LOG_TAG "FregServiceJNI"
    
    #include "jni.h"
    #include "JNIHelp.h"
    #include "android_runtime/AndroidRuntime.h"
    #include <utils/misc.h>
    #include <utils/Log.h>
    #include <hardware/hardware.h>
    #include <hardware/freg.h>
    #include <stdio.h>
    
    namespace android
    {
    //硬件抽象层中定义的 硬件结构体
    	struct freg_device_t* freg_device = NULL;
    
    //通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值
    static void freg_setVal(JNIEnv* env, jobject clazz, jint value) {
    		int val = value;
    		
    		LOGI("Freg JNI: set value %d to device.", val);
    		
    		if(!freg_device){
    			LOGI("Freg JNI: device is not open.");
    			return;
    		}
    
    		freg_device->set_val(freg_device, val);
    	}
    
    //通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值
    	static jint freg_getVal(JNIEnv* env, jobject clazz){
    		
    		int val = 0;
    		
    		if(!freg_device){
    			LOGE("Device freg is not oprn.");
    			return 0;
    		}
    		freg_device->get_val(freg_device,&val);
    		LOGE("Freg JNI: Get value %d from device freg."val);
    		return val;
    	}
    
    //通过硬件抽象层定义的硬件模块打开接口打开硬件设备
    	static inline int freg_device_open(const hw_module_t* module, struct freg_device_t** device)
    	{
    		return module->methods->open(module, FREG_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
    	}	
    		
    //通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件
    	static jint freg_init(JNIEnv* env, jclass clazz){
    		freg_module_t* module;
    		
    		LOGI(Initializing HAL stub freg......);
    		
    		//加载硬件抽象层模块 freg
    		if(hw_get_module(FREG_HARDWARE_MODULE_ID,(const struct hw_module_t**)&module) == 0) {
    			LOGI("Freg JNI : freg Stub found.");
    			
    			//打开虚拟硬件设备freg
    			if(freg_device_open(&(module->common),&freg_device) ==0) {
    				LOGI("Freg JNI :freg Device found");
    				return 0;
    			}
    			LOGI("Failed to open device freg");
    			return -1;
    		}
    		LOGI("Failed to get HAL stub freg");
    		return -1;
    	}
    	
    	//Java 本地接口方法表
    	static const JNINativeMethod method_table[] = {
    		{"init_native", "()Z", (void*)freg_init},
    		{"setVal_native", "(I)V", (void*)freg_setVal},
    		{"getVal_native", "()I", (void*)freg_getVal},
    	};
    	
    	//注册java本地接口方法
    	int register_android_server_FregService(JNIEnv *env) {
        		return jniRegisterNativeMethods(env, "com/android/server/FregService", method_table, NELEM(method_table));
    	}
    
    };
    

    在函数 freg_init 中,首先通过Android硬件抽象层提供的 hw_module_get 函数来加载模块ID为 FREG_HARDWARE_MODULE_ID 的硬件抽象层模块,其中, FREG_HARDWARE_MODULE_ID 是在<hardware/freg.h>中定义的。Android硬件抽象层会根据 FREG_HARDWARE_MODULE_ID 的值在Android系统的/system/lib/hw目录中找到相应的模块,然后加载起来,并且返回hw_module_t接口给调用者使用。

    需要注意到是,在调用 freg_setVal 和 freg_getVal这两个JNI方法之前,调用者首先要调用JNI方法 freg_init 打开虚拟硬件设备,以便可以获得一个 freg_device_t接口。文件中定义的 JNI方法表 method_table,分别将函数 freg_init、freg_setVal、freg_getVal的JNI方法注册为 init_native setVal_native getVal_native。文件最后调用了 jniRegisterNativeMethods()函数把JNI方法表注册到JAVA虚拟机中,在 jniRegisterNativeMethods 函数中,第二个参数的值必须对应FregService所在的包的路径,即 com.android.server.FregService。以便提供给硬件访问服务 FregService 使用。

    4.2 声明JNI注册方法

    增加 register_android_server_FregService()函数的声明和调用。

    frameworks\base\services\core\jni\onload.cpp

    namespace android {
    ...
    ...
    int register_android_server_FregService(JNIEnv *env);
    };
    
    using namespace android;
    extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */){
    
    	...
    	register_android_server_FregService(env);
    }
    
    4.3 添加JNI方法代码

    最后到 frameworks\base\services\core\jni 目录中,打开里面的Android.mK文件,修改变量LOCALSRC_FILS的值。

    frameworks\base\services\core\jni\Android.mK

    LOCAL_SRC_FILES += \
    ......
    com_android_server_FregService.cpp \
    onload.cpp
    

    最后执行

    mmm frameworks/base/services/core/jni 
    

    最后得到的 libandroid_service.so文件就包含 init_native、setVal_native、getVal_native 这三个JNI方法了。至此 硬件访问服务FregService的实现就完成了。下面介绍如何在系统进程System中启动它。

    五 开发Android硬件访问服务

    在前面,我们介绍了如何为Android系统的硬件编写驱动程序,包括如何在Linux内核空间实现内核驱动程序和在用户空间实现硬件抽象层接口。实现这两者的目的是为了向更上一层提供硬件访问接口,即为Android的Application Frameworks层提供硬件服务。那么到此为止,在开发好硬件抽象层模块之后,我们还需要在应用程序框架层中实现一个硬件访问服务,硬件访问服务通过硬件抽象层模块来为应用程序提供硬件读写操作接口,由于硬件抽象层模块是使用 C++/C 语言开发的,而应用程序框架中的硬件访问服务是使用JAVA语言开发的,那么,Java接口如何去访问C接口呢?众所周知,Java提供了JNI方法调用,因此,硬件访问服务必须通过JAVA本地接口(Java Native Interface JNI)来调用硬件抽象层模块的接口。Android系统的硬件访问服务通常运行在系统进程System中,而使用这些硬件访问服务的应用程序运行在其他的进程中,即应用程序需要通过进程间通信机制来访问这些硬件访问服务,Android系统提供了一种高效的进程间通信机制–Binder进程间通信机制,应用程序就是通过它来访问运行在系统进程System中的硬件访问服务的。Binder进程间通信机制要求要求提供服务的一方必须实现一个具有跨进程访问能力的服务接口,以便使用服务的一方可以通过这个服务接口来访问它。因此,在实现硬件访问服务之前,我们首先要定义它的服务接口。

    所以综上所述,我们在此处要实现以下2个任务

    1.定义硬件访问服务接口 
    2.实现硬件访问服务 最后 启动硬件访问服务
    
    5.1 定义硬件访问服务接口

    Android 系统提供了一种描述语言来定义具有跨进程访问能力的服务接口,这种描述语言称为 Android 接口描述语言(Android Interface Definition Language, AIDL)。以AIDL定义的服务接口文件是以aidl为后缀的,在编译时,编译系统会将他们转换成Java文件,然后对他们进行编译,此处我们使用AIDL来定义硬件访问服务接口 IFregService。在Android系统中,通常把硬件访问服务接口定义在 framework/base/core/java/android/os 目录中,因此,我们把定义了硬件访问服务接口 IFregService 的文件 IFregService.aidl也保存在这个目录中,内容如下:

    framework/base/core/java/android/os/IFregService.aidl

    package android.os;
    
    //注: 注释中需要添加{@hide},不然会出现编译问题 
    /** @hide */
    interface IFregService {
    	void setVal(int val);
    	int getVal();
    }
    

    IFregService服务接口之定义了两个成员函数,setVal用来往虚拟硬件设备freg写,另一个是读。

    由于服务器接口 IFregService 是使用AIDL语言描述的,因此,我们需要将其添加到编译脚本文件中,这样编译系统才能将其转换为Java文件,然后再对它进行编译,进入framework/base目录中,打开里面的 Andriod.mk文件,修改 LOCAL_SRC_FILES 变量的值,增加IFregService.aidl源文件

    frameworks/base\ Andriod.mk

    LOCAL_SRC_FILES += \
    .....
    voip/java/android/net/sip/ISipService.aidl \
    ...
    core/java/android/os/IFregService.aidl
    

    修改这个编译脚本之后,可以使用mmm命令对硬件访问服务接口IFregService进行编译了,

    mmm frameworks/base 
    

    这样,就会根据 IFregService.aidl 生成相应的IFregService.Stub接口

    5.2 实现硬件访问服务 最后 启动硬件访问服务

    在Android系统中,通常把硬件访问服务实现在 frameworks/base/services/java/com/android/server 中,因此,我们把实现了硬件访问服务 FregService的FregService.java文件也保存在这个目录中,内容如下:

    frameworks/base/services/java/com/android/server/FregService.java

    package com.android.server;
    import android.content.Context;
    import android.os.IFregService;
    import android.util.Slog;
    
    /**
     * @hide
     */
    
    // 定义类FregService 继承自  IFregService.Stub
    public class FregService extends IFregService.Stub{
    	
    private static final String TAG = "FregService";//final关键字定义常量,就使得他在被定义后无法再对此进行赋值
    
    FregService(){
    	init_native();
    }
    
    public void setVal(int val){
    	setVal_native(val);
    }
    
    public int getVal(){
    	return getVal_native();
    }
    
    private static native int init_native();
    private static native void setVal_native(int val);
    private static native int getVal_native();
    
    };
    

    硬件访问服务FregService继承了IFregService.Stub类,并且实现了IFregService接口的成员函数setVal和getVal,其中,成员函数setVal通过调用JNI方法来写虚拟硬件设备freg,而成员函数getVal调用JNI方法getVal_native来读虚拟硬件设备。

    前面提到,Android系统的硬件访问服务通常是在系统进程System中启动的,而系统进程System是在开机时自动启动,因此,将硬件访问服务运行在系统进程System中,就可以实现开机时自动启动,此处我们将硬件访问服务 FregService运行在系统进程System中,因此,进入到 frameworks/base/service/java/com/android/server目录下,打开里面的 SystemService.java 文件,修改ServiceThread类的成员函数 run的实现

             public void run() {
                Slog.i(TAG, "Making services ready");
    			......
    			
    			try {
    			Slog.i(TAG,"Freg Service");
    			ServiceManager.addService("freg", new FregService());
    			} catch(Throwable e) {
    			Slog.i(TAG,"Failure starting Freg Service", e);
    			}
    
            }
    

    系统进程System在启动时,会创建一个 ServiceThread 线程来启动系统中的关键服务,其中就包括一些硬件访问服务,在ServiceThread类的成员函数run中,首先创建一个 FregService实例,然后把他注册到 Service Manager中,Service Manager是Android系统的Binder进程间通信机制的一个重要角色,他负责管理系统中的服务对象,注册到 Service Manager 中的服务对象都有一个对应的名称,使用这些服务的Client进程就是通过这些名称来向 Service Manager 请求他们的Binder代理对象接口的,以便可以访问他们所提供的服务,硬件访问服务 FregService 注册到 Service Manager之后,他的启动过程就完成了。

    最后执行

    mmm frameworks/base/services/java/ 
    

    编译后得到的 service.jar 文件就包含有硬件访问服务FregService,并且在系统启动时,将他运行在系统进程System中。

    五 开发Android应用程序来使用硬件访问服务

    。。。。。。待续。。。。。。

    展开全文
  • 一、七层 七层是指OSI(Open System Interconnect的缩写,意为开放式系统互联)七层协议模型,主要是:应用层(Application)、表示层(Presentation)、会话层(Session)、...五层只是OSI和TCP/IP的综合,是业...

    一、七层

    七层是指OSI(Open System Interconnect的缩写,意为开放式系统互联)七层协议模型,主要是:应用层(Application)、表示层(Presentation)、会话层(Session)、传输层(Transport)、网络层(Network)、数据链路层(Data Link)、物理层(Physical)。

    二、五层

    五层只是OSI和TCP/IP的综合,是业界产生出来的非官方协议模型,但是很多具体的应用。实际应用还是TCP/IP的四层结构。为了方便可以把下两层称为网络接口层。五层体系结构包括:应用层、运输层、网络层、数据链路层和物理层。 

    三、四层

    四层是指TCP/IP四层模型,主要包括:应用层、运输层、网际层和网络接口层。

    四层协议和对应的标准七层协议的关系如下图:

    简图:

    四、总结

    所谓的五层协议的网络体系结构其实是为了方便学习计算机网络原理而采用的,综合了OSI七层模型和TCP/IP的四层模型而得到的五层模型。

    TCP/IP四层模型跟OSI模型有什么不一样?

    OSI是一个完整的、完善的宏观理论模型;而TCP/IP(参考)模型,更加侧重的是互联网通信核心(也是就是围绕TCP/IP协议展开的一系列通信协议)的分层,因此它不包括物理层,以及其他一些不想干的协议;其次,之所以说他是参考模型,是因为他本身也是OSI模型中的一部分,因此参考OSI模型对其分层。

    七层模型有什么用?

    互联网的实现,分成好几层,每一层都有自己的功能,就像建筑物一样,每一层都靠下一层支持。OSI模型就是这样的一个分层,它是一个由国际标准化组织提出的概念模型,试图提供一个使各种不同的终端和网络类型在世界范围内实现互联的标准框架。划分为七层,每层都可以提供抽象良好的接口。

     


    我的微信公众号:架构真经(id:gentoo666),分享Java干货,高并发编程,热门技术教程,微服务及分布式技术,架构设计,区块链技术,人工智能,大数据,Java面试题,以及前沿热门资讯等。每日更新哦!

    参考内容:

    1. https://blog.csdn.net/buknow/article/details/81148684
    2. http://www.360doc.com/content/19/0721/09/99071_850093348.shtml
    3. https://network.51cto.com/art/201907/599289.htm
    展开全文
  • 产品经理数据分析入门

    万次阅读 多人点赞 2017-11-20 11:47:25
    这篇文章一共会分为四个部分进行讲解。 认识数据 通过这部分我们可以知道什么是数据,数据与产品之间的关系等。...这里我们可以知道在做产品的时候,使用数据的一些场景和利用数据驱动产品的思维方式
  • 本文分为两部分,第一部分总的介绍RTC框架,而第二部分将结合详细的代码来分析各个层次的关系以及在本中他们所做的事情。  Linux内核:linux-2.6.22.6  所用开发板:JZ2440 V3(S3C2440A) 声明 :  ...
  • 作者:小胖 编辑:小胖 目录 第一部分 概览 1.1 行业概述 1.2 产品分析 第二部分 基于用户体验5要素的竞品分析 2.1 战略 2.2 范围 2.3 结构 2.4 框架层 2.5表现 第三部分 总结 3.1 用户需求回顾 3.2 综合...
  • 作者:find goo ...来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 我为什么反对用各类框架。 什么ssh,orm,spring,struct,复杂,速度...如果有有一百万种框架学一百万年后,知道了
  • 典型情境是指软件开发的常见情境,本文选择如下来进行分析: 1. 传统瀑布模型开发下的需求评审 2. 使用IEEE Std. 1028的需求评审 3. 敏捷开发下的需求评审传统瀑布模型下的需求评审对传统瀑布模型现有需求评审...
  • Web中MVC设计理念 & 经典三架构 & 大主流框架

    万次阅读 多人点赞 2018-10-30 21:31:03
    一、Web的MVC设计理念和MVC框架: 之前在Web篇04中已经详述了Servlet、TomCat、JSP和Web.xml之间的联系; (1)浏览器发送请求到收到响应,简要的过程如下: 浏览器发送请求后,由Web.xml中规定的协议,进入...
  • 微信小程序框架分析

    千次阅读 2018-03-08 21:43:28
    加上JavaScript逻辑语言和json配置文件,构建起了微信小程序框架 框架页面文件 工具类文件: 框架全局文件: 2.1微信小程序目录结构介绍: 1. 框架全局文件:对于框架全局文件来说,必须放在项目的根目录中...
  • 计算机网络五层结构功能汇总

    千次阅读 多人点赞 2020-03-29 19:59:19
    网上有很多博客介绍过计算机网络五层结构,但专门汇总五层结构功能的博文非常少; 本文从纵向的角度,清晰概述计算机网络五层结构的功能和特点; 本文总结了计算机网络五层结构的协议名和专用术语,并对一些结构性...
  • 1. 摘要这篇文章中,主要针对的是语篇结构和类型、层级性和分析模式的研究,着重对于语篇的结构类型进行了相关的探讨。我也主要是注重其语篇的结构方面进行相关的思考。2. 语篇、话语与篇章语篇(text)和话语...
  • Java 框架之间的对比

    万次阅读 多人点赞 2016-11-27 22:37:03
    Spring 及其优点大部分项目都少不了spring的身影,为什么大家对他如此青睐,而且对他的追捧丝毫没有减退之势呢Spring是什么:Spring是一个轻量级的DI和AOP容器框架。说它轻量级有一大部分原因是相对与EJB的(虽然...
  • Android系统架构 五层结构

    万次阅读 2017-06-27 14:09:43
    Android系统架构 五层结构 Android系统架构(由下往上): Linux Kernel HAL Native C/C++ Libraries & Android Runtime Java Framework Applications Android系统架构
  • 选自 RevolutionAnalytics http://www.aiweibang.com/yuedu/139947035.html 机器之心编译 ...近日,微软数据科学家 Anusua Trivedi 发表系列文章讲解深度学习,这是此系列的第一篇,对主流深度学习框架进行
  • 产品用户体验的个层次

    万次阅读 2016-12-16 11:44:36
    《用户体验要素》产品用户体验的个层次 说到用户体验,大家都已经耳熟能详了。无论是互联网产品还是传统软件行业的产品,都越来越重视用户体验,都已经把用户体验提示到一个新的高度。大家谈论用户体验的方式也有...
  • hadoop框架详细分析

    千次阅读 2013-08-20 13:28:23
    hadoop框架详细分析
  • 种大数据计算框架

    千次阅读 2019-08-27 00:27:45
    虽然“引擎”和“框架”之间的区别没有什么权威的定义,但大部分时候可以将前者定义为实际负责处理数据操作的组件,后者则可定义为承担类似作用的一系列组件。 例如 Apache Hadoop 可以看作一种以 MapReduce 作为...
  • 当年刚刚入产品经理这一行的时候,第一节课学习的就是如何对产品进行分析。但是随着年龄的增长,时常感到自己对竞品分析产品分析理解的浅薄,我一度无法分清两者的区别与侧重点,现在才对两者之间的关系渐渐清晰,...
  • 我深入分析个大数据处理框架:Hadoop,Spark,Flink,Storm,Samaza Hadoop 顶尖的框架之一,大数据的代名词。Hadoop,MapReduce,以及其生态系统和相关的技术,比如Pig,Hive,Flume,HDFS等。Hadoop是第一个...
  • 里面讲述了用户体验要素的个层面:战略,范围,结构框架层,表现。也是产品设计的个层面,所以学习记录下。首先附上这个层次的图: 首先介绍下用户体验要素这本书,这本书主要以web网页作为例子...
  • 前端框架MVVM是什么(整理)

    千次阅读 多人点赞 2020-08-06 06:25:42
    一句话总结:vm(视图模型)通过接口从后台m(model)请求数据,vm继而和v(view)实现数据的双向绑定。
  • android 优秀框架整理

    万次阅读 多人点赞 2018-01-11 11:28:29
    程序员界有个神奇的网站,那就是github,这个网站集合了一大批优秀的开源框架,极大地节省了开发者开发的时间,在这里我进行了一下整理,这样可以使我们在使用到时快速的查找到,希望对大家有所帮助! 1. Retrofit...
  • 真正在金融行业做数据分析的人,都知道金融业虽然有着很强的交易数据流,但其实它们的数据化程度已经远远落后于普通电商、电信行业,落后的IT业务系统没有办法实现与数据分析的深度融合,整个行业的数据价值早就被...
  • 大家好,又到了学习Glide的时间了。...不过Glide的这个框架的功能实在是太强大了,它所能做的事情远远不止于目前我们所学的这些。因此,今天我们就再来学习一个新的功能模块,并且是一个非常重要的模块
  • 几大主流的前端框架(UI/JS)框架

    千次阅读 2020-12-14 11:03:25
    如今的前端已经不再像以前一样就是简单的写写页面和调调样式而已,现在的前端越来越复杂,知识点越来越丰富。...web前端发展至今,演变出了无数的库和框架;说到库第一时间想到的是不是jquery?在小编刚接触库的时候
  • 知乎产品分析|知识社区何去何从

    千次阅读 2017-04-20 10:41:15
    通过对知乎这款产品分析,锻炼自己的思维能力,深化自己对产品的理解,向优秀的产品学习,同时提出一些自己对该产品的看法。 1.2体验环境 移动设备:Letv 1s Android版本:6.0 1.3版本信息 知乎:...
  • 作业帮产品分析

    千次阅读 2020-07-02 15:24:39
    作业帮产品分析 本文将从如下方面分析: 行业分析 竞品分析 用户价值分析 商业价值分析 产品迭代分析 产品结构分析 运营分析 总结 一、行业分析 目前国家选拔人才的主要方式是各类招录考试,因此对于学历制阶段的...
  • 结构框架层 3.1结构分析 3.2交互设计分析 总结 1.优劣势总结分析 2.功能建议 一.分析背景与竞品选择 1.竞品分析目的 调研目前国内市场上的头部第三方移动支付产品,了解其产品结构,功能呈现,分析产品在内容...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 122,833
精华内容 49,133
关键字:

产品分析的五层框架