blob: fb21b065daf54d856eb49b4fbc4a4dcf64099e34 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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;
Dianne Hackbornb7bb3b32010-06-06 22:47:50 -070020import android.content.ComponentName;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070021import android.content.IContentProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.pm.ApplicationInfo;
23import android.content.pm.ProviderInfo;
Svetoslav Ganov25872aa2012-02-03 19:19:09 -080024import android.os.IBinder;
25import android.os.IBinder.DeathRecipient;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.os.Process;
Svetoslav Ganov25872aa2012-02-03 19:19:09 -080027import android.os.RemoteException;
28import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
30import java.io.PrintWriter;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070031import java.util.ArrayList;
Svetoslav Ganov25872aa2012-02-03 19:19:09 -080032import java.util.HashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import java.util.HashSet;
34
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070035class ContentProviderRecord {
36 final ActivityManagerService service;
37 public final ProviderInfo info;
38 final int uid;
39 final ApplicationInfo appInfo;
40 final ComponentName name;
41 public IContentProvider provider;
42 public boolean noReleaseNeeded;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 // All attached clients
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070044 final ArrayList<ContentProviderConnection> connections
45 = new ArrayList<ContentProviderConnection>();
46 //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
Svetoslav Ganov25872aa2012-02-03 19:19:09 -080047 // Handles for non-framework processes supported by this provider
48 HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
49 // Count for external process for which we have no handles.
50 int externalProcessNoHandleCount;
Dianne Hackborn2a6bcda2011-09-21 15:07:05 -070051 ProcessRecord proc; // if non-null, hosting process.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070053 String stringName;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070054 String shortStringName;
Svetoslav Ganov25872aa2012-02-03 19:19:09 -080055
56 public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info,
57 ApplicationInfo ai, ComponentName _name) {
Svetoslav Ganov25872aa2012-02-03 19:19:09 -080058 service = _service;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070059 info = _info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 uid = ai.uid;
61 appInfo = ai;
Dianne Hackborn2a6bcda2011-09-21 15:07:05 -070062 name = _name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 noReleaseNeeded = uid == 0 || uid == Process.SYSTEM_UID;
64 }
65
66 public ContentProviderRecord(ContentProviderRecord cpr) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070067 service = cpr.service;
68 info = cpr.info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 uid = cpr.uid;
70 appInfo = cpr.appInfo;
Dianne Hackbornb7bb3b32010-06-06 22:47:50 -070071 name = cpr.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 noReleaseNeeded = cpr.noReleaseNeeded;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070073 }
74
75 public ContentProviderHolder newHolder(ContentProviderConnection conn) {
76 ContentProviderHolder holder = new ContentProviderHolder(info);
77 holder.provider = provider;
78 holder.noReleaseNeeded = noReleaseNeeded;
79 holder.connection = conn;
80 return holder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 }
82
83 public boolean canRunHere(ProcessRecord app) {
84 return (info.multiprocess || info.processName.equals(app.processName))
85 && (uid == Process.SYSTEM_UID || uid == app.info.uid);
86 }
87
Svetoslav Ganov25872aa2012-02-03 19:19:09 -080088 public void addExternalProcessHandleLocked(IBinder token) {
89 if (token == null) {
90 externalProcessNoHandleCount++;
91 } else {
92 if (externalProcessTokenToHandle == null) {
93 externalProcessTokenToHandle = new HashMap<IBinder, ExternalProcessHandle>();
94 }
95 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
96 if (handle == null) {
97 handle = new ExternalProcessHandle(token);
98 externalProcessTokenToHandle.put(token, handle);
99 }
100 handle.mAcquisitionCount++;
101 }
102 }
103
104 public boolean removeExternalProcessHandleLocked(IBinder token) {
105 if (hasExternalProcessHandles()) {
106 boolean hasHandle = false;
107 if (externalProcessTokenToHandle != null) {
108 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
109 if (handle != null) {
110 hasHandle = true;
111 handle.mAcquisitionCount--;
112 if (handle.mAcquisitionCount == 0) {
113 removeExternalProcessHandleInternalLocked(token);
114 return true;
115 }
116 }
117 }
118 if (!hasHandle) {
119 externalProcessNoHandleCount--;
120 return true;
121 }
122 }
123 return false;
124 }
125
126 private void removeExternalProcessHandleInternalLocked(IBinder token) {
127 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
128 handle.unlinkFromOwnDeathLocked();
129 externalProcessTokenToHandle.remove(token);
130 if (externalProcessTokenToHandle.size() == 0) {
131 externalProcessTokenToHandle = null;
132 }
133 }
134
135 public boolean hasExternalProcessHandles() {
136 return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0);
137 }
138
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700139 void dump(PrintWriter pw, String prefix, boolean full) {
140 if (full) {
141 pw.print(prefix); pw.print("package=");
142 pw.print(info.applicationInfo.packageName);
143 pw.print(" process="); pw.println(info.processName);
144 }
Dianne Hackborn2a6bcda2011-09-21 15:07:05 -0700145 pw.print(prefix); pw.print("proc="); pw.println(proc);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700146 if (launchingApp != null) {
147 pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp);
148 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700149 if (full) {
150 pw.print(prefix); pw.print("uid="); pw.print(uid);
151 pw.print(" provider="); pw.println(provider);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700152 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700153 pw.print(prefix); pw.print("authority="); pw.println(info.authority);
154 if (full) {
155 if (info.isSyncable || info.multiprocess || info.initOrder != 0) {
156 pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable);
157 pw.print(" multiprocess="); pw.print(info.multiprocess);
158 pw.print(" initOrder="); pw.println(info.initOrder);
159 }
Dianne Hackbornd8c98fe2011-11-15 11:29:38 -0800160 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700161 if (full) {
162 if (hasExternalProcessHandles()) {
163 pw.print(prefix); pw.print("externals=");
164 pw.println(externalProcessTokenToHandle.size());
165 }
166 } else {
167 if (connections.size() > 0 || externalProcessNoHandleCount > 0) {
168 pw.print(prefix); pw.print(connections.size());
169 pw.print(" connections, "); pw.print(externalProcessNoHandleCount);
170 pw.println(" external handles");
171 }
172 }
173 if (connections.size() > 0) {
174 if (full) {
175 pw.print(prefix); pw.println("Connections:");
176 }
177 for (int i=0; i<connections.size(); i++) {
178 ContentProviderConnection conn = connections.get(i);
179 pw.print(prefix); pw.print(" -> "); pw.println(conn.toClientString());
180 if (conn.provider != this) {
181 pw.print(prefix); pw.print(" *** WRONG PROVIDER: ");
182 pw.println(conn.provider);
183 }
Dianne Hackborn8ec8d412011-11-14 18:27:24 -0800184 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700185 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 }
187
Svetoslav Ganov25872aa2012-02-03 19:19:09 -0800188 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 public String toString() {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700190 if (stringName != null) {
191 return stringName;
192 }
193 StringBuilder sb = new StringBuilder(128);
194 sb.append("ContentProviderRecord{");
195 sb.append(Integer.toHexString(System.identityHashCode(this)));
196 sb.append(' ');
Dianne Hackborn9da2d402012-03-15 13:43:08 -0700197 sb.append(name.flattenToShortString());
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700198 sb.append('}');
199 return stringName = sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 }
Svetoslav Ganov25872aa2012-02-03 19:19:09 -0800201
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700202 public String toShortString() {
203 if (shortStringName != null) {
204 return shortStringName;
205 }
206 StringBuilder sb = new StringBuilder(128);
207 sb.append(Integer.toHexString(System.identityHashCode(this)));
208 sb.append('/');
209 sb.append(name.flattenToShortString());
210 return shortStringName = sb.toString();
211 }
212
Svetoslav Ganov25872aa2012-02-03 19:19:09 -0800213 // This class represents a handle from an external process to a provider.
214 private class ExternalProcessHandle implements DeathRecipient {
215 private static final String LOG_TAG = "ExternalProcessHanldle";
216
217 private final IBinder mToken;
218 private int mAcquisitionCount;
219
220 public ExternalProcessHandle(IBinder token) {
221 mToken = token;
222 try {
223 token.linkToDeath(this, 0);
224 } catch (RemoteException re) {
225 Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re);
226 }
227 }
228
229 public void unlinkFromOwnDeathLocked() {
230 mToken.unlinkToDeath(this, 0);
231 }
232
233 @Override
234 public void binderDied() {
235 synchronized (service) {
236 if (hasExternalProcessHandles() &&
237 externalProcessTokenToHandle.get(mToken) != null) {
238 removeExternalProcessHandleInternalLocked(mToken);
239 }
240 }
241 }
242 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243}