<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 101,  comments - 29,  trackbacks - 0

            通過前面的學(xué)習(xí),我們知道在Android系統(tǒng)中,Content Provider可以為不同的應(yīng)用程序訪問相同的數(shù)據(jù)提供統(tǒng)一的入口。Content Provider一般是運(yùn)行在獨(dú)立的進(jìn)程中的,每一個(gè)Content Provider在系統(tǒng)中只有一個(gè)實(shí)例存在,其它應(yīng)用程序首先要找到這個(gè)實(shí)例,然后才能訪問它的數(shù)據(jù)。那么,系統(tǒng)中的Content Provider實(shí)例是由誰來負(fù)責(zé)啟動(dòng)的呢?本文將回答這個(gè)問題。

            Content Provider和應(yīng)用程序組件Activity、Service一樣,需要在AndroidManifest.xml文件中配置之后才能使用。系統(tǒng)在安裝包含Content Provider的應(yīng)用程序的時(shí)候,會(huì)把這些Content Provider的描述信息保存起來,其中最重要的就是Content Provider的Authority信息,Android應(yīng)用程序的安裝過程具體可以參考Android應(yīng)用程序安裝過程源代碼分析一文。注意,安裝應(yīng)用程序的時(shí)候,并不會(huì)把相應(yīng)的Content Provider加載到內(nèi)存中來,系統(tǒng)采取的是懶加載的機(jī)制,等到第一次要使用這個(gè)Content Provider的時(shí)候,系統(tǒng)才會(huì)把它加載到內(nèi)存中來,下次再要使用這個(gè)Content Provider的時(shí)候,就可以直接返回了。

            本文以前面一篇文章Android應(yīng)用程序組件Content Provider應(yīng)用實(shí)例中的例子來詳細(xì)分析Content Provider的啟動(dòng)過程。Android應(yīng)用程序組件Content Provider應(yīng)用實(shí)例這篇文章介紹的應(yīng)用程序Article中,第一次使用ArticlesProvider這個(gè)Content Provider的地方是ArticlesAdapter類的getArticleCount函數(shù),因?yàn)镸ainActivity要在ListView中顯示文章信息列表時(shí), 首先要知道ArticlesProvider中的文章信息的數(shù)量。從ArticlesAdapter類的getArticleCount函數(shù)調(diào)用開始,一直到ArticlesProvider類的onCreate函數(shù)被調(diào)用,就是ArticlesProvider的完整啟動(dòng)過程,下面我們就先看看這個(gè)過程的序列圖,然后再詳細(xì)分析每一個(gè)步驟:


            Step 1. ArticlesAdapter.getArticleCount

            這個(gè)函數(shù)定義在前面一篇文章Android應(yīng)用程序組件Content Provider應(yīng)用實(shí)例介紹的應(yīng)用程序Artilce源代碼工程目錄下,在文件為packages/experimental/Article/src/shy/luo/article/ArticlesAdapter.java中:

    public class ArticlesAdapter {
    	......
    
    	private ContentResolver resolver = null;
    
    	public ArticlesAdapter(Context context) {
    		resolver = context.getContentResolver();
    	}
    
    	......
    
    	public int getArticleCount() {
    		int count = 0;
    
    		try {
    			IContentProvider provider = resolver.acquireProvider(Articles.CONTENT_URI);
    			Bundle bundle = provider.call(Articles.METHOD_GET_ITEM_COUNT, null, null);
    			count = bundle.getInt(Articles.KEY_ITEM_COUNT, 0);
    		} catch(RemoteException e) {
    			e.printStackTrace();
    		}
    
    		return count;
    	}
    
    	......
    }
             這個(gè)函數(shù)通過應(yīng)用程序上下文的ContentResolver接口resolver的acquireProvider函數(shù)來獲得與Articles.CONTENT_URI對(duì)應(yīng)的Content Provider對(duì)象的IContentProvider接口。常量Articles.CONTENT_URI是在應(yīng)用程序ArticlesProvider中定義的,它的值為“content://shy.luo.providers.articles/item”,對(duì)應(yīng)的Content Provider就是ArticlesProvider了。

             Step 2. ContentResolver.acqireProvider

             這個(gè)函數(shù)定義在frameworks/base/core/java/android/content/ContentResolver.java文件中:

    public abstract class ContentResolver {
    	......
    
    	public final IContentProvider acquireProvider(Uri uri) {
    		if (!SCHEME_CONTENT.equals(uri.getScheme())) {
    			return null;
    		}
    		String auth = uri.getAuthority();
    		if (auth != null) {
    			return acquireProvider(mContext, uri.getAuthority());
    		}
    		return null;
    	}
    
    	......
    }
            函數(shù)首先驗(yàn)證參數(shù)uri的scheme是否正確,即是否是以content://開頭,然后取出它的authority部分,最后調(diào)用另外一個(gè)成員函數(shù)acquireProvider執(zhí)行獲取ContentProvider接口的操作。在我們這個(gè)情景中,參數(shù)uri的authority的內(nèi)容便是“shy.luo.providers.articles”了。

            從ContentResolver類的定義我們可以看出,它是一個(gè)抽象類,兩個(gè)參數(shù)版本的acquireProvider函數(shù)是由它的子類來實(shí)現(xiàn)的。回到Step 1中,這個(gè)ContentResolver接口是通過應(yīng)用程序上下文Context對(duì)象的getContentResolver函數(shù)來獲得的,而應(yīng)用程序上下文Context是由ContextImpl類來實(shí)現(xiàn)的,它定義在frameworks/base/core/java/android/app/ContextImpl.java文件中:

    class ContextImpl extends Context {
    	......
    
    	private ApplicationContentResolver mContentResolver;
    
    	......
    
    	final void init(LoadedApk packageInfo,
    			IBinder activityToken, ActivityThread mainThread,
    			Resources container) {
    		......
    
    		mContentResolver = new ApplicationContentResolver(this, mainThread);
    
    		......
    	}
    
    	......
    
    	@Override
    	public ContentResolver getContentResolver() {
    		return mContentResolver;
    	}
    
    	......
    }
             ContextImpl類的init函數(shù)是在應(yīng)用程序啟動(dòng)的時(shí)候調(diào)用的,具體可以參考Android應(yīng)用程序啟動(dòng)過程源代碼分析一文中的Step 34。

             因此,在上面的ContentResolver類的acquireProvider函數(shù)里面接下來要調(diào)用的ApplicationContentResolver類的acquireProvider函數(shù)。

             Step 3. ApplicationContentResolve.acquireProvider

             這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ContextImpl.java文件中:

    class ContextImpl extends Context {
    	......
    
    	private static final class ApplicationContentResolver extends ContentResolver {
    		......
    
    		@Override
    		protected IContentProvider acquireProvider(Context context, String name) {
    			return mMainThread.acquireProvider(context, name);
    		}
    
    		......
    
    		private final ActivityThread mMainThread;
    	}
    
    	......
    }
             它調(diào)用ActivityThread類的acquireProvider函數(shù)進(jìn)一步執(zhí)行獲取Content Provider接口的操作。

             Step 4. ActivityThread.acquireProvider

             這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:

    public final class ActivityThread {
    	......
    
    	public final IContentProvider acquireProvider(Context c, String name) {
    		IContentProvider provider = getProvider(c, name);
    		if(provider == null)
    			return null;
    		......
    		return provider;
    	}
    
    	......
    }
             它又是調(diào)用了另外一個(gè)成員函數(shù)getProvider來進(jìn)一步執(zhí)行獲取Content Provider接口的操作。

             Step 5. ActivityThread.getProvider

             這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:

    public final class ActivityThread {
    	......
    
    	private final IContentProvider getExistingProvider(Context context, String name) {
    		synchronized(mProviderMap) {
    			final ProviderClientRecord pr = mProviderMap.get(name);
    			if (pr != null) {
    				return pr.mProvider;
    			}
    			return null;
    		}
    	}
    
    	......
    
    	private final IContentProvider getProvider(Context context, String name) {
    		IContentProvider existing = getExistingProvider(context, name);
    		if (existing != null) {
    			return existing;
    		}
    
    		IActivityManager.ContentProviderHolder holder = null;
    		try {
    			holder = ActivityManagerNative.getDefault().getContentProvider(
    				getApplicationThread(), name);
    		} catch (RemoteException ex) {
    		}
    
    		IContentProvider prov = installProvider(context, holder.provider,
    			holder.info, true);
    
    		......
    
    		return prov;
    	}
    
    	......
    }

             這個(gè)函數(shù)首先會(huì)通過getExistingProvider函數(shù)來檢查本地是否已經(jīng)存在這個(gè)要獲取的ContentProvider接口,如果存在,就直接返回了。本地已經(jīng)存在的ContextProvider接口保存在ActivityThread類的mProviderMap成員變量中,以ContentProvider對(duì)應(yīng)的URI的authority為鍵值保存。在我們這個(gè)情景中,因?yàn)槭堑谝淮握{(diào)用ArticlesProvider接口,因此,這時(shí)候通過getExistingProvider函數(shù)得到的IContentProvider接口為null,于是下面就會(huì)調(diào)用ActivityManagerService服務(wù)的getContentProvider接口來獲取一個(gè)ContentProviderHolder對(duì)象holder,這個(gè)對(duì)象就包含了我們所要獲取的ArticlesProvider接口,在將這個(gè)接口返回給調(diào)用者之后,還會(huì)調(diào)用installProvider函數(shù)來把這個(gè)接口保存在本地中,以便下次要使用這個(gè)ContentProvider接口時(shí),直接就可以通過getExistingProvider函數(shù)獲取了。

            我們先進(jìn)入到ActivityManagerService服務(wù)的getContentProvider函數(shù)中看看它是如何獲取我們所需要的ArticlesProvider接口的,然后再返回來看看installProvider函數(shù)的實(shí)現(xiàn)。

            Step 6. ActivityManagerService.getContentProvider

            這個(gè)函數(shù)定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

    public final class ActivityManagerService extends ActivityManagerNative
    		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    	......
    
    	public final ContentProviderHolder getContentProvider(
    			IApplicationThread caller, String name) {
    		......
    
    		return getContentProviderImpl(caller, name);
    	}
    
    	......
    }
            它調(diào)用getContentProviderImpl函數(shù)來進(jìn)一步執(zhí)行操作。

            Step 7. ActivityManagerService.getContentProviderImpl

            這個(gè)函數(shù)定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

    public final class ActivityManagerService extends ActivityManagerNative
    		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    	......
    
    	private final ContentProviderHolder getContentProviderImpl(
    			IApplicationThread caller, String name) {
    		ContentProviderRecord cpr;
    		ProviderInfo cpi = null;
    
    		synchronized(this) {
    			ProcessRecord r = null;
    			if (caller != null) {
    				r = getRecordForAppLocked(caller);
    				......
    			}
    
    			// First check if this content provider has been published...
    			cpr = mProvidersByName.get(name);
    			if (cpr != null) {
    				......
    			} else {
    				try {
    					cpi = AppGlobals.getPackageManager().
    						resolveContentProvider(name,
    						STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
    				} catch (RemoteException ex) {
    				}
    				......
    			}
    
    			cpr = mProvidersByClass.get(cpi.name);
    			final boolean firstClass = cpr == null;
    			if (firstClass) {
    				try {
    					ApplicationInfo ai =
    						AppGlobals.getPackageManager().
    						getApplicationInfo(
    						cpi.applicationInfo.packageName,
    						STOCK_PM_FLAGS);
    					......
    					cpr = new ContentProviderRecord(cpi, ai);
    				} catch (RemoteException ex) {
    					// pm is in same process, this will never happen.
    				}
    			}
    
    			if (r != null && cpr.canRunHere(r)) {
    				// If this is a multiprocess provider, then just return its
    				// info and allow the caller to instantiate it.  Only do
    				// this if the provider is the same user as the caller's
    				// process, or can run as root (so can be in any process).
    				return cpr;
    			}
    
    			......
    
    			// This is single process, and our app is now connecting to it.
    			// See if we are already in the process of launching this
    			// provider.
    			final int N = mLaunchingProviders.size();
    			int i;
    			for (i=0; i<N; i++) {
    				if (mLaunchingProviders.get(i) == cpr) {
    					break;
    				}
    			}
    
    			// If the provider is not already being launched, then get it
    			// started.
    			if (i >= N) {
    				final long origId = Binder.clearCallingIdentity();
    				ProcessRecord proc = startProcessLocked(cpi.processName,
    					cpr.appInfo, false, 0, "content provider",
    					new ComponentName(cpi.applicationInfo.packageName,
    					cpi.name), false);
    				......
    				mLaunchingProviders.add(cpr);
    				......
    			}
    
    			// Make sure the provider is published (the same provider class
    			// may be published under multiple names).
    			if (firstClass) {
    				mProvidersByClass.put(cpi.name, cpr);
    			}
    			cpr.launchingApp = proc;
    			mProvidersByName.put(name, cpr);
    
    			......
    		}
    
    		// Wait for the provider to be published...
    		synchronized (cpr) {
    			while (cpr.provider == null) {
    				......
    				try {
    					cpr.wait();
    				} catch (InterruptedException ex) {
    				}
    			}
    		}
    
    		return cpr;
    	}
    	
    	......
    }
            這個(gè)函數(shù)比較長(zhǎng),我們一步一步地分析。
            函數(shù)首先是獲取調(diào)用者的進(jìn)程記錄塊信息:

    ProcessRecord r = null;
    if (caller != null) {
    	r = getRecordForAppLocked(caller);
    	......
    }
            在我們這個(gè)情景中,要獲取的就是應(yīng)用程序Article的進(jìn)程記錄塊信息了,后面會(huì)用到。

            在ActivityManagerService中,有兩個(gè)成員變量是用來保存系統(tǒng)中的Content Provider信息的,一個(gè)是mProvidersByName,一個(gè)是mProvidersByClass,前者是以Content Provider的authoriry值為鍵值來保存的,后者是以Content Provider的類名為鍵值來保存的。一個(gè)Content Provider可以有多個(gè)authority,而只有一個(gè)類來和它對(duì)應(yīng),因此,這里要用兩個(gè)Map來保存,這里為了方便根據(jù)不同條件來快速查找而設(shè)計(jì)的。下面的代碼就是用來檢查要獲取的Content Provider是否已經(jīng)加存在的了:

    // First check if this content provider has been published...
    cpr = mProvidersByName.get(name);
    if (cpr != null) {
    	......
    } else {
    	try {
    		cpi = AppGlobals.getPackageManager().
    			resolveContentProvider(name,
    			STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
    	} catch (RemoteException ex) {
    	}
    	......
    }
    
    cpr = mProvidersByClass.get(cpi.name);
    final boolean firstClass = cpr == null;
    if (firstClass) {
    	try {
    		ApplicationInfo ai =
    			AppGlobals.getPackageManager().
    			getApplicationInfo(
    			cpi.applicationInfo.packageName,
    			STOCK_PM_FLAGS);
    		......
    		cpr = new ContentProviderRecord(cpi, ai);
    	} catch (RemoteException ex) {
    		// pm is in same process, this will never happen.
    	}
    }
            在我們這個(gè)情景中,由于是第一次調(diào)用ArticlesProvider接口,因此,在mProvidersByName和mProvidersByClass兩個(gè)Map中都不存在ArticlesProvider的相關(guān)信息,因此,這里會(huì)通過AppGlobals.getPackageManager函數(shù)來獲得PackageManagerService服務(wù)接口,然后分別通過它的resolveContentProvider和getApplicationInfo函數(shù)來分別獲取ArticlesProvider應(yīng)用程序的相關(guān)信息,分別保存在cpi和cpr這兩個(gè)本地變量中。這些信息都是在安裝應(yīng)用程序的過程中保存下來的,具體可以參考Android應(yīng)用程序安裝過程源代碼分析一文。

            接下去這個(gè)代碼判斷當(dāng)前要獲取的Content Provider是否允許在客戶進(jìn)程中加載,即查看一個(gè)這個(gè)Content Provider否配置了multiprocess屬性為true,如果允許在客戶進(jìn)程中加載,就直接返回了這個(gè)Content Provider的信息了:

    if (r != null && cpr.canRunHere(r)) {
    	// If this is a multiprocess provider, then just return its
    	// info and allow the caller to instantiate it.  Only do
    	// this if the provider is the same user as the caller's
    	// process, or can run as root (so can be in any process).
    	return cpr;
    }
            在我們這個(gè)情景中,要獲取的ArticlesProvider設(shè)置了要在獨(dú)立的進(jìn)程中運(yùn)行,因此,繼續(xù)往下執(zhí)行:

    // This is single process, and our app is now connecting to it.
    // See if we are already in the process of launching this
    // provider.
    final int N = mLaunchingProviders.size();
    int i;
    for (i=0; i<N; i++) {
    	if (mLaunchingProviders.get(i) == cpr) {
    		break;
    	}
    }
            系統(tǒng)中所有正在加載的Content Provider都保存在mLaunchingProviders成員變量中。在加載相應(yīng)的Content Provider之前,首先要判斷一下它是可否正在被其它應(yīng)用程序加載,如果是的話,就不用重復(fù)加載了。在我們這個(gè)情景中,沒有其它應(yīng)用程序也正在加載ArticlesProvider這個(gè)Content Provider,繼續(xù)往前執(zhí)行:

    // If the provider is not already being launched, then get it
    // started.
    if (i >= N) {
    	final long origId = Binder.clearCallingIdentity();
    	ProcessRecord proc = startProcessLocked(cpi.processName,
    		cpr.appInfo, false, 0, "content provider",
    		new ComponentName(cpi.applicationInfo.packageName,
    		cpi.name), false);
    	......
    	mLaunchingProviders.add(cpr);
    	......
    }
            這里的條件i >= N為true,就表明沒有其它應(yīng)用程序正在加載這個(gè)Content Provider,因此,就要調(diào)用startProcessLocked函數(shù)來啟動(dòng)一個(gè)新的進(jìn)程來加載這個(gè)Content Provider對(duì)應(yīng)的類了,然后把這個(gè)正在加載的信息增加到mLaunchingProviders中去。我們先接著分析這個(gè)函數(shù),然后再來看在新進(jìn)程中加載Content Provider的過程,繼續(xù)往下執(zhí)行:

    // Make sure the provider is published (the same provider class
    // may be published under multiple names).
    if (firstClass) {
    	mProvidersByClass.put(cpi.name, cpr);
    }
    cpr.launchingApp = proc;
    mProvidersByName.put(name, cpr);
            這段代碼把這個(gè)Content Provider的信息分別保存到mProvidersByName和mProviderByCalss兩個(gè)Map中去,以方便后續(xù)查詢。

            因?yàn)槲覀冃枰@取的Content Provider是在新的進(jìn)程中加載的,而getContentProviderImpl這個(gè)函數(shù)是在系統(tǒng)進(jìn)程中執(zhí)行的,它必須要等到要獲取的Content Provider是在新的進(jìn)程中加載完成后才能返回,這樣就涉及到進(jìn)程同步的問題了。這里使用的同步方法是不斷地去檢查變量cpr的provider域是否被設(shè)置了。當(dāng)要獲取的Content Provider在新的進(jìn)程加載完成之后,它會(huì)通過Binder進(jìn)程間通信機(jī)制調(diào)用到系統(tǒng)進(jìn)程中,把這個(gè)cpr變量的provider域設(shè)置為已經(jīng)加載好的Content Provider接口,這時(shí)候,函數(shù)getContentProviderImpl就可以返回了。下面的代碼就是用來等待要獲取的Content Provider是在新的進(jìn)程中加載完成的:

    // Wait for the provider to be published...
    synchronized (cpr) {
    	while (cpr.provider == null) {
    		......
    		try {
    			cpr.wait();
    		} catch (InterruptedException ex) {
    		}
    	}
    }
            下面我們?cè)俜治鲈谛逻M(jìn)程中加載ArticlesProvider這個(gè)Content Provider的過程。

             Step 8. ActivityManagerService.startProcessLocked

             Step 9. Process.start

             Step 10. ActivityThread.main

             Step 11. ActivityThread.attach

             Step 12. ActivityManagerService.attachApplication

             這五步是標(biāo)準(zhǔn)的Android應(yīng)用程序啟動(dòng)步驟,具體可以參考Android應(yīng)用程序啟動(dòng)過程源代碼分析一文中的Step 23到Step 27,或者Android系統(tǒng)在新進(jìn)程中啟動(dòng)自定義服務(wù)過程(startService)的原理分析一文中的Step 4到Step 9,這里就不再詳細(xì)描述了。

             Step 13. ActivityManagerService.attachApplicationLocked

             這個(gè)函數(shù)定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

    public final class ActivityManagerService extends ActivityManagerNative
    		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    	......
    
    	private final boolean attachApplicationLocked(IApplicationThread thread,
    			int pid) {
    		// Find the application record that is being attached...  either via
    		// the pid if we are running in multiple processes, or just pull the
    		// next app record if we are emulating process with anonymous threads.
    		ProcessRecord app;
    		if (pid != MY_PID && pid >= 0) {
    			synchronized (mPidsSelfLocked) {
    				app = mPidsSelfLocked.get(pid);
    			}
    		} else if (mStartingProcesses.size() > 0) {
    			......
    		} else {
    			......
    		}
    
    		......
    
    		app.thread = thread;
    		app.curAdj = app.setAdj = -100;
    		app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
    		app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
    		app.forcingToForeground = null;
    		app.foregroundServices = false;
    		app.debugging = false;
    
    		......
    
    		boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    		List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
    
    		try {
    			......
    
    			thread.bindApplication(processName, app.instrumentationInfo != null
    				? app.instrumentationInfo : app.info, providers,
    				app.instrumentationClass, app.instrumentationProfileFile,
    				app.instrumentationArguments, app.instrumentationWatcher, testMode,
    				isRestrictedBackupMode || !normalMode,
    				mConfiguration, getCommonServicesLocked());
    
    			......
    		} catch (Exception e) {
    			......
    		}
    
    		......
    		
    		return true;
    	}
    
    	......
    
    	private final List generateApplicationProvidersLocked(ProcessRecord app) {
    		List providers = null;
    		try {
    			providers = AppGlobals.getPackageManager().
    				queryContentProviders(app.processName, app.info.uid,
    				STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
    		} catch (RemoteException ex) {
    		}
    		if (providers != null) {
    			final int N = providers.size();
    			for (int i=0; i<N; i++) {
    				ProviderInfo cpi =
    					(ProviderInfo)providers.get(i);
    				ContentProviderRecord cpr = mProvidersByClass.get(cpi.name);
    				if (cpr == null) {
    					cpr = new ContentProviderRecord(cpi, app.info);
    					mProvidersByClass.put(cpi.name, cpr);
    				}
    				app.pubProviders.put(cpi.name, cpr);
    				app.addPackage(cpi.applicationInfo.packageName);
    				ensurePackageDexOpt(cpi.applicationInfo.packageName);
    			}
    		}
    		return providers;
    	}
    
    	......
    }
            這個(gè)函數(shù)首先是根據(jù)傳進(jìn)來的進(jìn)程ID找到相應(yīng)的進(jìn)程記錄塊,注意,這個(gè)進(jìn)程ID是應(yīng)用程序ArticlesProvider的ID,然后對(duì)這個(gè)進(jìn)程記錄塊做一些初傾始化的工作。再接下來通過調(diào)用generateApplicationProvidersLocked獲得需要在這個(gè)過程中加載的Content Provider列表,在我們這個(gè)情景中,就只有ArticlesProvider這個(gè)Content Provider了。最后調(diào)用從參數(shù)傳進(jìn)來的IApplicationThread對(duì)象thread的bindApplication函數(shù)來執(zhí)行一些應(yīng)用程序初始化工作。從Android應(yīng)用程序啟動(dòng)過程源代碼分析一文中我們知道,在Android系統(tǒng)中,每一個(gè)應(yīng)用程序進(jìn)程都加載了一個(gè)ActivityThread實(shí)例,在這個(gè)ActivityThread實(shí)例里面,有一個(gè)成員變量mAppThread,它是一個(gè)Binder對(duì)象,類型為ApplicationThread,實(shí)現(xiàn)了IApplicationThread接口,它是專門用來和ActivityManagerService服務(wù)進(jìn)行通信的。因此,調(diào)用下面語句:

    thread.bindApplication(processName, app.instrumentationInfo != null
    	? app.instrumentationInfo : app.info, providers,
    	app.instrumentationClass, app.instrumentationProfileFile,
    	app.instrumentationArguments, app.instrumentationWatcher, testMode,
    	isRestrictedBackupMode || !normalMode,
    	mConfiguration, getCommonServicesLocked());
            就會(huì)進(jìn)入到應(yīng)用程序ArticlesProvider進(jìn)程中的ApplicationThread對(duì)象的bindApplication函數(shù)中去。在我們這個(gè)情景場(chǎng),這個(gè)函數(shù)調(diào)用中最重要的參數(shù)便是第三個(gè)參數(shù)providers了,它是我們要處理的對(duì)象。

            Step 14. ApplicationThread.bindApplication

            這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:

    public final class ActivityThread {
    	......
    
    	private final class ApplicationThread extends ApplicationThreadNative {
    		......
    
    		public final void bindApplication(String processName,
    				ApplicationInfo appInfo, List<ProviderInfo> providers,
    				ComponentName instrumentationName, String profileFile,
    				Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
    				int debugMode, boolean isRestrictedBackupMode, Configuration config,
    				Map<String, IBinder> services) {
    			if (services != null) {
    				// Setup the service cache in the ServiceManager
    				ServiceManager.initServiceCache(services);
    			}
    
    			AppBindData data = new AppBindData();
    			data.processName = processName;
    			data.appInfo = appInfo;
    			data.providers = providers;
    			data.instrumentationName = instrumentationName;
    			data.profileFile = profileFile;
    			data.instrumentationArgs = instrumentationArgs;
    			data.instrumentationWatcher = instrumentationWatcher;
    			data.debugMode = debugMode;
    			data.restrictedBackupMode = isRestrictedBackupMode;
    			data.config = config;
    			queueOrSendMessage(H.BIND_APPLICATION, data);
    		}
    
    		......
    	}
    
    	......
    }
             這個(gè)函數(shù)把相關(guān)的信息都封裝成一個(gè)AppBindData對(duì)象,然后以一個(gè)消息的形式發(fā)送到主線程的消息隊(duì)列中去等等待處理。這個(gè)消息最終是是在ActivityThread類的handleBindApplication函數(shù)中進(jìn)行處理的。

             Step 15. ActivityThread.handleBindApplication

             這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:

    public final class ActivityThread {
    	......
    	
    	private final void handleBindApplication(AppBindData data) {
    		......
    
    		List<ProviderInfo> providers = data.providers;
    		if (providers != null) {
    			installContentProviders(app, providers);
    			......
    		}
    
    		......
    	}
    
    	......
    }
             這個(gè)函數(shù)的內(nèi)容比較多,我們忽略了其它無關(guān)的部分,只關(guān)注和Content Provider有關(guān)的邏輯,這里主要就是調(diào)用installContentProviders函數(shù)來在本地安裝Content Providers信息。

             Step 16. ActivityThread.installContentProviders

             這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:

    public final class ActivityThread {
    	......
    	
    	private final void installContentProviders(
    			Context context, List<ProviderInfo> providers) {
    		final ArrayList<IActivityManager.ContentProviderHolder> results =
    			new ArrayList<IActivityManager.ContentProviderHolder>();
    
    		Iterator<ProviderInfo> i = providers.iterator();
    		while (i.hasNext()) {
    			ProviderInfo cpi = i.next();
    			StringBuilder buf = new StringBuilder(128);
    			buf.append("Pub ");
    			buf.append(cpi.authority);
    			buf.append(": ");
    			buf.append(cpi.name);
    			Log.i(TAG, buf.toString());
    			IContentProvider cp = installProvider(context, null, cpi, false);
    			if (cp != null) {
    				IActivityManager.ContentProviderHolder cph =
    					new IActivityManager.ContentProviderHolder(cpi);
    				cph.provider = cp;
    				results.add(cph);
    				// Don't ever unload this provider from the process.
    				synchronized(mProviderMap) {
    					mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000));
    				}
    			}
    		}
    
    		try {
    			ActivityManagerNative.getDefault().publishContentProviders(
    				getApplicationThread(), results);
    		} catch (RemoteException ex) {
    		}
    	}
    
    	......
    }
             這個(gè)函數(shù)主要是做了兩件事情,一是調(diào)用installProvider來在本地安裝每一個(gè)Content Proivder的信息,并且為每一個(gè)Content Provider創(chuàng)建一個(gè)ContentProviderHolder對(duì)象來保存相關(guān)的信息。ContentProviderHolder對(duì)象是一個(gè)Binder對(duì)象,是用來把Content Provider的信息傳遞給ActivityManagerService服務(wù)的。當(dāng)這些Content Provider都處理好了以后,還要調(diào)用ActivityManagerService服務(wù)的publishContentProviders函數(shù)來通知ActivityManagerService服務(wù),這個(gè)進(jìn)程中所要加載的Content Provider,都已經(jīng)準(zhǔn)備完畢了,而ActivityManagerService服務(wù)的publishContentProviders函數(shù)的作用就是用來喚醒在前面Step 7等待的線程的了。我們先來看installProvider的實(shí)現(xiàn),然后再來看ActivityManagerService服務(wù)的publishContentProviders函數(shù)的實(shí)現(xiàn)。

            Step 17. ActivityThread.installProvider

            這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:

    public final class ActivityThread {
    	......
    	
    	private final IContentProvider installProvider(Context context,
    			IContentProvider provider, ProviderInfo info, boolean noisy) {
    		ContentProvider localProvider = null;
    		if (provider == null) {
    			......
    
    			Context c = null;
    			ApplicationInfo ai = info.applicationInfo;
    			if (context.getPackageName().equals(ai.packageName)) {
    				c = context;
    			} else if (mInitialApplication != null &&
    				mInitialApplication.getPackageName().equals(ai.packageName)) {
    					c = mInitialApplication;
    			} else {
    				try {
    					c = context.createPackageContext(ai.packageName,
    						Context.CONTEXT_INCLUDE_CODE);
    				} catch (PackageManager.NameNotFoundException e) {
    				}
    			}
    
    			......
    
    			try {
    				final java.lang.ClassLoader cl = c.getClassLoader();
    				localProvider = (ContentProvider)cl.
    					loadClass(info.name).newInstance();
    				provider = localProvider.getIContentProvider();
    				......
    
    				// XXX Need to create the correct context for this provider.
    				localProvider.attachInfo(c, info);
    			} catch (java.lang.Exception e) {
    				......
    			}
    
    		} else if (localLOGV) {
    			......
    		}
    
    		synchronized (mProviderMap) {
    			// Cache the pointer for the remote provider.
    			String names[] = PATTERN_SEMICOLON.split(info.authority);
    			for (int i=0; i<names.length; i++) {
    				ProviderClientRecord pr = new ProviderClientRecord(names[i], provider,
    					localProvider);
    				try {
    					provider.asBinder().linkToDeath(pr, 0);
    					mProviderMap.put(names[i], pr);
    				} catch (RemoteException e) {
    					return null;
    				}
    			}
    			if (localProvider != null) {
    				mLocalProviders.put(provider.asBinder(),
    					new ProviderClientRecord(null, provider, localProvider));
    			}
    		}
    
    		return provider;
    	}
    
    	......
    }
             這個(gè)函數(shù)的作用主要就是在應(yīng)用程序進(jìn)程中把相應(yīng)的Content Provider類加載進(jìn)來了,在我們這個(gè)種情景中,就是要在ArticlesProvider這個(gè)應(yīng)用程序中把ArticlesProvider這個(gè)Content Provider類加載到內(nèi)存中來了:

    final java.lang.ClassLoader cl = c.getClassLoader();
    localProvider = (ContentProvider)cl.
    	loadClass(info.name).newInstance();
    
             接著通過調(diào)用localProvider的getIContentProvider函數(shù)來獲得一個(gè)Binder對(duì)象,這個(gè)Binder對(duì)象返回給installContentProviders函數(shù)之后,就會(huì)傳到ActivityManagerService中去,后續(xù)其它應(yīng)用程序就是通過獲得這個(gè)Binder對(duì)象來和相應(yīng)的Content Provider進(jìn)行通信的了。我們先看一下這個(gè)函數(shù)的實(shí)現(xiàn),然后再回到installProvider函數(shù)中繼續(xù)分析。

             Step 18. ContentProvider.getIContentProvider

             這個(gè)函數(shù)定義在frameworks/base/core/java/android/content/ContentProvider.java文件中:

    public abstract class ContentProvider implements ComponentCallbacks {
    	......
    
    	private Transport mTransport = new Transport();
    
    	......
    
    	class Transport extends ContentProviderNative {
    		......
    	}
    
    	public IContentProvider getIContentProvider() {
    		return mTransport;
    	}
    
    	......
    }
            從這里我們可以看出,ContentProvider類和Transport類的關(guān)系就類似于ActivityThread和ApplicationThread的關(guān)系,其它應(yīng)用程序不是直接調(diào)用ContentProvider接口來訪問它的數(shù)據(jù),而是通過調(diào)用它的內(nèi)部對(duì)象mTransport來間接調(diào)用ContentProvider的接口,這一點(diǎn)我們?cè)谙乱黄恼轮蟹治稣{(diào)用Content Provider接口來獲取共享數(shù)據(jù)時(shí)將會(huì)看到。
            回到前面的installProvider函數(shù)中,它接下來調(diào)用下面接口來初始化剛剛加載好的Content Provider:

    // XXX Need to create the correct context for this provider.
    localProvider.attachInfo(c, info);
            同樣,我們先進(jìn)入到ContentProvider類的attachInfo函數(shù)去看看它的實(shí)現(xiàn),然后再回到installProvider函數(shù)來。

            Step 19. ContentProvider.attachInfo

            這個(gè)函數(shù)定義在frameworks/base/core/java/android/content/ContentProvider.java文件中:

    public abstract class ContentProvider implements ComponentCallbacks {
    	......
    
    	public void attachInfo(Context context, ProviderInfo info) {
    		/*
    		* Only allow it to be set once, so after the content service gives
    		* this to us clients can't change it.
    		*/
    		if (mContext == null) {
    			mContext = context;
    			mMyUid = Process.myUid();
    			if (info != null) {
    				setReadPermission(info.readPermission);
    				setWritePermission(info.writePermission);
    				setPathPermissions(info.pathPermissions);
    				mExported = info.exported;
    			}
    			ContentProvider.this.onCreate();
    		}
    	}
    
    	......
    }
            這個(gè)函數(shù)很簡(jiǎn)單,主要就是根據(jù)這個(gè)Content Provider的信息info來設(shè)置相應(yīng)的讀寫權(quán)限,然后調(diào)用它的子類的onCreate函數(shù)來讓子類執(zhí)行一些初始化的工作。在我們這個(gè)情景中,這個(gè)子類就是ArticlesProvide應(yīng)用程序中的ArticlesProvider類了。

            Step 20. ArticlesProvider.onCreate

            這個(gè)函數(shù)定義在前面一篇文章Android應(yīng)用程序組件Content Provider應(yīng)用實(shí)例介紹的應(yīng)用程序ArtilcesProvider源代碼工程目錄下,在文件為packages/experimental/ArticlesProvider/src/shy/luo/providers/articles/ArticlesProvider.java中:

    public class ArticlesProvider extends ContentProvider {
    	......
    
    	@Override
    	public boolean onCreate() {
    		Context context = getContext();
    		resolver = context.getContentResolver();
    		dbHelper = new DBHelper(context, DB_NAME, null, DB_VERSION);
    
    		return true;
    	}
    
    	......
    }
            這個(gè)函數(shù)主要執(zhí)行一些簡(jiǎn)單的工作,例如,獲得應(yīng)用程序上下文的ContentResolver接口和創(chuàng)建數(shù)據(jù)庫(kù)操作輔助對(duì)象,具體可以參考前面一篇文章Android應(yīng)用程序組件Content Provider應(yīng)用實(shí)例

            回到前面Step 17中的installProvider函數(shù)中,它接下來就是把這些在本地中加載的Content Provider信息保存下來了,以方便后面查詢和使用:

    synchronized (mProviderMap) {
        // Cache the pointer for the remote provider.
        String names[] = PATTERN_SEMICOLON.split(info.authority);
        for (int i=0; i<names.length; i++) {
    	ProviderClientRecord pr = new ProviderClientRecord(names[i], provider,
    		localProvider);
    	try {
    		provider.asBinder().linkToDeath(pr, 0);
    		mProviderMap.put(names[i], pr);
    	} catch (RemoteException e) {
    		return null;
    	}
        }
        if (localProvider != null) {
    	mLocalProviders.put(provider.asBinder(),
    		new ProviderClientRecord(null, provider, localProvider));
        }
    }
            和ActivityMangerService類似,在ActivityThread中,以Content Provider的authority為鍵值來把這個(gè)Content Provider的信息保存在mProviderMap成員變量中,因?yàn)橐粋€(gè)Content Provider可以對(duì)應(yīng)多個(gè)authority,因此這里用一個(gè)for循環(huán)來處理,同時(shí)又以這個(gè)Content Provider對(duì)應(yīng)的Binder對(duì)象provider來鍵值來把這個(gè)Content Provider的信息保存在mLocalProviders成員變量中,表明這是一個(gè)在本地加載的Content Provider。

            函數(shù)installProvider執(zhí)行完成以后,返回到Step 16中的instalContentProviders函數(shù)中,執(zhí)行下面語句:

    try {
    	ActivityManagerNative.getDefault().publishContentProviders(
    		getApplicationThread(), results);
    } catch (RemoteException ex) {
    }
            前面已經(jīng)提到,這個(gè)函數(shù)調(diào)用的作用就是通知ActivityMangerService,需要在這個(gè)進(jìn)程中加載的Content Provider已經(jīng)完加載完成了,參數(shù)results就包含了這些已經(jīng)加載好的Content Provider接口。

            Step 21. ActivityMangerService.publishContentProviders

            這個(gè)函數(shù)定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

    public final class ActivityManagerService extends ActivityManagerNative
    		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    	......
    
    	public final void publishContentProviders(IApplicationThread caller,
    			List<ContentProviderHolder> providers) {
    		......
    
    		synchronized(this) {
    			final ProcessRecord r = getRecordForAppLocked(caller);
    			......
    
    			final int N = providers.size();
    			for (int i=0; i<N; i++) {
    				ContentProviderHolder src = providers.get(i);
    				if (src == null || src.info == null || src.provider == null) {
    					continue;
    				}
    				ContentProviderRecord dst = r.pubProviders.get(src.info.name);
    				if (dst != null) {
    					mProvidersByClass.put(dst.info.name, dst);
    					String names[] = dst.info.authority.split(";");
    					for (int j = 0; j < names.length; j++) {
    						mProvidersByName.put(names[j], dst);
    					}
    
    					int NL = mLaunchingProviders.size();
    					int j;
    					for (j=0; j<NL; j++) {
    						if (mLaunchingProviders.get(j) == dst) {
    							mLaunchingProviders.remove(j);
    							j--;
    							NL--;
    						}
    					}
    					synchronized (dst) {
    						dst.provider = src.provider;
    						dst.app = r;
    						dst.notifyAll();
    					}
    					......
    				}
    			}
    		}
    	}
    
    	......
    }
             在我們這個(gè)情景中,只有一個(gè)Content Provider,因此,這里的N等待1。在中間的for循環(huán)里面,最重要的是下面這個(gè)語句:

    ContentProviderRecord dst = r.pubProviders.get(src.info.name);
             從這里得到的ContentProviderRecord對(duì)象dst,就是在前面Step 7中創(chuàng)建的ContentProviderRecord對(duì)象cpr了。在for循環(huán)中,首先是把這個(gè)Content Provider信息保存好在mProvidersByClass和mProvidersByName中:

    mProvidersByClass.put(dst.info.name, dst);
    String names[] = dst.info.authority.split(";");
    for (int j = 0; j < names.length; j++) {
    	mProvidersByName.put(names[j], dst);
    }
            前面已經(jīng)說過,這兩個(gè)Map中,一個(gè)是以類名為鍵值保存Content Provider信息,一個(gè)是以authority為鍵值保存Content Provider信息。

            因?yàn)檫@個(gè)Content Provider已經(jīng)加載好了,因此,把它從mLaunchingProviders列表中刪除:

    int NL = mLaunchingProviders.size();
    int j;
    for (j=0; j<NL; j++) {
    	if (mLaunchingProviders.get(j) == dst) {
    		mLaunchingProviders.remove(j);
    		j--;
    		NL--;
    	}
    }
            最后,設(shè)置這個(gè)ContentProviderRecord對(duì)象dst的provider域?yàn)閺膮?shù)傳進(jìn)來的Content Provider遠(yuǎn)程接口:
    synchronized (dst) {
    	dst.provider = src.provider;
    	dst.app = r;
    	dst.notifyAll();
    }
            執(zhí)行了dst.notiryAll語句后,在Step 7中等待要獲取的Content Provider接口加載完畢的線程就被喚醒了。喚醒之后,它檢查本地ContentProviderRecord變量cpr的provider域不為null,于是就返回了。它最終返回到Step 5中的ActivityThread類的getProvider函數(shù)中,繼續(xù)往下執(zhí)行:

    IContentProvider prov = installProvider(context, holder.provider,
    	holder.info, true);
            注意,這里是在Article應(yīng)用程序中進(jìn)程中執(zhí)行installProvider函數(shù)的,而前面的Step 17的installProvider函數(shù)是在ArticlesProvider應(yīng)用程序進(jìn)程中執(zhí)行的。

            Step 22. ActivityThread.installProvider

            這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:

    public final class ActivityThread {
    	......
    	
    	private final IContentProvider installProvider(Context context,
    			IContentProvider provider, ProviderInfo info, boolean noisy) {
    		......
    		if (provider == null) {
    			......
    		} else if (localLOGV) {
    			......
    		}
    
    		synchronized (mProviderMap) {
    			// Cache the pointer for the remote provider.
    			String names[] = PATTERN_SEMICOLON.split(info.authority);
    			for (int i=0; i<names.length; i++) {
    				ProviderClientRecord pr = new ProviderClientRecord(names[i], provider,
    					localProvider);
    				try {
    					provider.asBinder().linkToDeath(pr, 0);
    					mProviderMap.put(names[i], pr);
    				} catch (RemoteException e) {
    					return null;
    				}
    			}
    			......
    		}
    
    		return provider;
    	}
    
    	......
    }
            同樣是執(zhí)行installProvider函數(shù),與Step 17不同,這里傳進(jìn)來的參數(shù)provider是不為null的,因此,它不需要執(zhí)行在本地加載Content Provider的工作,只需要把從ActivityMangerService中獲得的Content Provider接口保存在成員變量mProviderMap中就可以了。

            這樣,獲取與"shy.luo.providers.artilces"這個(gè)uri對(duì)應(yīng)的Content Provider(shy.luo.providers.articles.ArticlesProvider)就完成了,它同時(shí)也是啟動(dòng)Content Provider的完整過程。第三方應(yīng)用程序獲得了這個(gè)Content Provider的接口之后,就可以訪問它里面的共享數(shù)據(jù)了。在下面一篇文章中,我們將重點(diǎn)分析Android應(yīng)用程序組件Content Provider在不同進(jìn)程中傳輸數(shù)據(jù)的過程,即Content Provider在不同應(yīng)用程序中共享數(shù)據(jù)的原理,敬請(qǐng)關(guān)注。

    作者:Luoshengyang 發(fā)表于2011-11-28 0:58:59 原文鏈接
    閱讀:3733 評(píng)論:25 查看評(píng)論
    posted on 2012-04-17 21:32 mixer-a 閱讀(1219) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲精品在线观看视频| 99精品视频在线免费观看 | 亚洲一卡2卡3卡4卡乱码 在线| 亚洲精品国产成人影院| 毛片基地免费观看| 在线免费观看你懂的| 国产黄片不卡免费| 精品国产亚洲第一区二区三区| 亚洲一级片在线观看| 亚洲天堂中文字幕| 亚洲国产一成人久久精品| 亚洲国产精品成人| 国产无遮挡色视频免费视频| 日本成年免费网站| 亚洲成人免费网址| 日韩精品极品视频在线观看免费| 国产精品高清免费网站| 苍井空亚洲精品AA片在线播放| 33333在线亚洲| 亚洲色欲色欲www| 亚洲国产成人手机在线电影bd| 亚洲天堂中文字幕| 亚洲综合无码一区二区| 老司机亚洲精品影院无码| 亚洲ⅴ国产v天堂a无码二区| 亚洲韩国精品无码一区二区三区| 亚洲中文字幕丝袜制服一区| 亚洲国产日韩成人综合天堂| 亚洲国产一级在线观看 | 亚洲AV无码国产剧情| 亚洲熟女精品中文字幕| 亚洲人配人种jizz| 亚洲午夜在线播放| 亚洲欧美第一成人网站7777 | 在线观看人成视频免费| 亚洲成在人线aⅴ免费毛片| 亚洲精品动漫免费二区| 蜜桃精品免费久久久久影院| 国产老女人精品免费视频| 国产aa免费视频| 久久久久亚洲AV成人网人人网站 |