Android4.0中判断WIFI P2P选项是否显示的源码分析

Android 4.0新增WIFI DIRECT的功能,但是在模拟器上以及一些可以升级至4.0的手机或平板,在settings里面仍然没有WIFI DIRECT功能选项。于是出于好奇,所以跟踪了一

下源码。

1.  查找在系统设置包中是否有WIFI DIRECT这部分代码处理。

在Android4.0的源码路径(我的是源码路径为:myandroid_4.0)/packages/apps/Settings/src/com/android/settings/wifi中发现有P2P这个文件夹,哪说明设置包里面具有WIFI DIRECT这部分的代码处理。

2.   查找在系统设置里对WIFI DIRECT是否有过滤。

跟踪Settings包源码,终于发现苗头:在WirelessSettings.java (myandroid_4.0\packages\apps\settings\src\com\android\settings) 文件中

  1. @Override 
  2. public void onCreate(Bundle savedInstanceState) { 
  3. super.onCreate(savedInstanceState); 
  4. .......................................... 
  5. ........................................... 
  6. WifiP2pManager p2p = (WifiP2pManager) activity.getSystemService(Context.WIFI_P2P_SERVICE); 
  7. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) { 
  8. getPreferenceScreen().removePreference(wifiP2p); 
  9. } else { 
  10. mWifiP2pEnabler = new WifiP2pEnabler(activity, wifiP2p); 
  11. ........................................... 
  12. ........................................... 

1)分析PackageManager.FEATURE_WIFI_DIRECT:文件PackageManager.java (frameworks\base\core\java\android\content\pm) 中:

@SdkConstant(SdkConstantType.FEATURE)

public static final String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";//即为传进去做判断的String。

2)分析getPackageManager()函数

