ContentProviderRecord.java revision 49782e46c0eb85a25ae2abcf80880c48dbab5aea
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 pw.println(externalProcessTokenToHandle.size()); 171 } 172 } else { 173 if (connections.size() > 0 || externalProcessNoHandleCount > 0) { 174 pw.print(prefix); pw.print(connections.size()); 175 pw.print(" connections, "); pw.print(externalProcessNoHandleCount); 176 pw.println(" external handles"); 177 } 178 } 179 if (connections.size() > 0) { 180 if (full) { 181 pw.print(prefix); pw.println("Connections:"); 182 } 183 for (int i=0; i<connections.size(); i++) { 184 ContentProviderConnection conn = connections.get(i); 185 pw.print(prefix); pw.print(" -> "); pw.println(conn.toClientString()); 186 if (conn.provider != this) { 187 pw.print(prefix); pw.print(" *** WRONG PROVIDER: "); 188 pw.println(conn.provider); 189 } 190 } 191 } 192 } 193 194 @Override 195 public String toString() { 196 if (stringName != null) { 197 return stringName; 198 } 199 StringBuilder sb = new StringBuilder(128); 200 sb.append("ContentProviderRecord{"); 201 sb.append(Integer.toHexString(System.identityHashCode(this))); 202 sb.append(" u"); 203 sb.append(UserHandle.getUserId(uid)); 204 sb.append(' '); 205 sb.append(name.flattenToShortString()); 206 sb.append('}'); 207 return stringName = sb.toString(); 208 } 209 210 public String toShortString() { 211 if (shortStringName != null) { 212 return shortStringName; 213 } 214 StringBuilder sb = new StringBuilder(128); 215 sb.append(Integer.toHexString(System.identityHashCode(this))); 216 sb.append('/'); 217 sb.append(name.flattenToShortString()); 218 return shortStringName = sb.toString(); 219 } 220 221 // This class represents a handle from an external process to a provider. 222 private class ExternalProcessHandle implements DeathRecipient { 223 private static final String LOG_TAG = "ExternalProcessHanldle"; 224 225 private final IBinder mToken; 226 private int mAcquisitionCount; 227 228 public ExternalProcessHandle(IBinder token) { 229 mToken = token; 230 try { 231 token.linkToDeath(this, 0); 232 } catch (RemoteException re) { 233 Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re); 234 } 235 } 236 237 public void unlinkFromOwnDeathLocked() { 238 mToken.unlinkToDeath(this, 0); 239 } 240 241 @Override 242 public void binderDied() { 243 synchronized (service) { 244 if (hasExternalProcessHandles() && 245 externalProcessTokenToHandle.get(mToken) != null) { 246 removeExternalProcessHandleInternalLocked(mToken); 247 } 248 } 249 } 250 } 251} 252