• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.am;
18 
19 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
20 
21 import android.app.ContentProviderHolder;
22 import android.app.IApplicationThread;
23 import android.content.ComponentName;
24 import android.content.IContentProvider;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.ProviderInfo;
27 import android.os.IBinder;
28 import android.os.IBinder.DeathRecipient;
29 import android.os.Process;
30 import android.os.RemoteException;
31 import android.os.UserHandle;
32 import android.util.ArrayMap;
33 import android.util.Slog;
34 
35 import com.android.internal.app.procstats.AssociationState;
36 import com.android.internal.app.procstats.ProcessStats;
37 
38 import java.io.PrintWriter;
39 import java.util.ArrayList;
40 
41 final class ContentProviderRecord implements ComponentName.WithComponentName {
42     // Maximum attempts to bring up the content provider before giving up.
43     static final int MAX_RETRY_COUNT = 3;
44 
45     final ActivityManagerService service;
46     public final ProviderInfo info;
47     final int uid;
48     final ApplicationInfo appInfo;
49     final ComponentName name;
50     final boolean singleton;
51     public IContentProvider provider;
52     public boolean noReleaseNeeded;
53     // All attached clients
54     final ArrayList<ContentProviderConnection> connections
55             = new ArrayList<ContentProviderConnection>();
56     //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
57     // Handles for non-framework processes supported by this provider
58     ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
59     // Count for external process for which we have no handles.
60     int externalProcessNoHandleCount;
61     int mRestartCount; // number of times we tried before bringing up it successfully.
62     ProcessRecord proc; // if non-null, hosting process.
63     ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
64     String stringName;
65     String shortStringName;
66 
ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info, ApplicationInfo ai, ComponentName _name, boolean _singleton)67     public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info,
68             ApplicationInfo ai, ComponentName _name, boolean _singleton) {
69         service = _service;
70         info = _info;
71         uid = ai.uid;
72         appInfo = ai;
73         name = _name;
74         singleton = _singleton;
75         noReleaseNeeded = (uid == 0 || uid == Process.SYSTEM_UID)
76                 && (_name == null || !"com.android.settings".equals(_name.getPackageName()));
77     }
78 
ContentProviderRecord(ContentProviderRecord cpr)79     public ContentProviderRecord(ContentProviderRecord cpr) {
80         service = cpr.service;
81         info = cpr.info;
82         uid = cpr.uid;
83         appInfo = cpr.appInfo;
84         name = cpr.name;
85         singleton = cpr.singleton;
86         noReleaseNeeded = cpr.noReleaseNeeded;
87     }
88 
newHolder(ContentProviderConnection conn, boolean local)89     public ContentProviderHolder newHolder(ContentProviderConnection conn, boolean local) {
90         ContentProviderHolder holder = new ContentProviderHolder(info);
91         holder.provider = provider;
92         holder.noReleaseNeeded = noReleaseNeeded;
93         holder.connection = conn;
94         holder.mLocal = local;
95         return holder;
96     }
97 
setProcess(ProcessRecord proc)98     public void setProcess(ProcessRecord proc) {
99         this.proc = proc;
100         if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) {
101             for (int iconn = connections.size() - 1; iconn >= 0; iconn--) {
102                 final ContentProviderConnection conn = connections.get(iconn);
103                 if (proc != null) {
104                     conn.startAssociationIfNeeded();
105                 } else {
106                     conn.stopAssociation();
107                 }
108             }
109             if (externalProcessTokenToHandle != null) {
110                 for (int iext = externalProcessTokenToHandle.size() - 1; iext >= 0; iext--) {
111                     final ExternalProcessHandle handle = externalProcessTokenToHandle.valueAt(iext);
112                     if (proc != null) {
113                         handle.startAssociationIfNeeded(this);
114                     } else {
115                         handle.stopAssociation();
116                     }
117                 }
118             }
119         }
120     }
121 
canRunHere(ProcessRecord app)122     public boolean canRunHere(ProcessRecord app) {
123         return (info.multiprocess || info.processName.equals(app.processName))
124                 && uid == app.info.uid;
125     }
126 
addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag)127     public void addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag) {
128         if (token == null) {
129             externalProcessNoHandleCount++;
130         } else {
131             if (externalProcessTokenToHandle == null) {
132                 externalProcessTokenToHandle = new ArrayMap<>();
133             }
134             ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
135             if (handle == null) {
136                 handle = new ExternalProcessHandle(token, callingUid, callingTag);
137                 externalProcessTokenToHandle.put(token, handle);
138                 handle.startAssociationIfNeeded(this);
139             }
140             handle.mAcquisitionCount++;
141         }
142     }
143 
removeExternalProcessHandleLocked(IBinder token)144     public boolean removeExternalProcessHandleLocked(IBinder token) {
145         if (hasExternalProcessHandles()) {
146             boolean hasHandle = false;
147             if (externalProcessTokenToHandle != null) {
148                 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
149                 if (handle != null) {
150                     hasHandle = true;
151                     handle.mAcquisitionCount--;
152                     if (handle.mAcquisitionCount == 0) {
153                         removeExternalProcessHandleInternalLocked(token);
154                         return true;
155                     }
156                 }
157             }
158             if (!hasHandle) {
159                 externalProcessNoHandleCount--;
160                 return true;
161             }
162         }
163         return false;
164     }
165 
removeExternalProcessHandleInternalLocked(IBinder token)166     private void removeExternalProcessHandleInternalLocked(IBinder token) {
167         ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
168         handle.unlinkFromOwnDeathLocked();
169         handle.stopAssociation();
170         externalProcessTokenToHandle.remove(token);
171         if (externalProcessTokenToHandle.size() == 0) {
172             externalProcessTokenToHandle = null;
173         }
174     }
175 
hasExternalProcessHandles()176     public boolean hasExternalProcessHandles() {
177         return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0);
178     }
179 
hasConnectionOrHandle()180     public boolean hasConnectionOrHandle() {
181         return !connections.isEmpty() || hasExternalProcessHandles();
182     }
183 
184     /**
185      * Notify all clients that the provider has been published and ready to use,
186      * or timed out.
187      *
188      * @param status true: successfully published; false: timed out
189      */
onProviderPublishStatusLocked(boolean status)190     void onProviderPublishStatusLocked(boolean status) {
191         final int numOfConns = connections.size();
192         for (int i = 0; i < numOfConns; i++) {
193             final ContentProviderConnection conn = connections.get(i);
194             if (conn.waiting && conn.client != null) {
195                 final ProcessRecord client = conn.client;
196                 if (!status) {
197                     if (launchingApp == null) {
198                         Slog.w(TAG_AM, "Unable to launch app "
199                                 + appInfo.packageName + "/"
200                                 + appInfo.uid + " for provider "
201                                 + info.authority + ": launching app became null");
202                         EventLogTags.writeAmProviderLostProcess(
203                                 UserHandle.getUserId(appInfo.uid),
204                                 appInfo.packageName,
205                                 appInfo.uid, info.authority);
206                     } else {
207                         Slog.wtf(TAG_AM, "Timeout waiting for provider "
208                                 + appInfo.packageName + "/"
209                                 + appInfo.uid + " for provider "
210                                 + info.authority
211                                 + " caller=" + client);
212                     }
213                 }
214                 final IApplicationThread thread = client.getThread();
215                 if (thread != null) {
216                     try {
217                         thread.notifyContentProviderPublishStatus(
218                                 newHolder(status ? conn : null, false),
219                                 info.authority, conn.mExpectedUserId, status);
220                     } catch (RemoteException e) {
221                     }
222                 }
223             }
224             conn.waiting = false;
225         }
226     }
227 
dump(PrintWriter pw, String prefix, boolean full)228     void dump(PrintWriter pw, String prefix, boolean full) {
229         if (full) {
230             pw.print(prefix); pw.print("package=");
231                     pw.print(info.applicationInfo.packageName);
232                     pw.print(" process="); pw.println(info.processName);
233         }
234         pw.print(prefix); pw.print("proc="); pw.println(proc);
235         if (launchingApp != null) {
236             pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp);
237         }
238         if (full) {
239             pw.print(prefix); pw.print("uid="); pw.print(uid);
240                     pw.print(" provider="); pw.println(provider);
241         }
242         if (singleton) {
243             pw.print(prefix); pw.print("singleton="); pw.println(singleton);
244         }
245         pw.print(prefix); pw.print("authority="); pw.println(info.authority);
246         if (full) {
247             if (info.isSyncable || info.multiprocess || info.initOrder != 0) {
248                 pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable);
249                         pw.print(" multiprocess="); pw.print(info.multiprocess);
250                         pw.print(" initOrder="); pw.println(info.initOrder);
251             }
252         }
253         if (full) {
254             if (hasExternalProcessHandles()) {
255                 pw.print(prefix); pw.print("externals:");
256                 if (externalProcessTokenToHandle != null) {
257                     pw.print(" w/token=");
258                     pw.print(externalProcessTokenToHandle.size());
259                 }
260                 if (externalProcessNoHandleCount > 0) {
261                     pw.print(" notoken=");
262                     pw.print(externalProcessNoHandleCount);
263                 }
264                 pw.println();
265             }
266         } else {
267             if (connections.size() > 0 || externalProcessNoHandleCount > 0) {
268                 pw.print(prefix); pw.print(connections.size());
269                         pw.print(" connections, "); pw.print(externalProcessNoHandleCount);
270                         pw.println(" external handles");
271             }
272         }
273         if (connections.size() > 0) {
274             if (full) {
275                 pw.print(prefix); pw.println("Connections:");
276             }
277             for (int i=0; i<connections.size(); i++) {
278                 ContentProviderConnection conn = connections.get(i);
279                 pw.print(prefix); pw.print("  -> "); pw.println(conn.toClientString());
280                 if (conn.provider != this) {
281                     pw.print(prefix); pw.print("    *** WRONG PROVIDER: ");
282                             pw.println(conn.provider);
283                 }
284             }
285         }
286     }
287 
288     @Override
toString()289     public String toString() {
290         if (stringName != null) {
291             return stringName;
292         }
293         StringBuilder sb = new StringBuilder(128);
294         sb.append("ContentProviderRecord{");
295         sb.append(Integer.toHexString(System.identityHashCode(this)));
296         sb.append(" u");
297         sb.append(UserHandle.getUserId(uid));
298         sb.append(' ');
299         sb.append(name.flattenToShortString());
300         sb.append('}');
301         return stringName = sb.toString();
302     }
303 
toShortString()304     public String toShortString() {
305         if (shortStringName != null) {
306             return shortStringName;
307         }
308         StringBuilder sb = new StringBuilder(128);
309         sb.append(Integer.toHexString(System.identityHashCode(this)));
310         sb.append('/');
311         sb.append(name.flattenToShortString());
312         return shortStringName = sb.toString();
313     }
314 
315     // This class represents a handle from an external process to a provider.
316     private class ExternalProcessHandle implements DeathRecipient {
317         private static final String LOG_TAG = "ExternalProcessHanldle";
318 
319         final IBinder mToken;
320         final int mOwningUid;
321         final String mOwningProcessName;
322         int mAcquisitionCount;
323         AssociationState.SourceState mAssociation;
324         private Object mProcStatsLock;  // Internal lock for accessing AssociationState
325 
ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName)326         public ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName) {
327             mToken = token;
328             mOwningUid = owningUid;
329             mOwningProcessName = owningProcessName;
330             try {
331                 token.linkToDeath(this, 0);
332             } catch (RemoteException re) {
333                 Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re);
334             }
335         }
336 
unlinkFromOwnDeathLocked()337         public void unlinkFromOwnDeathLocked() {
338             mToken.unlinkToDeath(this, 0);
339         }
340 
startAssociationIfNeeded(ContentProviderRecord provider)341         public void startAssociationIfNeeded(ContentProviderRecord provider) {
342             // If we don't already have an active association, create one...  but only if this
343             // is an association between two different processes.
344             if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS
345                     && mAssociation == null && provider.proc != null
346                     && (provider.appInfo.uid != mOwningUid
347                             || !provider.info.processName.equals(mOwningProcessName))) {
348                 ProcessStats.ProcessStateHolder holder =
349                         provider.proc.getPkgList().get(provider.name.getPackageName());
350                 if (holder == null) {
351                     Slog.wtf(TAG_AM, "No package in referenced provider "
352                             + provider.name.toShortString() + ": proc=" + provider.proc);
353                 } else if (holder.pkg == null) {
354                     Slog.wtf(TAG_AM, "Inactive holder in referenced provider "
355                             + provider.name.toShortString() + ": proc=" + provider.proc);
356                 } else {
357                     mProcStatsLock = provider.proc.mService.mProcessStats.mLock;
358                     synchronized (mProcStatsLock) {
359                         mAssociation = holder.pkg.getAssociationStateLocked(holder.state,
360                                 provider.name.getClassName()).startSource(mOwningUid,
361                                 mOwningProcessName, null);
362                     }
363                 }
364             }
365         }
366 
stopAssociation()367         public void stopAssociation() {
368             if (mAssociation != null) {
369                 synchronized (mProcStatsLock) {
370                     mAssociation.stop();
371                 }
372                 mAssociation = null;
373             }
374         }
375 
376         @Override
binderDied()377         public void binderDied() {
378             synchronized (service) {
379                 if (hasExternalProcessHandles() &&
380                         externalProcessTokenToHandle.get(mToken) != null) {
381                     removeExternalProcessHandleInternalLocked(mToken);
382                 }
383             }
384         }
385     }
386 
getComponentName()387     public ComponentName getComponentName() {
388         return name;
389     }
390 }
391