文件SettingsPreferenceFragment.java (packages\apps\settings\src\com\android\settings)中,

  1. ................................... 
  2. ................................... 
  3. /**
  4. * Returns the PackageManager from the owning Activity.
  5. */ 
  6. protected PackageManager getPackageManager() { 
  7. return getActivity().getPackageManager(); 
  8. ................................... 
  9. ................................... 

分析getAcivity()返回一个Activity。Activity.java (frameworks\base\core\java\android\app) 中没有 getPackageManager()函数;

由于public class Activity extends ContextThemeWrapper,所以进入文件ContextThemeWrapper.java (frameworks\base\core\java\android\view)中,

也没有getPackageManager()函数,同理发现public class ContextThemeWrapper extends ContextWrapper,所以进入文件ContextWrapper.java (frameworks\base\core\java\android\content) ,此时终于见到getPackageManager()踪影:

public class ContextWrapper extends Context {

Context mBase;

....................................

....................................

@Override

public PackageManager getPackageManager() {

return mBase.getPackageManager();

}

.....................................

......................................

}

继续跟踪文件Context.java (frameworks\base\core\java\android\content),发现getPackageManager()是一个抽象函数:

/** Return PackageManager instance to find global package information. */

public abstract PackageManager getPackageManager();

分析到这里其实我也不知到该怎么继续跟踪这个函数了,想想是否跟这个文件(因为class ContextImpl extends Context)有关联ContextImpl.java (frameworks\base\core\java\android\app),的确找到了关心的代码:

  1. @Override 
  2. public PackageManager getPackageManager() { 
  3. if (mPackageManager != null) { 
  4. return mPackageManager; 
  5. IPackageManager pm = ActivityThread.getPackageManager(); 
  6. if (pm != null) { 
  7. // Doesn't matter if we make more than one instance. 
  8. return (mPackageManager = new ApplicationPackageManager(this, pm)); 
  9. return null; 

因为 final class ApplicationPackageManager extends PackageManager,所以从上面代码分析getPackageManager()返回一个ApplicationPackageManager. 

3)  分析getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)

由上面分析而知,getPackageManager().hasSystemFeature函数应该调到文件ApplicationPackageManager.java (frameworks\base\core\java\android\app) ,

  1. final class ApplicationPackageManager extends PackageManager { 
  2. .............................. 
  3. .............................. 
  4. @Override 
  5. public boolean hasSystemFeature(String name) { 
  6. try { 
  7. return mPM.hasSystemFeature(name); 
  8. } catch (RemoteException e) { 
  9. throw new RuntimeException("Package manager has died", e); 
  10. .............................. 
  11. ............................... 

mPM.hasSystemFeature(name)经过AIDL实际上调用到文件PackageManagerService.java (frameworks\base\services\java\com\android\server\pm) 

  1. public class PackageManagerService extends IPackageManager.Stub { 
  2. .................................... 
  3. .................................... 
  4. public boolean hasSystemFeature(String name) { 
  5. synchronized (mPackages) { 
  6. return mAvailableFeatures.containsKey(name); 
  7. ................................... 
  8. ................................... 

mAvailableFeatures里面的内容是通过读取/system/etc/permissions下面的文档。具体代码如下所示:

  1. void readPermissions() { 
  2. // Read permissions from .../etc/permission directory. 
  3. File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions"); 
  4. if (!libraryDir.exists() || !libraryDir.isDirectory()) { 
  5. Slog.w(TAG, "No directory " + libraryDir + ", skipping"); 
  6. return; 
  7. if (!libraryDir.canRead()) { 
  8. Slog.w(TAG, "Directory " + libraryDir + " cannot be read"); 
  9. return; 
  10. // Iterate over the files in the directory and scan .xml files 
  11. for (File f : libraryDir.listFiles()) { 
  12. // We'll read platform.xml last 
  13. if (f.getPath().endsWith("etc/permissions/platform.xml")) { 
  14. continue; 
  15. if (!f.getPath().endsWith(".xml")) { 
  16. Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring"); 
  17. continue; 
  18. if (!f.canRead()) { 
  19. Slog.w(TAG, "Permissions library file " + f + " cannot be read"); 
  20. continue; 
  21. readPermissionsFromXml(f); 
  22. // Read permissions from .../etc/permissions/platform.xml last so it will take precedence 
  23. final File permFile = new File(Environment.getRootDirectory(), 
  24. "etc/permissions/platform.xml"); 
  25. readPermissionsFromXml(permFile); 
  26. private void readPermissionsFromXml(File permFile) { 
  27. FileReader permReader = null; 
  28. try { 
  29. permReader = new FileReader(permFile); 
  30. } catch (FileNotFoundException e) { 
  31. Slog.w(TAG, "Couldn't find or open permissions file " + permFile); 
  32. return; 
  33. try { 
  34. XmlPullParser parser = Xml.newPullParser(); 
  35. parser.setInput(permReader); 
  36. XmlUtils.beginDocument(parser, "permissions"); 
  37. while (true) { 
  38. XmlUtils.nextElement(parser); 
  39. if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { 
  40. break; 
  41. String name = parser.getName(); 
  42. if ("group".equals(name)) { 
  43. String gidStr = parser.getAttributeValue(null, "gid"); 
  44. if (gidStr != null) { 
  45. int gid = Integer.parseInt(gidStr); 
  46. mGlobalGids = appendInt(mGlobalGids, gid); 
  47. } else { 
  48. Slog.w(TAG, "<group> without gid at " 
  49. + parser.getPositionDescription()); 
  50. XmlUtils.skipCurrentTag(parser); 
  51. continue; 
  52. }  
  53. ................... 
  54. ................... 
  55. else if ("feature".equals(name)) { 
  56. String fname = parser.getAttributeValue(null, "name"); 
  57. if (fname == null) { 
  58. Slog.w(TAG, "<feature> without name at " 
  59. + parser.getPositionDescription()); 
  60. } else { 
  61. //Log.i(TAG, "Got feature " + fname); 
  62. FeatureInfo fi = new FeatureInfo(); 
  63. fi.name = fname; 
  64. mAvailableFeatures.put(fname, fi); 
  65. XmlUtils.skipCurrentTag(parser); 
  66. continue; 
  67. } else { 
  68. XmlUtils.skipCurrentTag(parser); 
  69. continue; 
  70. permReader.close(); 
  71. } catch (XmlPullParserException e) { 
  72. Slog.w(TAG, "Got execption parsing permissions.", e); 
  73. } catch (IOException e) { 
  74. Slog.w(TAG, "Got execption parsing permissions.", e); 

3.    验证上面代码分析的正确性。

1) 启动一个ANDROID 4.0的模拟器,然后通过adb shell进入/system/etc/permissions目录下查看,

# cd /system/etc/permissions

# ls

com.android.location.provider.xml

platform.xml

#

的确没有android.hardware.wifi.direct.xml文件。

2) 因为在源码/frameworks/base/data/etc中有android.hardware.wifi.direct.xml文件,所以我手动拷贝此文件到out/target/product/generic/system/etc/permissions/

目录下,然后编译源码,然后用命令行指定编译完成的system.img,userdata.img,ramdisk.img来启动模拟器:

XXX@XXX:~/Android_code/system_img$ /home/XXX/Android_install/android-sdk-linux_x86/tools/emulator  -system system.img -data userdata.img -ramdisk ramdisk.img  -partition-size 256 -avd Android4.0.3-APILevel15

然后在模拟器设置中看到了WiFi Direct的设置项了,如图所示:

只是点击时弹出错误框提示“Couldn't start Wi-Fi Direct”,简单的跟踪了一下是WifiP2pService.java中有WifiNative.startP2pSupplicant()的一个判断,跟到JNI层

WifiP2pService.java (frameworks\base\wifi\java\android\net\wifi\p2p)

static jboolean android_net_wifi_startP2pSupplicant(JNIEnv* env, jobject)

{

return (jboolean)(::wifi_start_p2p_supplicant() == 0); //这个应该是硬件方面的判断。

}

没有再继续跟踪下去了,至少关于WIFI P2P设置的过滤过程已经清楚了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值