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