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 ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info, ApplicationInfo ai, ComponentName _name, boolean _singleton)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 ContentProviderRecord(ContentProviderRecord cpr)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 newHolder(ContentProviderConnection conn)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 canRunHere(ProcessRecord app)86 public boolean canRunHere(ProcessRecord app) { 87 return (info.multiprocess || info.processName.equals(app.processName)) 88 && uid == app.info.uid; 89 } 90 addExternalProcessHandleLocked(IBinder token)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 removeExternalProcessHandleLocked(IBinder token)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 removeExternalProcessHandleInternalLocked(IBinder token)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 hasExternalProcessHandles()138 public boolean hasExternalProcessHandles() { 139 return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0); 140 } 141 hasConnectionOrHandle()142 public boolean hasConnectionOrHandle() { 143 return !connections.isEmpty() || hasExternalProcessHandles(); 144 } 145 dump(PrintWriter pw, String prefix, boolean full)146 void dump(PrintWriter pw, String prefix, boolean full) { 147 if (full) { 148 pw.print(prefix); pw.print("package="); 149 pw.print(info.applicationInfo.packageName); 150 pw.print(" process="); pw.println(info.processName); 151 } 152 pw.print(prefix); pw.print("proc="); pw.println(proc); 153 if (launchingApp != null) { 154 pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp); 155 } 156 if (full) { 157 pw.print(prefix); pw.print("uid="); pw.print(uid); 158 pw.print(" provider="); pw.println(provider); 159 } 160 if (singleton) { 161 pw.print(prefix); pw.print("singleton="); pw.println(singleton); 162 } 163 pw.print(prefix); pw.print("authority="); pw.println(info.authority); 164 if (full) { 165 if (info.isSyncable || info.multiprocess || info.initOrder != 0) { 166 pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable); 167 pw.print(" multiprocess="); pw.print(info.multiprocess); 168 pw.print(" initOrder="); pw.println(info.initOrder); 169 } 170 } 171 if (full) { 172 if (hasExternalProcessHandles()) { 173 pw.print(prefix); pw.print("externals:"); 174 if (externalProcessTokenToHandle != null) { 175 pw.print(" w/token="); 176 pw.print(externalProcessTokenToHandle.size()); 177 } 178 if (externalProcessNoHandleCount > 0) { 179 pw.print(" notoken="); 180 pw.print(externalProcessNoHandleCount); 181 } 182 pw.println(); 183 } 184 } else { 185 if (connections.size() > 0 || externalProcessNoHandleCount > 0) { 186 pw.print(prefix); pw.print(connections.size()); 187 pw.print(" connections, "); pw.print(externalProcessNoHandleCount); 188 pw.println(" external handles"); 189 } 190 } 191 if (connections.size() > 0) { 192 if (full) { 193 pw.print(prefix); pw.println("Connections:"); 194 } 195 for (int i=0; i<connections.size(); i++) { 196 ContentProviderConnection conn = connections.get(i); 197 pw.print(prefix); pw.print(" -> "); pw.println(conn.toClientString()); 198 if (conn.provider != this) { 199 pw.print(prefix); pw.print(" *** WRONG PROVIDER: "); 200 pw.println(conn.provider); 201 } 202 } 203 } 204 } 205 206 @Override toString()207 public String toString() { 208 if (stringName != null) { 209 return stringName; 210 } 211 StringBuilder sb = new StringBuilder(128); 212 sb.append("ContentProviderRecord{"); 213 sb.append(Integer.toHexString(System.identityHashCode(this))); 214 sb.append(" u"); 215 sb.append(UserHandle.getUserId(uid)); 216 sb.append(' '); 217 sb.append(name.flattenToShortString()); 218 sb.append('}'); 219 return stringName = sb.toString(); 220 } 221 toShortString()222 public String toShortString() { 223 if (shortStringName != null) { 224 return shortStringName; 225 } 226 StringBuilder sb = new StringBuilder(128); 227 sb.append(Integer.toHexString(System.identityHashCode(this))); 228 sb.append('/'); 229 sb.append(name.flattenToShortString()); 230 return shortStringName = sb.toString(); 231 } 232 233 // This class represents a handle from an external process to a provider. 234 private class ExternalProcessHandle implements DeathRecipient { 235 private static final String LOG_TAG = "ExternalProcessHanldle"; 236 237 private final IBinder mToken; 238 private int mAcquisitionCount; 239 ExternalProcessHandle(IBinder token)240 public ExternalProcessHandle(IBinder token) { 241 mToken = token; 242 try { 243 token.linkToDeath(this, 0); 244 } catch (RemoteException re) { 245 Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re); 246 } 247 } 248 unlinkFromOwnDeathLocked()249 public void unlinkFromOwnDeathLocked() { 250 mToken.unlinkToDeath(this, 0); 251 } 252 253 @Override binderDied()254 public void binderDied() { 255 synchronized (service) { 256 if (hasExternalProcessHandles() && 257 externalProcessTokenToHandle.get(mToken) != null) { 258 removeExternalProcessHandleInternalLocked(mToken); 259 } 260 } 261 } 262 } 263 } 264