編輯:關於Android編程
本文參考Android應用程序組件Content Provider的啟動過程源代碼分析http://blog.csdn.net/luoshengyang/article/details/6963418和《Android系統源代碼情景分析》,作者羅升陽。
0、總圖流程圖如下:
1、MainActivity進程向ActivityServiceManager主線程發送GET_CONTENT_PORVIDER_TRANSACTION<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+ICAgICAgIMjnz8LNvKO6PGJyPgo8L3A+CjxwPjxpbWcgc3JjPQ=="/uploadfile/Collfiles/20140713/2014071310171261.jpg" alt="\">
如圖:第一步
~/Android/frameworks/base/core/java/android/app
----ActivityManagerNative.java
class ActivityManagerProxy implements IActivityManager { ...... public ContentProviderHolder getContentProvider(IApplicationThread caller, String name) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); data.writeString(name); mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); ContentProviderHolder cph = null; if (res != 0) { cph = ContentProviderHolder.CREATOR.createFromParcel(reply); } data.recycle(); reply.recycle(); return cph; } ...... }
如圖:第二步,省略binder_transaction傳輸過程,因為上面已經分析過了。
如圖:第三步
~/Android/frameworks/base/core/java/android/app
----ActivityManagerNative.java
public abstract class ActivityManagerNative extends Binder implements IActivityManager { ...... public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case GET_CONTENT_PROVIDER_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); IApplicationThread app = ApplicationThreadNative.asInterface(b); String name = data.readString(); ContentProviderHolder cph = getContentProvider(app, name); reply.writeNoException(); if (cph != null) { reply.writeInt(1); cph.writeToParcel(reply, 0); } else { reply.writeInt(0); } return true; } ....... }其中name為shy.luo.providers.articles。
如圖:第四步
~/Android/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); } ...... }
它調用getContentProviderImpl函數來進一步執行操作。
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) { 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; } ...... }
(1)根據傳遞過來的name創建了ProviderInfo對象和ApplicationInfo對象,然後根據它們兩個對象創建了ContentProviderRecord對象。
(2)創建了ProcessRecord對象,並創建ArticlesProvider子線程。
(3)循環等待cpr.provider的值不為null。
2、創建ArticlesProvider子線程,略。
3、ArticlesProvider子線程向ActivityManagerService子線程發送ATTACH_APPLICATION_TRANSACTION
第一、二、三步全部省略,只看第四步。
~/Android/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主要做了以下幾件事: (1)獲取了剛在ActivityServiceManager主線程創建的ProcessRecord對象。
(2)根據這個ProcessRecord對象獲得剛在ActivityServiceManager主線程中的ProviderInfo對象。
(3)ActivityServiceManager子線程向ArticlesProvider子線程發送BIND_APPLICATION_TRANSACTION。
4、ActivityServiceManager子線程向ArticlesProvider子線程發送BIND_APPLICATION_TRANSACTION
如圖:第一步
~/Android/frameworks/base/core/java/android/app
----ApplicationThreadNative.java,ApplicationThreadProxy類
public final void bindApplication(String packageName, ApplicationInfo info, Listproviders, ComponentName testName, String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode, Configuration config, Map services) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeString(packageName); info.writeToParcel(data, 0); data.writeTypedList(providers); if (testName == null) { data.writeInt(0); } else { data.writeInt(1); testName.writeToParcel(data, 0); } data.writeString(profileName); data.writeBundle(testArgs); data.writeStrongInterface(testWatcher); data.writeInt(debugMode); data.writeInt(restrictedBackupMode ? 1 : 0); config.writeToParcel(data, 0); data.writeMap(services); mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } 其中providers是在ActivityServiceManager主線程根據傳遞過來的name創建了ProviderInfo對象。
如圖:第二步,省略binder_transaction傳輸過程,因為上面已經分析過了。
如圖:第三步
~/Android/frameworks/base/core/java/android/app
----ApplicationThreadNative.java
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread { ........ public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case BIND_APPLICATION_TRANSACTION: { data.enforceInterface(IApplicationThread.descriptor); String packageName = data.readString(); ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data); List其中providers是在ActivityServiceManager主線程根據傳遞過來的name創建了ProviderInfo對象。providers = data.createTypedArrayList(ProviderInfo.CREATOR); ComponentName testName = (data.readInt() != 0) ? new ComponentName(data) : null; String profileName = data.readString(); Bundle testArgs = data.readBundle(); IBinder binder = data.readStrongBinder(); IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder); int testMode = data.readInt(); boolean restrictedBackupMode = (data.readInt() != 0); Configuration config = Configuration.CREATOR.createFromParcel(data); HashMap services = data.readHashMap(null); bindApplication(packageName, info, providers, testName, profileName, testArgs, testWatcher, testMode, restrictedBackupMode, config, services); return true; } ..... }
如圖:第四步
~/Android/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, Listproviders, ComponentName instrumentationName, String profileFile, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, int debugMode, boolean isRestrictedBackupMode, Configuration config, Map 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); } ...... } ...... } 這個函數把相關的信息都封裝成一個AppBindData對象,然後以一個消息的形式發送到主線程的消息隊列中去等等待處理。這個消息最終在ArticlesProvider主線程中處理。
5、ArticlesProvider主線程installContentProvider
主要做了以下幾件事:(1)根據傳遞過來的providers把ArticlesProvider這個Content Provider類加載到內存中來了,並調用了它的onCreat方法。
(2)創建了Transport對象,它的關系圖如下:
(3)ArticlesProvider主線程ActivityServiceManager子線程發送PUBLISH_CONTENT_PROVIDER_TRANSACTION
6、ArticlesProvider主線程ActivityServiceManager子線程發送PUBLISH_CONTENT_PROVIDER_TRANSACTION
第一、二、三步全部省略,只看第四步。
~/Android/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, Listproviders) { ...... synchronized(this) { final ProcessRecord r = getRecordForAppLocked(caller); ...... final int N = providers.size(); for (int i=0; i 還記得ActivityServiceManager在循環等待麼?這裡dst.provider = src.provider,為ContentProviderProxy對象(實現了IContentProvider)。 之後調用notifyAll通知ActivityManagerService主線程,讓它從等待中返回。
7、notifyAll通知ActivityManagerService主線程
8、ActivityManagerService主線程向MainActivity進程發送返回結果
~/Android/frameworks/base/core/java/android/app
----ActivityThread.java
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; }
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; } ...... }
最後返回的是ContentProviderProxy對象,指向了ArticlesProvider主線程中Transport對象。如下圖:
Bundle bundle = provider.call(Articles.METHOD_GET_ITEM_COUNT, null, null);使用進程間通信的方式取得博客欄目數量。因為要傳輸的數據比較小。
使用情景:最近有個需求是統計後台應用運行時間,如果一個應用在後台運行超過一定時間就Kill掉進程,達到省電的目的。此時就可以使用PkgUsageStats這個類來實現啦!
一、 看效果二、上代碼package com.framework.widget;import android.app.Activity;import android.co
android 系統集成了一個輕量級的數據庫,SQLite只是一個嵌入式的數據庫引擎;android提供SQLiteDatabase代表一個數據庫,一旦應用程序獲得了SQ
項目中需要用到底欄導航欄,滑動或者點擊會切換上面的視圖,如圖: 這個效果使用Viewpager+Fragmen實現是主流方案,加入你之前對fragment