1、packages/apps/Settings/src/com/android/settings/display/DrmDisplaySetting.java
public static void updateDisplayModesInfo(DisplayInfo displayInfo) {
RkDisplayOutputManager manager = new RkDisplayOutputManager();
String[] orginModes = manager.getModeList(display, type);
orginModes = filterOrginModes(orginModes);
}
//返回分辨率数组
private static String[] filterOrginModes(String[] modes) {
for (int i = 0; i < modes.length; ++i) {
filterModeList.add(modes[i]);
}
return filterModeList.toArray(new String[0]);
}
这里用到了RkDisplayOutputManager 类,最终被应用程序调用的函数是 updateDisplayModesInfo(),用于更新分辨率
2、frameworks/base/core/java/android/os/RkDisplayOutputManager.java
public String[] getModeList(int display, int type) {
String iface = typetoface(type);
try {
return mService.getModelist(display, iface);
} catch (Exception e) {
Log.e(TAG, "Error get list mode :" + e);
return null;
}
}
这里使用到了mService的getModelist方法,而mService是进程间通信,如下:
IBinder b = ServiceManager.getService("drm_device_management");
mService = IRkDisplayDeviceManagementService.Stub.asInterface(b);
3、对应的aidl文件在:frameworks/base/core/java/android/os/IRkDisplayDeviceManagementService.aidl
4、实现类在:frameworks/base/services/core/java/com/android/server/RkDisplayDeviceManagementService.java
class RkDisplayDeviceManagementService extends IRkDisplayDeviceManagementService.Stub {
public RkDisplayDeviceManagementService(Context context) {
mContext = context;
mdrmModes = new RkDisplayModes();
mdrmModes.init();
IntentFilter hdmiFilter = new IntentFilter();
hdmiFilter.addAction(ACTION_PLUGGED);
mHdmiReceiver = new HdmiReceiver(mdrmModes);
mContext.registerReceiver(mHdmiReceiver,hdmiFilter);
}
public String[] getModelist(int display, String iface){
List<String> hdmiResoList = mdrmModes.getModeList(display);
return hdmiResoList.toArray(new String[hdmiResoList.size()]);
}
}
5、这里有出现一个新的类RkDisplayModes.java并且调佣了该类的getModeList方法
frameworks/base/services/core/java/com/android/server/rkdisplay/RkDisplayModes.java
public List<String> getModeList(int dpy){
List<String> modeList = new ArrayList<>();
Log.e(TAG, "getModeList =========== dpy " + dpy);
//readModeWhiteList(RESOLUTION_XML_PATH);
mDisplayInfos = getDisplayConfigs(dpy);
if (dpy == 0)
mMainDisplayInfos = mDisplayInfos;
else
mAuxDisplayInfos = mDisplayInfos;
if (mDisplayInfos != null) {
modeList.add("Auto");
for (int i = 0; i < mDisplayInfos.length; i++){
boolean found=false;
RkDisplayModes.RkPhysicalDisplayInfo info = mDisplayInfos[i];
StringBuilder builder = new StringBuilder();
builder.append(info.width).append("x").append(info.height);
if (info.interlaceFlag == true) {
builder.append("i");
builder.append(String.format("%.2f", info.refreshRate));
} else {
builder.append("p");
builder.append(String.format("%.2f", info.refreshRate));
}
//builder.append("@");
builder.append("-").append(info.idx);
boolean existingMode = false;
if (resolutions == null || IsResolutionNeedFilter(dpy)) {
modeList.add(builder.toString());
} else {
for (int j = 0; j < resolutions.size(); j++) {
if (resolutions.get(j).hasMatchingMode(info)) {
existingMode = true;
break;
}
}
if (existingMode) {
modeList.add(builder.toString());
}
}
}
} else {
modeList = null;
}
return modeList;
}
从改方法我们可以看到,点击HDMI分辨率设置显示出来的第一个Auto就是在这里添加的,还有其它分辨率也是这里的getDisplayConfigs(dpy);获取到的,继续跟踪getDisplayConfigs函数
public static RkDisplayModes.RkPhysicalDisplayInfo[] getDisplayConfigs(int dpy) {
return nativeGetDisplayConfigs(dpy);
}
这下芭比Q了,到native去了,又是一顿猛找,终于发现对应的native方法在frameworks/base/services/core/jni/com_android_server_rkdisplay_RkDisplayModes.cpp
static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,jint dpy) {
hidl_vec<RkDrmMode> mModes;
if (mComposer != nullptr)
{
mComposer->getDisplayModes(dpy,
[&](const auto& tmpResult, const auto& tmpModes)
{
if (tmpResult == Result::OK) {
mModes = tmpModes;
}
});
}
jobjectArray configArray = env->NewObjectArray(mModes.size(),
gRkPhysicalDisplayInfoClassInfo.clazz, NULL);
for (size_t c=0;c<mModes.size();c++) {
RkDrmMode tmpMode = mModes[c];
jobject infoObj = env->NewObject(gRkPhysicalDisplayInfoClassInfo.clazz,
gRkPhysicalDisplayInfoClassInfo.ctor);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.width, tmpMode.width);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.height, tmpMode.height);
env->SetFloatField(infoObj, gRkPhysicalDisplayInfoClassInfo.refreshRate, tmpMode.refreshRate);//1000 * 1000 * 1000 /
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.clock, tmpMode.clock);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.flags, tmpMode.flags);
env->SetBooleanField(infoObj, gRkPhysicalDisplayInfoClassInfo.interlaceFlag,
tmpMode.interlaceFlag>0?1:0);
env->SetBooleanField(infoObj, gRkPhysicalDisplayInfoClassInfo.yuvFlag, tmpMode.yuvFlag>0?1:0);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.connectorId, tmpMode.connectorId);//mode_type
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.mode_type, tmpMode.mode_type);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.idx, tmpMode.idx);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.hsync_start, tmpMode.hsync_start);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.hsync_end, tmpMode.hsync_end);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.htotal, tmpMode.htotal);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.hskew, tmpMode.hskew);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.vsync_start, tmpMode.vsync_start);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.vsync_end, tmpMode.vsync_end);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.vtotal, tmpMode.vtotal);
env->SetIntField(infoObj, gRkPhysicalDisplayInfoClassInfo.vscan, tmpMode.vscan);
env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
env->DeleteLocalRef(infoObj);
}
return configArray;
}
这里的关键代码为:mComposer->getDisplayModes,
sp<IRkOutputManager> mComposer = nullptr;
mComposer = IRkOutputManager::getService();
继续跟踪getService
找了好久没找到,有知道的大佬请告知
上面的调用流程我会继续跟踪,先提一下在系统启动之后的设置界面选择HDMI分辨率的问题。
显示出来给用户选择的分辨率是在kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c的dw_hdmi_default_modes数组里面添加的,添加完成之后到Android层还需要经过过滤,过滤函数在frameworks/base/services/core/java/com/android/server/rkdisplay/RkDisplayModes.java
public List<String> getModeList(int dpy){
boolean existingMode = false;
if (resolutions == null || IsResolutionNeedFilter(dpy)) {
modeList.add(builder.toString());
} else {
for (int j = 0; j < resolutions.size(); j++) {
if (resolutions.get(j).hasMatchingMode(info)) {
existingMode = true;
break;
}
}
if (existingMode) {
modeList.add(builder.toString());
}
}
}
在上面这个函数里,首先判断resolutions是否有值,就是是否存在resolution_white.xml白名单列表文件,如果存在就使用白名单里面的分辨率,所以如果要屏蔽过滤修改这里就可以了
而变量resolutions又是在readModeWhiteList函数里面被赋值的
private static List<ResolutionParser.RkResolutionInfo> resolutions=null;
private static boolean readModeWhiteList(String pathname) {
InputStream is;
try {
is = new FileInputStream(RESOLUTION_XML_PATH);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + RESOLUTION_XML_PATH + ".");
return false;
}
resolutions=null;
try {
resolutions = mParser.parse(is);
is.close();
} catch (Exception e) {
Log.e(TAG, "Couldn't get resolutions path " + RESOLUTION_XML_PATH + ".");
return false;
}
//logd("readStrListFromFile - " + fileStrings.toString());
return true;
}