/** * @file gralloc_drm_rockchip.cpp * 对 rk_driver_of_gralloc_drm_device_t 的具体实现. */ #define LOG_TAG "GRALLOC-ROCKCHIP" // #define ENABLE_DEBUG_LOG #include "custom_log.h" #include #include #include #include #include #include extern "C" { #include } #include "gralloc_helper.h" #include "gralloc_drm.h" #include "gralloc_drm_priv.h" #if RK_DRM_GRALLOC #include #endif //end of RK_DRM_GRALLOC #include #include #ifdef USE_HWC2 #include "gralloc_buffer_priv.h" #endif #include #include /*---------------------------------------------------------------------------*/ #define RK_CTS_WORKROUND (1) #define UNUSED(...) ((void)(__VA_ARGS__)) #define USAGE_CONTAIN_VALUE(value,mask) ((usage & mask) == value) #if RK_CTS_WORKROUND #define VIEW_CTS_FILE "/data/data/android.view.cts/view_cts.ini" #define VIEW_CTS_PROG_NAME "android.view.cts" #define VIEW_CTS_HINT "view_cts" #define BIG_SCALE_HINT "big_scale" typedef unsigned int u32; typedef enum { IMG_STRING_TYPE = 1, /*!< String type */ IMG_FLOAT_TYPE , /*!< Float type */ IMG_UINT_TYPE , /*!< Unsigned Int type */ IMG_INT_TYPE , /*!< (Signed) Int type */ IMG_FLAG_TYPE /*!< Flag Type */ }IMG_DATA_TYPE; #endif struct dma_buf_sync { __u64 flags; }; #define DMA_BUF_SYNC_READ (1 << 0) #define DMA_BUF_SYNC_WRITE (2 << 0) #define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE) #define DMA_BUF_SYNC_START (0 << 2) #define DMA_BUF_SYNC_END (1 << 2) #define DMA_BUF_SYNC_VALID_FLAGS_MASK \ (DMA_BUF_SYNC_RW | DMA_BUF_SYNC_END) #define DMA_BUF_NAME_LEN 32 #define DMA_BUF_BASE 'b' #define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync) #define DMA_BUF_SET_NAME _IOW(DMA_BUF_BASE, 1, const char *) /* memory type definitions. */ enum drm_rockchip_gem_mem_type { /* Physically Continuous memory and used as default. */ ROCKCHIP_BO_CONTIG = 1 << 0, /* cachable mapping. */ ROCKCHIP_BO_CACHABLE = 1 << 1, /* write-combine mapping. */ ROCKCHIP_BO_WC = 1 << 2, ROCKCHIP_BO_SECURE = 1 << 3, ROCKCHIP_BO_MASK = ROCKCHIP_BO_CONTIG | ROCKCHIP_BO_CACHABLE | ROCKCHIP_BO_WC | ROCKCHIP_BO_SECURE }; struct drm_rockchip_gem_phys { uint32_t handle; uint32_t phy_addr; }; #define DRM_ROCKCHIP_GEM_GET_PHYS 0x04 #define DRM_IOCTL_ROCKCHIP_GEM_GET_PHYS DRM_IOWR(DRM_COMMAND_BASE + \ DRM_ROCKCHIP_GEM_GET_PHYS, struct drm_rockchip_gem_phys) /*---------------------------------------------------------------------------*/ // for rk_drm_adapter : using namespace android; /** * 用于 记录当前进程中某个 gem_obj 被引用状态信息 的类型. */ class gem_obj_referenced_info_entry_t { public: /* handle of current gem_obj. */ uint32_t m_handle; /* 当前 gem_obj 的被引用计数. */ uint32_t m_ref; /*-------------------------------------------------------*/ gem_obj_referenced_info_entry_t(uint32_t gem_handle) : m_handle(gem_handle), m_ref(1) // "1" : 初始被引用计数. {} uint32_t get_ref() const { return m_ref; } void inc_ref() { m_ref++; } void dec_ref() { LOG_ALWAYS_FATAL_IF(0 == m_ref, "m_ref is 0, can not decrease any more."); m_ref--; } }; /** * 基于 rk_drm 的, 对 driver_of_gralloc_drm_device_t 的具体实现, * 即 .DP : rk_driver_of_gralloc_drm_device_t. * * 除了基类子对象, 还包括 扩展的成员等. */ struct rk_driver_of_gralloc_drm_device_t { /* 基类子对象. */ struct gralloc_drm_drv_t base; /* * rockchip drm device object, rk_drm_device_object or rk_drm_dev * returned from rockchip_device_create(). */ struct rockchip_device *rk_drm_dev; // rockchip_device 定义在 external/libdrm/rockchip/rockchip_drmif.h 中. /* gralloc_drm_t::fd, fd of drm device file.*/ int fd_of_drm_dev; /*-------------------------------------------------------*/ // .DP : rk_drm_adapter : // RK redmine Defect #16966 中涉及的某个和 camera HAL 相关的 case 中, 确定有可能出现如下异常 : // buffer_a 和 buffer_b 引用相同的 底层的 gem_obj 实例, 在不同的线程中, 被并发地调用 register/lock/unlock/unregister; // buffer_a 被 unregister, rockchip_bo_destroy() 将被调用, // 因为 rk_drm 对 rockchip_bo 实例下的 gem_obj 未提供 被引用计数机制, 底层的 gem_obj 将被直接 close. // 而之后 buffer_b 又被 lock, 此时因为底层的 gem_obj 已经被 close, 即 gem_handle 无效, lock 失败. // // 为处理上述的 case, 在 rk_drm_gralloc 中增加对 rockchip_bo 引用的底层的 gem_obj 被引用计数, // 将对应的逻辑机构记为 rk_drm_adapter. /** * 保存当前进程中 所有有效 gem_obj 的被引用状态信息的 map. * 以 gem_handle 为 key, * 对应的 gem_obj_referenced_info_entry_t heap_object 的指针作为 value. */ KeyedVector m_gem_objs_ref_info_map; /* * 除了保护 'm_gem_objs_ref_info_map', 也保护对 rk_drm 的某一次调用. * .DP : drm_lock */ mutable Mutex m_drm_lock; }; /** * 当前 rk_driver_of_gralloc_drm_device_t 实例的指针. * * 按照原始的封装设计, drm_gem_rockchip_free() 等函数应该是 static 的, 并且外部传入的 'drv' 实参必须是有效的, * 但是之前的开发中, 庄晓亮为 workaround 某些异常, 在本文件外部直接调用 drm_gem_rockchip_free(), 且对 'drv' 传入 NULL, * 参见 commit 136daf0d. * 类似的接口还有 drm_gem_rockchip_alloc(). * 为处理上述 case, 这里静态地保存 当前 rk_driver_of_gralloc_drm_device_t 实例的指针. */ static struct rk_driver_of_gralloc_drm_device_t* s_rk_drv; /* rockchip_gralloc_drm_buffer_object. */ struct rockchip_buffer { /* 基类子对象. */ struct gralloc_drm_bo_t base; /* rk_drm_bo. */ struct rockchip_bo *bo; }; /*---------------------------------------------------------------------------*/ // for rk_drm_adapter : // static inline int get_fd_of_drm_dev(const struct rk_driver_of_gralloc_drm_device_t* rk_drv) { return rk_drv->fd_of_drm_dev; } static inline struct rockchip_device* get_rk_drm_dev(const struct rk_driver_of_gralloc_drm_device_t* rk_drv) { return rk_drv->rk_drm_dev; } static inline KeyedVector& get_gem_objs_ref_info_map(struct rk_driver_of_gralloc_drm_device_t* rk_drv) { return rk_drv->m_gem_objs_ref_info_map; } static inline Mutex& get_drm_lock(struct rk_driver_of_gralloc_drm_device_t* rk_drv) { return rk_drv->m_drm_lock; } /* * 初始化 'rk_drv' 中的 rk_drm_adapter. */ static inline int rk_drm_adapter_init(struct rk_driver_of_gralloc_drm_device_t* rk_drv) { int ret = 0; KeyedVector& map = get_gem_objs_ref_info_map(rk_drv); map.setCapacity(16); return ret; } static inline void rk_drm_adapter_term(struct rk_driver_of_gralloc_drm_device_t* rk_drv) { UNUSED(rk_drv); } static struct rockchip_bo* rk_drm_adapter_create_rockchip_bo(struct rk_driver_of_gralloc_drm_device_t* rk_drv, size_t size, uint32_t flags); static void rk_drm_adapter_destroy_rockchip_bo(struct rk_driver_of_gralloc_drm_device_t* rk_drv, struct rockchip_bo *bo); static struct rockchip_bo* rk_drm_adapter_import_dma_buf(struct rk_driver_of_gralloc_drm_device_t* rk_drv, int dma_buf_fd, uint32_t flags, uint32_t size); static inline uint32_t rk_drm_adapter_get_gem_handle(struct rockchip_bo *bo) { return rockchip_bo_handle(bo); } static inline uint32_t rk_drm_adapter_get_prime_fd(struct rk_driver_of_gralloc_drm_device_t* rk_drv, struct rockchip_bo *bo, int* prime_fd); static inline void* rk_drm_adapter_map_rockchip_bo(struct rockchip_bo *bo) { return rockchip_bo_map(bo); } static int rk_drm_adapter_inc_gem_obj_ref(struct rk_driver_of_gralloc_drm_device_t* rk_drv, uint32_t handle); static void rk_drm_adapter_dec_gem_obj_ref(struct rk_driver_of_gralloc_drm_device_t* rk_drv, uint32_t handle); static void rk_drm_adapter_close_gem_obj(struct rk_driver_of_gralloc_drm_device_t* rk_drv, uint32_t handle); /*---------------------------------------------------------------------------*/ #if RK_DRM_GRALLOC #if RK_DRM_GRALLOC_DEBUG #ifndef AWAR #define AWAR(fmt, args...) __android_log_print(ANDROID_LOG_WARN, "[Gralloc-Warning]", "%s:%d " fmt,__func__,__LINE__,##args) #endif #ifndef AINF #define AINF(fmt, args...) __android_log_print(ANDROID_LOG_INFO, "[Gralloc]", fmt,##args) #endif #ifndef ADBG #define ADBG(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, "[Gralloc-DEBUG]", fmt,##args) #endif #else #ifndef AWAR #define AWAR(fmt, args...) #endif #ifndef AINF #define AINF(fmt, args...) #endif #ifndef ADBG #define ADBG(fmt, args...) #endif #endif //end of RK_DRM_GRALLOC_DEBUG #ifndef AERR #define AERR(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, "[Gralloc-ERROR]", "%s:%d " fmt,__func__,__LINE__,##args) #endif #ifndef AERR_IF #define AERR_IF( eq, fmt, args...) if ( (eq) ) AERR( fmt, args ) #endif #define GRALLOC_ALIGN( value, base ) (((value) + ((base) - 1)) & ~((base) - 1)) #define ODD_ALIGN(x, align) (((x) % ((align) * 2) == 0) ? ((x) + (align)) : (x)) #define GRALLOC_ODD_ALIGN( value, base ) ODD_ALIGN(GRALLOC_ALIGN(value, base), base) #endif #if RK_CTS_WORKROUND static bool ConvertCharToData(const char *pszHintName, const char *pszData, void *pReturn, IMG_DATA_TYPE eDataType) { bool bFound = false; switch(eDataType) { case IMG_STRING_TYPE: { strcpy((char*)pReturn, pszData); ALOGD_IF(RK_DRM_GRALLOC_DEBUG, "Hint: Setting %s to %s\n", pszHintName, (char*)pReturn); bFound = true; break; } case IMG_FLOAT_TYPE: { *(float*)pReturn = (float) atof(pszData); ALOGD_IF(RK_DRM_GRALLOC_DEBUG, "Hint: Setting %s to %f", pszHintName, *(float*)pReturn); bFound = true; break; } case IMG_UINT_TYPE: case IMG_FLAG_TYPE: { /* Changed from atoi to stroul to support hexadecimal numbers */ *(u32*)pReturn = (u32) strtoul(pszData, NULL, 0); if (*(u32*)pReturn > 9) { ALOGD_IF(RK_DRM_GRALLOC_DEBUG, "Hint: Setting %s to %u (0x%X)", pszHintName, *(u32*)pReturn, *(u32*)pReturn); } else { ALOGD_IF(RK_DRM_GRALLOC_DEBUG, "Hint: Setting %s to %u", pszHintName, *(u32*)pReturn); } bFound = true; break; } case IMG_INT_TYPE: { *(int*)pReturn = (int) atoi(pszData); ALOGD_IF(RK_DRM_GRALLOC_DEBUG, "Hint: Setting %s to %d\n", pszHintName, *(int*)pReturn); bFound = true; break; } default: { ALOGD_IF(RK_DRM_GRALLOC_DEBUG, "ConvertCharToData: Bad eDataType"); break; } } return bFound; } static int getProcessCmdLine(char* outBuf, size_t bufSize) { int ret = 0; FILE* file = NULL; long pid = 0; char procPath[128]={0}; pid = getpid(); sprintf(procPath, "/proc/%ld/cmdline", pid); file = fopen(procPath, "r"); if ( NULL == file ) { ALOGE("fail to open file (%s)",strerror(errno)); } if ( NULL == fgets(outBuf, bufSize - 1, file) ) { ALOGE("fail to read from cmdline_file."); } if ( NULL != file ) { fclose(file); } return ret; } bool FindAppHintInFile(const char *pszFileName, const char *pszAppName, const char *pszHintName, void *pReturn, IMG_DATA_TYPE eDataType) { FILE *regFile; bool bFound = false; regFile = fopen(pszFileName, "r"); if(regFile) { char pszTemp[1024], pszApplicationSectionName[1024]; int iLineNumber; bool bUseThisSection, bInAppSpecificSection; /* Build the section name */ snprintf(pszApplicationSectionName, 1024, "[%s]", pszAppName); bUseThisSection = false; bInAppSpecificSection = false; iLineNumber = -1; while(fgets(pszTemp, 1024, regFile)) { size_t uiStrLen; iLineNumber++; ALOGD_IF(RK_DRM_GRALLOC_DEBUG, "FindAppHintInFile iLineNumber=%d pszTemp=%s",iLineNumber,pszTemp); uiStrLen = strlen(pszTemp); if (pszTemp[uiStrLen-1]!='\n') { ALOGE("FindAppHintInFile : Error in %s at line %u",pszFileName,iLineNumber); continue; } if((uiStrLen >= 2) && (pszTemp[uiStrLen-2] == '\r')) { /* CRLF (Windows) line ending */ pszTemp[uiStrLen-2] = '\0'; } else { /* LF (unix) line ending */ pszTemp[uiStrLen-1] = '\0'; } switch (pszTemp[0]) { case '[': { /* Section */ bUseThisSection = false; bInAppSpecificSection = false; if (!strcmp("[default]", pszTemp)) { bUseThisSection = true; } else if (!strcmp(pszApplicationSectionName, pszTemp)) { bUseThisSection = true; bInAppSpecificSection = true; } break; } default: { char *pszPos; if (!bUseThisSection) { /* This line isn't for us */ continue; } pszPos = strstr(pszTemp, pszHintName); if (pszPos!=pszTemp) { /* Hint name isn't at start of string */ continue; } if (*(pszPos + strlen(pszHintName)) != '=') { /* Hint name isn't exactly correct, or isn't followed by an equals sign */ continue; } /* Move to after the equals sign */ pszPos += strlen(pszHintName) + 1; /* Convert anything after the equals sign to the requested data type */ bFound = ConvertCharToData(pszHintName, pszPos, pReturn, eDataType); if (bFound && bInAppSpecificSection) { /* // If we've found the hint in the application specific section we may // as well drop out now, since this should override any default setting */ fclose(regFile); return true; } break; } } } fclose(regFile); } else { regFile = fopen(pszFileName, "wb+"); if(regFile) { char acBuf[] = "[android.view.cts]\n" "view_cts=0\n" "big_scale=0\n"; fprintf(regFile,"%s",acBuf); fclose(regFile); chmod(pszFileName, 0x777); } else { ALOGE("%s open fail errno=0x%x (%s)",__FUNCTION__, errno,strerror(errno)); } } return bFound; } bool ModifyAppHintInFile(const char *pszFileName, const char *pszAppName, const char *pszHintName, void *pReturn, int pSet, IMG_DATA_TYPE eDataType) { FILE *regFile; bool bFound = false; regFile = fopen(pszFileName, "r+"); if(regFile) { char pszTemp[1024], pszApplicationSectionName[1024]; int iLineNumber; bool bUseThisSection, bInAppSpecificSection; int offset = 0; /* Build the section name */ snprintf(pszApplicationSectionName, 1024, "[%s]", pszAppName); bUseThisSection = false; bInAppSpecificSection = false; iLineNumber = -1; while(fgets(pszTemp, 1024, regFile)) { size_t uiStrLen; iLineNumber++; ALOGD_IF(RK_DRM_GRALLOC_DEBUG, "ModifyAppHintInFile iLineNumber=%d pszTemp=%s",iLineNumber,pszTemp); uiStrLen = strlen(pszTemp); if (pszTemp[uiStrLen-1]!='\n') { ALOGE("FindAppHintInFile : Error in %s at line %u",pszFileName,iLineNumber); continue; } if((uiStrLen >= 2) && (pszTemp[uiStrLen-2] == '\r')) { /* CRLF (Windows) line ending */ pszTemp[uiStrLen-2] = '\0'; } else { /* LF (unix) line ending */ pszTemp[uiStrLen-1] = '\0'; } switch (pszTemp[0]) { case '[': { /* Section */ bUseThisSection = false; bInAppSpecificSection = false; if (!strcmp("[default]", pszTemp)) { bUseThisSection = true; } else if (!strcmp(pszApplicationSectionName, pszTemp)) { bUseThisSection = true; bInAppSpecificSection = true; } break; } default: { char *pszPos; if (!bUseThisSection) { /* This line isn't for us */ offset += uiStrLen; continue; } pszPos = strstr(pszTemp, pszHintName); if (pszPos!=pszTemp) { /* Hint name isn't at start of string */ offset += uiStrLen; continue; } if (*(pszPos + strlen(pszHintName)) != '=') { /* Hint name isn't exactly correct, or isn't followed by an equals sign */ offset += uiStrLen; continue; } /* Move to after the equals sign */ pszPos += strlen(pszHintName) + 1; /* Convert anything after the equals sign to the requested data type */ bFound = ConvertCharToData(pszHintName, pszPos, pReturn, eDataType); if (bFound && bInAppSpecificSection) { offset += (strlen(pszHintName) + 1); if(eDataType == IMG_INT_TYPE && *((int*)pReturn) != pSet) { fseek(regFile, offset, SEEK_SET); fprintf(regFile,"%d",pSet); *((int*)pReturn) = pSet; } /* // If we've found the hint in the application specific section we may // as well drop out now, since this should override any default setting */ fclose(regFile); return true; } break; } } offset += uiStrLen; } fclose(regFile); } else { regFile = fopen(pszFileName, "wb+"); if(regFile) { char acBuf[] = "[android.view.cts]\n" "view_cts=0\n" "big_scale=0\n"; fprintf(regFile,"%s",acBuf); fclose(regFile); chmod(pszFileName, 0x777); } else { ALOGE("%s open faile errno=0x%x (%s)",__FUNCTION__, errno,strerror(errno)); } } return bFound; } #endif static void drm_gem_rockchip_destroy(struct gralloc_drm_drv_t *drv) { struct rk_driver_of_gralloc_drm_device_t *rk_drv = (struct rk_driver_of_gralloc_drm_device_t *)drv; rk_drm_adapter_term(rk_drv); if (rk_drv->rk_drm_dev) rockchip_device_destroy(rk_drv->rk_drm_dev); delete rk_drv; s_rk_drv = NULL; } /* * 根据特定的规则 构建当前 buf 对应的底层 dmabuf 的 name, * 并从 'name' 指向的 buffer 中返回. * * 这里的 dmabuf_name 格式是 : __