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.content.ComponentName;
23 import android.content.IContentProvider;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.ProviderInfo;
26 import android.os.IBinder;
27 import android.os.IBinder.DeathRecipient;
28 import android.os.Process;
29 import android.os.RemoteException;
30 import android.os.UserHandle;
31 import android.util.ArrayMap;
32 import android.util.Slog;
33 
34 import com.android.internal.app.procstats.AssociationState;
35 import com.android.internal.app.procstats.ProcessStats;
36 
37 import java.io.PrintWriter;
38 import java.util.ArrayList;
39 
40 final class ContentProviderRecord implements ComponentName.WithComponentName {
41     // Maximum attempts to bring up the content provider before giving up.
42     static final int MAX_RETRY_COUNT = 3;
43 
44     final ActivityManagerService service;
45     public final ProviderInfo info;
46     final int uid;
47     final ApplicationInfo appInfo;
48     final ComponentName name;
49     final boolean singleton;
50     public IContentProvider provider;
51     public boolean noReleaseNeeded;
52     // All attached clients
53     final ArrayList<ContentProviderConnection> connections
54             = new ArrayList<ContentProviderConnection>();
55     //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
56     // Handles for non-framework processes supported by this provider
57     ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
58     // Count for external process for which we have no handles.
59     int externalProcessNoHandleCount;
60     int mRestartCount; // number of times we tried before bringing up it successfully.
61     ProcessRecord proc; // if non-null, hosting process.
62     ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
63     String stringName;
64     String shortStringName;
65 
ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info, ApplicationInfo ai, ComponentName _name, boolean _singleton)66     public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info,
67             ApplicationInfo ai, ComponentName _name, boolean _singleton) {
68         service = _service;
69         info = _info;
70         uid = ai.uid;
71         appInfo = ai;
72         name = _name;
73         singleton = _singleton;
74         noReleaseNeeded = (uid == 0 || uid == Process.SYSTEM_UID)
75                 && (_name == null || !"com.android.settings".equals(_name.getPackageName()));
76     }
77 
ContentProviderRecord(ContentProviderRecord cpr)78     public ContentProviderRecord(ContentProviderRecord cpr) {
79         service = cpr.service;
80         info = cpr.info;
81         uid = cpr.uid;
82         appInfo = cpr.appInfo;
83         name = cpr.name;
84         singleton = cpr.singleton;
85         noReleaseNeeded = cpr.noReleaseNeeded;
86     }
87 
newHolder(ContentProviderConnection conn)88     public ContentProviderHolder newHolder(ContentProviderConnection conn) {
89         ContentProviderHolder holder = new ContentProviderHolder(info);
90         holder.provider = provider;
91         holder.noReleaseNeeded = noReleaseNeeded;
92         holder.connection = conn;
93         return holder;
94     }
95 
setProcess(ProcessRecord proc)96     public void setProcess(ProcessRecord proc) {
97         this.proc = proc;
98         if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) {
99             for (int iconn = connections.size() - 1; iconn >= 0; iconn--) {
100                 final ContentProviderConnection conn = connections.get(iconn);
101                 if (proc != null) {
102                     conn.startAssociationIfNeeded();
103                 } else {
104                     conn.stopAssociation();
105                 }
106             }
107             if (externalProcessTokenToHandle != null) {
108                 for (int iext = externalProcessTokenToHandle.size() - 1; iext >= 0; iext--) {
109                     final ExternalProcessHandle handle = externalProcessTokenToHandle.valueAt(iext);
110                     if (proc != null) {
111                         handle.startAssociationIfNeeded(this);
112                     } else {
113                         handle.stopAssociation();
114                     }
115                 }
116             }
117         }
118     }
119 
canRunHere(ProcessRecord app)120     public boolean canRunHere(ProcessRecord app) {
121         return (info.multiprocess || info.processName.equals(app.processName))
122                 && uid == app.info.uid;
123     }
124 
addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag)125     public void addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag) {
126         if (token == null) {
127             externalProcessNoHandleCount++;
128         } else {
129             if (externalProcessTokenToHandle == null) {
130                 externalProcessTokenToHandle = new ArrayMap<>();
131             }
132             ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
133             if (handle == null) {
134                 handle = new ExternalProcessHandle(token, callingUid, callingTag);
135                 externalProcessTokenToHandle.put(token, handle);
136                 handle.startAssociationIfNeeded(this);
137             }
138             handle.mAcquisitionCount++;
139         }
140     }
141 
removeExternalProcessHandleLocked(IBinder token)142     public boolean removeExternalProcessHandleLocked(IBinder token) {
143         if (hasExternalProcessHandles()) {
144             boolean hasHandle = false;
145             if (externalProcessTokenToHandle != null) {
146                 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
147                 if (handle != null) {
148                     hasHandle = true;
149                     handle.mAcquisitionCount--;
150                     if (handle.mAcquisitionCount == 0) {
151                         removeExternalProcessHandleInternalLocked(token);
152                         return true;
153                     }
154                 }
155             }
156             if (!hasHandle) {
157                 externalProcessNoHandleCount--;
158                 return true;
159             }
160         }
161         return false;
162     }
163 
removeExternalProcessHandleInternalLocked(IBinder token)164     private void removeExternalProcessHandleInternalLocked(IBinder token) {
165         ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
166         handle.unlinkFromOwnDeathLocked();
167         handle.stopAssociation();
168         externalProcessTokenToHandle.remove(token);
169         if (externalProcessTokenToHandle.size() == 0) {
170             externalProcessTokenToHandle = null;
171         }
172     }
173 
hasExternalProcessHandles()174     public boolean hasExternalProcessHandles() {
175         return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0);
176     }
177 
hasConnectionOrHandle()178     public boolean hasConnectionOrHandle() {
179         return !connections.isEmpty() || hasExternalProcessHandles();
180     }
181 
dump(PrintWriter pw, String prefix, boolean full)182     void dump(PrintWriter pw, String prefix, boolean full) {
183         if (full) {
184             pw.print(prefix); pw.print("package=");
185                     pw.print(info.applicationInfo.packageName);
186                     pw.print(" process="); pw.println(info.processName);
187         }
188         pw.print(prefix); pw.print("proc="); pw.println(proc);
189         if (launchingApp != null) {
190             pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp);
191         }
192         if (full) {
193             pw.print(prefix); pw.print("uid="); pw.print(uid);
194                     pw.print(" provider="); pw.println(provider);
195         }
196         if (singleton) {
197             pw.print(prefix); pw.print("singleton="); pw.println(singleton);
198         }
199         pw.print(prefix); pw.print("authority="); pw.println(info.authority);
200         if (full) {
201             if (info.isSyncable || info.multiprocess || info.initOrder != 0) {
202                 pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable);
203                         pw.print(" multiprocess="); pw.print(info.multiprocess);
204                         pw.print(" initOrder="); pw.println(info.initOrder);
205             }
206         }
207         if (full) {
208             if (hasExternalProcessHandles()) {
209                 pw.print(prefix); pw.print("externals:");
210                 if (externalProcessTokenToHandle != null) {
211                     pw.print(" w/token=");
212                     pw.print(externalProcessTokenToHandle.size());
213                 }
214                 if (externalProcessNoHandleCount > 0) {
215                     pw.print(" notoken=");
216                     pw.print(externalProcessNoHandleCount);
217                 }
218                 pw.println();
219             }
220         } else {
221             if (connections.size() > 0 || externalProcessNoHandleCount > 0) {
222                 pw.print(prefix); pw.print(connections.size());
223                         pw.print(" connections, "); pw.print(externalProcessNoHandleCount);
224                         pw.println(" external handles");
225             }
226         }
227         if (connections.size() > 0) {
228             if (full) {
229                 pw.print(prefix); pw.println("Connections:");
230             }
231             for (int i=0; i<connections.size(); i++) {
232                 ContentProviderConnection conn = connections.get(i);
233                 pw.print(prefix); pw.print("  -> "); pw.println(conn.toClientString());
234                 if (conn.provider != this) {
235                     pw.print(prefix); pw.print("    *** WRONG PROVIDER: ");
236                             pw.println(conn.provider);
237                 }
238             }
239         }
240     }
241 
242     @Override
toString()243     public String toString() {
244         if (stringName != null) {
245             return stringName;
246         }
247         StringBuilder sb = new StringBuilder(128);
248         sb.append("ContentProviderRecord{");
249         sb.append(Integer.toHexString(System.identityHashCode(this)));
250         sb.append(" u");
251         sb.append(UserHandle.getUserId(uid));
252         sb.append(' ');
253         sb.append(name.flattenToShortString());
254         sb.append('}');
255         return stringName = sb.toString();
256     }
257 
toShortString()258     public String toShortString() {
259         if (shortStringName != null) {
260             return shortStringName;
261         }
262         StringBuilder sb = new StringBuilder(128);
263         sb.append(Integer.toHexString(System.identityHashCode(this)));
264         sb.append('/');
265         sb.append(name.flattenToShortString());
266         return shortStringName = sb.toString();
267     }
268 
269     // This class represents a handle from an external process to a provider.
270     private class ExternalProcessHandle implements DeathRecipient {
271         private static final String LOG_TAG = "ExternalProcessHanldle";
272 
273         final IBinder mToken;
274         final int mOwningUid;
275         final String mOwningProcessName;
276         int mAcquisitionCount;
277         AssociationState.SourceState mAssociation;
278 
ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName)279         public ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName) {
280             mToken = token;
281             mOwningUid = owningUid;
282             mOwningProcessName = owningProcessName;
283             try {
284                 token.linkToDeath(this, 0);
285             } catch (RemoteException re) {
286                 Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re);
287             }
288         }
289 
unlinkFromOwnDeathLocked()290         public void unlinkFromOwnDeathLocked() {
291             mToken.unlinkToDeath(this, 0);
292         }
293 
startAssociationIfNeeded(ContentProviderRecord provider)294         public void startAssociationIfNeeded(ContentProviderRecord provider) {
295             // If we don't already have an active association, create one...  but only if this
296             // is an association between two different processes.
297             if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS
298                     && mAssociation == null && provider.proc != null
299                     && (provider.appInfo.uid != mOwningUid
300                             || !provider.info.processName.equals(mOwningProcessName))) {
301                 ProcessStats.ProcessStateHolder holder = provider.proc.pkgList.get(
302                         provider.name.getPackageName());
303                 if (holder == null) {
304                     Slog.wtf(TAG_AM, "No package in referenced provider "
305                             + provider.name.toShortString() + ": proc=" + provider.proc);
306                 } else if (holder.pkg == null) {
307                     Slog.wtf(TAG_AM, "Inactive holder in referenced provider "
308                             + provider.name.toShortString() + ": proc=" + provider.proc);
309                 } else {
310                     mAssociation = holder.pkg.getAssociationStateLocked(holder.state,
311                             provider.name.getClassName()).startSource(mOwningUid,
312                             mOwningProcessName, null);
313 
314                 }
315             }
316         }
317 
stopAssociation()318         public void stopAssociation() {
319             if (mAssociation != null) {
320                 mAssociation.stop();
321                 mAssociation = null;
322             }
323         }
324 
325         @Override
binderDied()326         public void binderDied() {
327             synchronized (service) {
328                 if (hasExternalProcessHandles() &&
329                         externalProcessTokenToHandle.get(mToken) != null) {
330                     removeExternalProcessHandleInternalLocked(mToken);
331                 }
332             }
333         }
334     }
335 
getComponentName()336     public ComponentName getComponentName() {
337         return name;
338     }
339 }
340