First, what ContentProvider
Second, how to use ContentProvider
Three, battlefield training-example practice
Iv. in-depth understanding of the ContentProvider principle
Why use ContentProvider can achieve cross-process communication, the first reaction must be that the goods and binder, because Android only slightly with the cross-process on the edge, must think of binder.
Here's an analysis of how contentprovider steps through binder for cross-process communication:
1, first you have to create a contentprovider run in process A, such as the previous blog
Provider defined in Androidmanifest.xml:
<provider
Android:name= ". Mycontentprovider "
android:authorities= "TELEFK"//This is very important, the host name in the URI, the query data depends on it
Android:enabled= "true"
Android:exported= "true" >
</provider>
2. Process B accesses process A's data through the following interface:
Getcontentresolver (). Query (uri,columns,null,null,null);
Getcontentresolver () The Contextimpl.java method that is actually called returns the Mcontentresolver object
This object is instantiated in the construction method of the Contextimpl
Mcontentresolver = new Applicationcontentresolver (this, mainthread, user);
Now look at the query method, which is defined in Contentresolver.java:
Public Final@Nullable Cursor Query (Final@NonNull URI Uri, @Nullable string[] projection, @Nullable String selection, @Nullable string[] Selectionargs,@Nullable String sortOrder, @Nullable cancellationsignal cancellationsignal) {Preconditions.checknotnull (URI, "uri"); Icontentprovider Unstableprovider = Acquireunstableprovider (URI); This function is critical to find the provider we just defined by the specified URI . if(Unstableprovider = =NULL) { return NULL; }Icontentprovider Stableprovider =NULL;......
Next look at the Acquireunstableprovider () function:
Hundred Turn back, finally went to the Applicationcontentresolver.java that just returned
@Overrideprotected Icontentprovider Acquireunstableprovider (Context C, String auth) { return Mmainthread.acquireprovider (c, Contentprovider.getauthoritywithoutuserid (auth), Resolveuseridfromauthority (auth), false);}
Here again the Activitythread.java's Acquireprovider () method is called, and we continue to follow:
Public final Icontentprovider Acquireprovider (Context C, String auth, int userId, Boolean stable) {
Final Icontentprovider Provider = Acquireexistingprovider (c, auth, userId, stable);//Initially it is very empty if ( Provider = NULL) {return provider; }//There is a possible race here. Another thread may try to acquire//the same provider at the same time. When this happens, we want to ensure//that the first one wins. Note that we cannot hold the lock while acquiring and installing the//provider since it might take a long time To run and it could also potentially//being re-entrant in the case where the-the provider process. Iactivitymanager.contentproviderholder holder = null; try {holder = Activitymanagernative.getdefault (). Getcontentprovider (Getapplicationthread () , Auth, userId, stable);//Critical, note here the method that the cross-process is tuned to Activitymanagerservice.java} catch (RemoteException ex) {} if (Holder = = null) {SLOG.E (TAG, "Failed to find ProvIder info for "+ auth); return null; }//Install provider would increment the reference count for us, and break//all ties in the race. Holder = Installprovider (c, Holder, Holder.info, True/*noisy*/, holder.noreleaseneeded, stable); return holder.provider; }
Let's continue to look at Activitymanagerservice.java's Getcontentprovider () method:
@Override Public Finalcontentproviderholder Getcontentprovider (iapplicationthread caller, String name,intUseridBooleanStable) {Enforcenotisolatedcaller ("Getcontentprovider"); if(Caller = =NULL) {String msg= "Null Iapplicationthread when getting content provider" +name; SLOG.W (TAG, msg); Throw NewSecurityException (msg); } //The incoming user check is now handled in checkcontentproviderpermissionlocked () to deal//With Cross-user Grant. returnGetcontentproviderimpl (caller, name,NULL, stable, userId); }
Kidney na ~ not yet! and continue to go down, we continue to insist:
This method is very long, we select the key analysis, the second parameter name is the UiR authority that we just got in the query.
Private Final contentproviderholder Getcontentproviderimpl (iapplicationthread caller, booleanint userId) { Contentproviderrecord cpr;//ams is used to record provider, there are three other components Acitityrecord, Servicerecord, Broadcastrecord null; null;//This should be the androidmanifest of the PMS analytic application.
......
First check if this content provider have been published ...
CPR = mprovidermap.getproviderbyname (name, userId);
......
If we find that the corresponding provider is already running, we will analyze it later and analyze the situation without running:
Boolean providerrunning = CPR! = NULL; if (providerrunning) {CPI = Cpr.info; String msg; Checktime (StartTime, "Getcontentproviderimpl:before checkcontentproviderpermission"); if (msg = checkcontentproviderpermissionlocked (CPI, R, UserId, Checkcrossuser))! = null) { throw new SecurityException (msg); } checktime (StartTime, "Getcontentproviderimpl:after checkcontentproviderpermission"); if (r = null && Cpr.canrunhere (R)) {//This provider have been published or is in the process of being published ... but it's also allowed to run//in the caller ' s process, So don ' t make a connection//And just let the caller instantiate its own instance. Contentproviderholder holder = Cpr.newholder (null); Don ' t givE caller the provider object, it needs//to make its own. Holder.provider = null; return holder; } final Long Origid = Binder.clearcallingidentity (); Checktime (StartTime, "getcontentproviderimpl:incprovidercountlocked"); In this case the provider instance already exists and so we can/return it right away. conn = incprovidercountlocked (r, CPR, token, stable); IF (conn! = null && (conn.stablecount+conn.unstablecount) = = 1) {if (Cpr.proc! = null &&am P R.setadj <= Processlist.perceptible_app_adj) {//If This is a perceptible APP accessing the Pro Vider,//Make sure to count it as being accessed and thus LRU list. This is good because//content providers be often expensive to STARt. Checktime (StartTime, "Getcontentproviderimpl:before updatelruprocess"); Updatelruprocesslocked (Cpr.proc, false, NULL); Checktime (StartTime, "Getcontentproviderimpl:after updatelruprocess"); }} if (Cpr.proc! = null) {if (false) {if (CPR.N Ame.flattentoshortstring (). Equals ("com.android.providers.calendar/. CalendarProvider2 ")) {SLOG.V (TAG," ****************** killing ") + cpr.name.flattenToShortString ()); Process.killprocess (CPR.PROC.PID); }} checktime (StartTime, "Getcontentproviderimpl:before Updateoomadj"); Boolean success = updateoomadjlocked (Cpr.proc); Maybeupdateproviderusagestatslocked (R, Cpr.info.packagename, name); Checktime (StartTime, "Getcontentproviderimpl:after Updateoomadj"); if (Debug_provider) slog.i (Tag_provider, "Adjust success:" + success); Note:there is still a race here where a signal could being//pending on the process even though we MA naged to update their//adj level. Not sure-what-do-it, but at least//the race are now smaller. if (!success) {//Uh oh ... it looks like the provider's process/has bee N killed on us. We need to wait for a new//process to is started, and make sure its death doesn ' t kill our process. SLOG.I (TAG, "Existing provider" + cpr.name.flattenToShortString () + "is crashing; Detaching "+ R); Boolean lastref = Decprovidercountlocked (conn, CPR, token, stable); Checktime (StartTime, "Getcontentproviderimpl:before appdied"); Appdiedlocked (CPR.PROC); Checktime (StartTime, "Getcontentproviderimpl:after appdied"); if (!lastref) {//This wasn ' t the last ref we process had on//th E provider ... we have now been killed, bail. return null; } providerrunning = false; conn = null; }} binder.restorecallingidentity (Origid); }
if (!providerrunning) {try {checktime (startTime, "Getcontentproviderimpl: Before Resolvecontentprovider "); CPI = Appglobals.getpackagemanager (). Resolvecontentprovider (name, Stock_pm_flags | Packagemanager.get_uri_permission_patterns, userId); Checktime (StartTime, "Getcontentproviderimpl:after resolvecontentprovider"); } catch (RemoteException ex) {} if (CPI = = null) {return null; }//If The provider is a singleton and//(it's a call within the same user | | the Provider is a//privileged app)//Then allow connecting to the singleton provider Singleton = Issingleton (Cpi.processname, Cpi.applicationinfo, Cpi.name, Cpi.flags) && IsvalidsingletoNcall (R.uid, Cpi.applicationInfo.uid); if (singleton) {userId = Userhandle.user_owner; } Cpi.applicationinfo = Getappinfoforuser (Cpi.applicationinfo, userId); Checktime (StartTime, "Getcontentproviderimpl:got app info for user"); String msg; Checktime (StartTime, "Getcontentproviderimpl:before checkcontentproviderpermission"); if (msg = checkcontentproviderpermissionlocked (CPI, R, UserId,!singleton))! = null) { throw new SecurityException (msg); } checktime (StartTime, "Getcontentproviderimpl:after checkcontentproviderpermission"); if (!mprocessesready &&!mdidupdate &&!mwaitingupdate &&!cpi.processname. Equals ("System")) {//If This content provider does not run in the System//Proces S, anD The system is not yet ready to run other//processes and then fail fast instead of hanging. throw new IllegalArgumentException ("Attempt to launch content provider before system Ready "); }//Make sure, the user who owns this provider is running. If not,//We don ' t want to allow it to run. if (!isuserrunninglocked (UserId, False)) {SLOG.W (TAG, "Unable to launch app") + Cpi.applicationInfo.packageName + "/" + Cpi.applicationInfo.uid + "for provider" + name + ": User" + UserId + "is stopped"); return null; } componentname comp = new ComponentName (Cpi.packagename, cpi.name); Checktime (StartTime, "Getcontentproviderimpl:before getproviderbyclass"); CPR = Mprovidermap.getproviderbyClass (comp, userId); Checktime (StartTime, "Getcontentproviderimpl:after getproviderbyclass"); Final Boolean firstclass = CPR = = NULL; if (FirstClass) {final Long ident = Binder.clearcallingidentity (); try {checktime (startTime, "Getcontentproviderimpl:before getapplicationinfo"); ApplicationInfo ai = Appglobals.getpackagemanager (). Getapplicationinfo (Cpi.applicationInfo.packageName, Stock_pm_flags, userId); Checktime (StartTime, "Getcontentproviderimpl:after getapplicationinfo"); if (AI = = null) {SLOG.W (TAG, "No package info for content provider" + Cpi.name); return null; } ai = Getappinfoforuser (ai, userId); CPR = new Contentproviderrecord (this, CPI, AI, comp, singleton);//Critical, first create CPR and then start the target process
ContentProvider Study Notes