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 android.app.IActivityManager.ContentProviderHolder; 20 import android.content.ComponentName; 21 import android.content.IContentProvider; 22 import android.content.pm.ApplicationInfo; 23 import android.content.pm.ProviderInfo; 24 import android.os.IBinder; 25 import android.os.IBinder.DeathRecipient; 26 import android.os.Process; 27 import android.os.RemoteException; 28 import android.os.UserHandle; 29 import android.util.Slog; 30 31 import java.io.PrintWriter; 32 import java.util.ArrayList; 33 import java.util.HashMap; 34 35 final 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