ContentProviderRecord.java revision 3133c401cd34e3c75b25320b50566c93494310a7
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
17package com.android.server.am;
18
19import android.app.IActivityManager.ContentProviderHolder;
20import android.content.ComponentName;
21import android.content.IContentProvider;
22import android.content.pm.ApplicationInfo;
23import android.content.pm.ProviderInfo;
24import android.os.IBinder;
25import android.os.IBinder.DeathRecipient;
26import android.os.Process;
27import android.os.RemoteException;
28import android.os.UserHandle;
29import android.util.Slog;
30
31import java.io.PrintWriter;
32import java.util.ArrayList;
33import java.util.HashMap;
34
35final class ContentProviderRecord {
36    final ActivityManagerService service;
37    public final ProviderInfo info;
38    final int uid;
39    final ApplicationInfo appInfo;
40    final ComponentName name;
41    final boolean singleton;
42    public IContentProvider provider;
43    public boolean noReleaseNeeded;
44    // All attached clients
45    final ArrayList<ContentProviderConnection> connections
46            = new ArrayList<ContentProviderConnection>();
47    //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
48    // Handles for non-framework processes supported by this provider
49    HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
50    // Count for external process for which we have no handles.
51    int externalProcessNoHandleCount;
52    ProcessRecord proc; // if non-null, hosting process.
53    ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
54    String stringName;
55    String shortStringName;
56
57    public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info,
58            ApplicationInfo ai, ComponentName _name, boolean _singleton) {
59        service = _service;
60        info = _info;
61        uid = ai.uid;
62        appInfo = ai;
63        name = _name;
64        singleton = _singleton;
65        noReleaseNeeded = uid == 0 || uid == Process.SYSTEM_UID;
66    }
67
68    public ContentProviderRecord(ContentProviderRecord cpr) {
69        service = cpr.service;
70        info = cpr.info;
71        uid = cpr.uid;
72        appInfo = cpr.appInfo;
73        name = cpr.name;
74        singleton = cpr.singleton;
75        noReleaseNeeded = cpr.noReleaseNeeded;
76    }
77
78    public ContentProviderHolder newHolder(ContentProviderConnection conn) {
79        ContentProviderHolder holder = new ContentProviderHolder(info);
80        holder.provider = provider;
81        holder.noReleaseNeeded = noReleaseNeeded;
82        holder.connection = conn;
83        return holder;
84    }
85
86    public boolean canRunHere(ProcessRecord app) {
87        return (info.multiprocess || info.processName.equals(app.processName))
88                && uid == app.info.uid;
89    }
90
91    public void addExternalProcessHandleLocked(IBinder token) {
92        if (token == null) {
93            externalProcessNoHandleCount++;
94        } else {
95            if (externalProcessTokenToHandle == null) {
96                externalProcessTokenToHandle = new HashMap<IBinder, ExternalProcessHandle>();
97            }
98            ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
99            if (handle == null) {
100                handle = new ExternalProcessHandle(token);
101                externalProcessTokenToHandle.put(token, handle);
102            }
103            handle.mAcquisitionCount++;
104        }
105    }
106
107    public boolean removeExternalProcessHandleLocked(IBinder token) {
108        if (hasExternalProcessHandles()) {
109            boolean hasHandle = false;
110            if (externalProcessTokenToHandle != null) {
111                ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
112                if (handle != null) {
113                    hasHandle = true;
114                    handle.mAcquisitionCount--;
115                    if (handle.mAcquisitionCount == 0) {
116                        removeExternalProcessHandleInternalLocked(token);
117                        return true;
118                    }
119                }
120            }
121            if (!hasHandle) {
122                externalProcessNoHandleCount--;
123                return true;
124            }
125        }
126        return false;
127    }
128
129    private void removeExternalProcessHandleInternalLocked(IBinder token) {
130        ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
131        handle.unlinkFromOwnDeathLocked();
132        externalProcessTokenToHandle.remove(token);
133        if (externalProcessTokenToHandle.size() == 0) {
134            externalProcessTokenToHandle = null;
135        }
136    }
137
138    public boolean hasExternalProcessHandles() {
139        return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0);
140    }
141
142    void dump(PrintWriter pw, String prefix, boolean full) {
143        if (full) {
144            pw.print(prefix); pw.print("package=");
145                    pw.print(info.applicationInfo.packageName);
146                    pw.print(" process="); pw.println(info.processName);
147        }
148        pw.print(prefix); pw.print("proc="); pw.println(proc);
149        if (launchingApp != null) {
150            pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp);
151        }
152        if (full) {
153            pw.print(prefix); pw.print("uid="); pw.print(uid);
154                    pw.print(" provider="); pw.println(provider);
155        }
156        if (singleton) {
157            pw.print(prefix); pw.print("singleton="); pw.println(singleton);
158        }
159        pw.print(prefix); pw.print("authority="); pw.println(info.authority);
160        if (full) {
161            if (info.isSyncable || info.multiprocess || info.initOrder != 0) {
162                pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable);
163                        pw.print(" multiprocess="); pw.print(info.multiprocess);
164                        pw.print(" initOrder="); pw.println(info.initOrder);
165            }
166        }
167        if (full) {
168            if (hasExternalProcessHandles()) {
169                pw.print(prefix); pw.print("externals:");
170                if (externalProcessTokenToHandle != null) {
171                    pw.print(" w/token=");
172                    pw.print(externalProcessTokenToHandle.size());
173                }
174                if (externalProcessNoHandleCount > 0) {
175                    pw.print(" notoken=");
176                    pw.print(externalProcessNoHandleCount);
177                }
178                pw.println();
179            }
180        } else {
181            if (connections.size() > 0 || externalProcessNoHandleCount > 0) {
182                pw.print(prefix); pw.print(connections.size());
183                        pw.print(" connections, "); pw.print(externalProcessNoHandleCount);
184                        pw.println(" external handles");
185            }
186        }
187        if (connections.size() > 0) {
188            if (full) {
189                pw.print(prefix); pw.println("Connections:");
190            }
191            for (int i=0; i<connections.size(); i++) {
192                ContentProviderConnection conn = connections.get(i);
193                pw.print(prefix); pw.print("  -> "); pw.println(conn.toClientString());
194                if (conn.provider != this) {
195                    pw.print(prefix); pw.print("    *** WRONG PROVIDER: ");
196                            pw.println(conn.provider);
197                }
198            }
199        }
200    }
201
202    @Override
203    public String toString() {
204        if (stringName != null) {
205            return stringName;
206        }
207        StringBuilder sb = new StringBuilder(128);
208        sb.append("ContentProviderRecord{");
209        sb.append(Integer.toHexString(System.identityHashCode(this)));
210        sb.append(" u");
211        sb.append(UserHandle.getUserId(uid));
212        sb.append(' ');
213        sb.append(name.flattenToShortString());
214        sb.append('}');
215        return stringName = sb.toString();
216    }
217
218    public String toShortString() {
219        if (shortStringName != null) {
220            return shortStringName;
221        }
222        StringBuilder sb = new StringBuilder(128);
223        sb.append(Integer.toHexString(System.identityHashCode(this)));
224        sb.append('/');
225        sb.append(name.flattenToShortString());
226        return shortStringName = sb.toString();
227    }
228
229    // This class represents a handle from an external process to a provider.
230    private class ExternalProcessHandle implements DeathRecipient {
231        private static final String LOG_TAG = "ExternalProcessHanldle";
232
233        private final IBinder mToken;
234        private int mAcquisitionCount;
235
236        public ExternalProcessHandle(IBinder token) {
237            mToken = token;
238            try {
239                token.linkToDeath(this, 0);
240            } catch (RemoteException re) {
241                Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re);
242            }
243        }
244
245        public void unlinkFromOwnDeathLocked() {
246            mToken.unlinkToDeath(this, 0);
247        }
248
249        @Override
250        public void binderDied() {
251            synchronized (service) {
252                if (hasExternalProcessHandles() &&
253                        externalProcessTokenToHandle.get(mToken) != null) {
254                    removeExternalProcessHandleInternalLocked(mToken);
255                }
256            }
257        }
258    }
259}
260