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.util.Slog; 29 30 import java.io.PrintWriter; 31 import java.util.ArrayList; 32 import java.util.HashMap; 33 import java.util.HashSet; 34 35 class 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; 43 // All attached clients 44 final ArrayList<ContentProviderConnection> connections 45 = new ArrayList<ContentProviderConnection>(); 46 //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>(); 47 // 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; 51 ProcessRecord proc; // if non-null, hosting process. 52 ProcessRecord launchingApp; // if non-null, waiting for this app to be launched. 53 String stringName; 54 String shortStringName; 55 56 public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info, 57 ApplicationInfo ai, ComponentName _name) { 58 service = _service; 59 info = _info; 60 uid = ai.uid; 61 appInfo = ai; 62 name = _name; 63 noReleaseNeeded = uid == 0 || uid == Process.SYSTEM_UID; 64 } 65 66 public ContentProviderRecord(ContentProviderRecord cpr) { 67 service = cpr.service; 68 info = cpr.info; 69 uid = cpr.uid; 70 appInfo = cpr.appInfo; 71 name = cpr.name; 72 noReleaseNeeded = cpr.noReleaseNeeded; 73 } 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; 81 } 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 88 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 139 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 } 145 pw.print(prefix); pw.print("proc="); pw.println(proc); 146 if (launchingApp != null) { 147 pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp); 148 } 149 if (full) { 150 pw.print(prefix); pw.print("uid="); pw.print(uid); 151 pw.print(" provider="); pw.println(provider); 152 } 153 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 } 160 } 161 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 } 184 } 185 } 186 } 187 188 @Override 189 public String toString() { 190 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(' '); 197 sb.append(name.flattenToShortString()); 198 sb.append('}'); 199 return stringName = sb.toString(); 200 } 201 202 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 213 // 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 } 243 } 244