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