Android 4.0新增WIFI DIRECT的功能,但是在模擬器上以及一些可以升級至4.0的手機或平板,在settings里面仍然沒(méi)有WIFI DIRECT功能選項。于是出于好奇,所以跟蹤了一
下源碼。
1. 查找在系統設置包中是否有WIFI DIRECT這部分代碼處理。
在A(yíng)ndroid4.0的源碼路徑(我的是源碼路徑為:myandroid_4.0)/packages/apps/Settings/src/com/android/settings/wifi中發(fā)現有P2P這個(gè)文件夾,哪說(shuō)明設置包里面具有WIFI DIRECT這部分的代碼處理。
2. 查找在系統設置里對WIFI DIRECT是否有過(guò)濾。
跟蹤Settings包源碼,終于發(fā)現苗頭:在WirelessSettings.java (myandroid_4.0\packages\apps\settings\src\com\android\settings) 文件中
[java]
view plaincopy@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
..........................................
...........................................
WifiP2pManager p2p = (WifiP2pManager) activity.getSystemService(Context.WIFI_P2P_SERVICE);
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) {
getPreferenceScreen().removePreference(wifiP2p);
} else {
mWifiP2pEnabler = new WifiP2pEnabler(activity, wifiP2p);
}
...........................................
...........................................
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";//即為傳進(jìn)去做判斷的String。
2)分析getPackageManager()函數
文件SettingsPreferenceFragment.java (packages\apps\settings\src\com\android\settings)中,
[java]
view plaincopy...................................
...................................
/**
* Returns the PackageManager from the owning Activity.
*/
protected PackageManager getPackageManager() {
return getActivity().getPackageManager();
}
...................................
...................................
分析getAcivity()返回一個(gè)Activity。Activity.java (frameworks\base\core\java\android\app) 中沒(méi)有 getPackageManager()函數;
由于public class Activity extends ContextThemeWrapper,所以進(jìn)入文件ContextThemeWrapper.java (frameworks\base\core\java\android\view)中,
也沒(méi)有g(shù)etPackageManager()函數,同理發(fā)現public class ContextThemeWrapper extends ContextWrapper,所以進(jìn)入文件ContextWrapper.java (frameworks\base\core\java\android\content) ,此時(shí)終于見(jiàn)到getPackageManager()蹤影:
public class ContextWrapper extends Context {
Context mBase;
....................................
....................................
@Override
public PackageManager getPackageManager() {
return mBase.getPackageManager();
}
.....................................
......................................
}
繼續跟蹤文件Context.java (frameworks\base\core\java\android\content),發(fā)現getPackageManager()是一個(gè)抽象函數:
/** Return PackageManager instance to find global package information. */
public abstract PackageManager getPackageManager();
分析到這里其實(shí)我也不知到該怎么繼續跟蹤這個(gè)函數了,想想是否跟這個(gè)文件(因為class ContextImpl extends Context)有關(guān)聯(lián)ContextImpl.java (frameworks\base\core\java\android\app),的確找到了關(guān)心的代碼:
[java]
view plaincopy@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
因為 final class ApplicationPackageManager extends PackageManager,所以從上面代碼分析getPackageManager()返回一個(gè)ApplicationPackageManager.
3) 分析getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)
由上面分析而知,getPackageManager().hasSystemFeature函數應該調到文件ApplicationPackageManager.java (frameworks\base\core\java\android\app) ,
[java]
view plaincopyfinal class ApplicationPackageManager extends PackageManager {
..............................
..............................
@Override
public boolean hasSystemFeature(String name) {
try {
return mPM.hasSystemFeature(name);
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
..............................
...............................
}
mPM.hasSystemFeature(name)經(jīng)過(guò)AIDL實(shí)際上調用到文件PackageManagerService.java (frameworks\base\services\java\com\android\server\pm)
[java]
view plaincopypublic class PackageManagerService extends IPackageManager.Stub {
....................................
....................................
public boolean hasSystemFeature(String name) {
synchronized (mPackages) {
return mAvailableFeatures.containsKey(name);
}
}
...................................
...................................
}
mAvailableFeatures里面的內容是通過(guò)讀取/system/etc/permissions下面的文檔。具體代碼如下所示:
[java]
view plaincopyvoid readPermissions() {
// Read permissions from .../etc/permission directory.
File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
Slog.w(TAG, "No directory " + libraryDir + ", skipping");
return;
}
if (!libraryDir.canRead()) {
Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
return;
}
// Iterate over the files in the directory and scan .xml files
for (File f : libraryDir.listFiles()) {
// We'll read platform.xml last
if (f.getPath().endsWith("etc/permissions/platform.xml")) {
continue;
}
if (!f.getPath().endsWith(".xml")) {
Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
continue;
}
if (!f.canRead()) {
Slog.w(TAG, "Permissions library file " + f + " cannot be read");
continue;
}
readPermissionsFromXml(f);
}
// Read permissions from .../etc/permissions/platform.xml last so it will take precedence
final File permFile = new File(Environment.getRootDirectory(),
"etc/permissions/platform.xml");
readPermissionsFromXml(permFile);
}
private void readPermissionsFromXml(File permFile) {
FileReader permReader = null;
try {
permReader = new FileReader(permFile);
} catch (FileNotFoundException e) {
Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
return;
}
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(permReader);
XmlUtils.beginDocument(parser, "permissions");
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
break;
}
String name = parser.getName();
if ("group".equals(name)) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = Integer.parseInt(gidStr);
mGlobalGids = appendInt(mGlobalGids, gid);
} else {
Slog.w(TAG, "<group> without gid at "
+ parser.getPositionDescription());
}
XmlUtils.skipCurrentTag(parser);
continue;
}
...................
...................
else if ("feature".equals(name)) {
String fname = parser.getAttributeValue(null, "name");
if (fname == null) {
Slog.w(TAG, "<feature> without name at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got feature " + fname);
FeatureInfo fi = new FeatureInfo();
fi.name = fname;
mAvailableFeatures.put(fname, fi);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else {
XmlUtils.skipCurrentTag(parser);
continue;
}
}
permReader.close();
} catch (XmlPullParserException e) {
Slog.w(TAG, "Got execption parsing permissions.", e);
} catch (IOException e) {
Slog.w(TAG, "Got execption parsing permissions.", e);
}
}
3. 驗證上面代碼分析的正確性。
1) 啟動(dòng)一個(gè)ANDROID 4.0的模擬器,然后通過(guò)adb shell進(jìn)入/system/etc/permissions目錄下查看,
# cd /system/etc/permissions
# ls
com.android.location.provider.xml
platform.xml
#
的確沒(méi)有android.hardware.wifi.direct.xml文件。
2) 因為在源碼/frameworks/base/data/etc中有android.hardware.wifi.direct.xml文件,所以我手動(dòng)拷貝此文件到out/target/product/generic/system/etc/permissions/
目錄下,然后編譯源碼,然后用命令行指定編譯完成的system.img,userdata.img,ramdisk.img來(lái)啟動(dòng)模擬器:
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的設置項了,如圖所示:
只是點(diǎn)擊時(shí)彈出錯誤框提示“Couldn't start Wi-Fi Direct”,簡(jiǎn)單的跟蹤了一下是WifiP2pService.java中有WifiNative.startP2pSupplicant()的一個(gè)判斷,跟到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); //這個(gè)應該是硬件方面的判斷。
}
沒(méi)有再繼續跟蹤下去了,至少關(guān)于WIFI P2P設置的過(guò)濾過(guò)程已經(jīng)清楚了。