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 static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 20 21 import android.app.ContentProviderHolder; 22 import android.app.IApplicationThread; 23 import android.content.ComponentName; 24 import android.content.IContentProvider; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.ProviderInfo; 27 import android.os.IBinder; 28 import android.os.IBinder.DeathRecipient; 29 import android.os.Process; 30 import android.os.RemoteException; 31 import android.os.UserHandle; 32 import android.util.ArrayMap; 33 import android.util.Slog; 34 35 import com.android.internal.app.procstats.AssociationState; 36 import com.android.internal.app.procstats.ProcessStats; 37 38 import java.io.PrintWriter; 39 import java.util.ArrayList; 40 41 final class ContentProviderRecord implements ComponentName.WithComponentName { 42 // Maximum attempts to bring up the content provider before giving up. 43 static final int MAX_RETRY_COUNT = 3; 44 45 final ActivityManagerService service; 46 public final ProviderInfo info; 47 final int uid; 48 final ApplicationInfo appInfo; 49 final ComponentName name; 50 final boolean singleton; 51 public IContentProvider provider; 52 public boolean noReleaseNeeded; 53 // All attached clients 54 final ArrayList<ContentProviderConnection> connections 55 = new ArrayList<ContentProviderConnection>(); 56 //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>(); 57 // Handles for non-framework processes supported by this provider 58 ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle; 59 // Count for external process for which we have no handles. 60 int externalProcessNoHandleCount; 61 int mRestartCount; // number of times we tried before bringing up it successfully. 62 ProcessRecord proc; // if non-null, hosting process. 63 ProcessRecord launchingApp; // if non-null, waiting for this app to be launched. 64 String stringName; 65 String shortStringName; 66 ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info, ApplicationInfo ai, ComponentName _name, boolean _singleton)67 public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info, 68 ApplicationInfo ai, ComponentName _name, boolean _singleton) { 69 service = _service; 70 info = _info; 71 uid = ai.uid; 72 appInfo = ai; 73 name = _name; 74 singleton = _singleton; 75 noReleaseNeeded = (uid == 0 || uid == Process.SYSTEM_UID) 76 && (_name == null || !"com.android.settings".equals(_name.getPackageName())); 77 } 78 ContentProviderRecord(ContentProviderRecord cpr)79 public ContentProviderRecord(ContentProviderRecord cpr) { 80 service = cpr.service; 81 info = cpr.info; 82 uid = cpr.uid; 83 appInfo = cpr.appInfo; 84 name = cpr.name; 85 singleton = cpr.singleton; 86 noReleaseNeeded = cpr.noReleaseNeeded; 87 } 88 newHolder(ContentProviderConnection conn, boolean local)89 public ContentProviderHolder newHolder(ContentProviderConnection conn, boolean local) { 90 ContentProviderHolder holder = new ContentProviderHolder(info); 91 holder.provider = provider; 92 holder.noReleaseNeeded = noReleaseNeeded; 93 holder.connection = conn; 94 holder.mLocal = local; 95 return holder; 96 } 97 setProcess(ProcessRecord proc)98 public void setProcess(ProcessRecord proc) { 99 this.proc = proc; 100 if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) { 101 for (int iconn = connections.size() - 1; iconn >= 0; iconn--) { 102 final ContentProviderConnection conn = connections.get(iconn); 103 if (proc != null) { 104 conn.startAssociationIfNeeded(); 105 } else { 106 conn.stopAssociation(); 107 } 108 } 109 if (externalProcessTokenToHandle != null) { 110 for (int iext = externalProcessTokenToHandle.size() - 1; iext >= 0; iext--) { 111 final ExternalProcessHandle handle = externalProcessTokenToHandle.valueAt(iext); 112 if (proc != null) { 113 handle.startAssociationIfNeeded(this); 114 } else { 115 handle.stopAssociation(); 116 } 117 } 118 } 119 } 120 } 121 canRunHere(ProcessRecord app)122 public boolean canRunHere(ProcessRecord app) { 123 return (info.multiprocess || info.processName.equals(app.processName)) 124 && uid == app.info.uid; 125 } 126 addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag)127 public void addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag) { 128 if (token == null) { 129 externalProcessNoHandleCount++; 130 } else { 131 if (externalProcessTokenToHandle == null) { 132 externalProcessTokenToHandle = new ArrayMap<>(); 133 } 134 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); 135 if (handle == null) { 136 handle = new ExternalProcessHandle(token, callingUid, callingTag); 137 externalProcessTokenToHandle.put(token, handle); 138 handle.startAssociationIfNeeded(this); 139 } 140 handle.mAcquisitionCount++; 141 } 142 } 143 removeExternalProcessHandleLocked(IBinder token)144 public boolean removeExternalProcessHandleLocked(IBinder token) { 145 if (hasExternalProcessHandles()) { 146 boolean hasHandle = false; 147 if (externalProcessTokenToHandle != null) { 148 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); 149 if (handle != null) { 150 hasHandle = true; 151 handle.mAcquisitionCount--; 152 if (handle.mAcquisitionCount == 0) { 153 removeExternalProcessHandleInternalLocked(token); 154 return true; 155 } 156 } 157 } 158 if (!hasHandle) { 159 externalProcessNoHandleCount--; 160 return true; 161 } 162 } 163 return false; 164 } 165 removeExternalProcessHandleInternalLocked(IBinder token)166 private void removeExternalProcessHandleInternalLocked(IBinder token) { 167 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); 168 handle.unlinkFromOwnDeathLocked(); 169 handle.stopAssociation(); 170 externalProcessTokenToHandle.remove(token); 171 if (externalProcessTokenToHandle.size() == 0) { 172 externalProcessTokenToHandle = null; 173 } 174 } 175 hasExternalProcessHandles()176 public boolean hasExternalProcessHandles() { 177 return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0); 178 } 179 hasConnectionOrHandle()180 public boolean hasConnectionOrHandle() { 181 return !connections.isEmpty() || hasExternalProcessHandles(); 182 } 183 184 /** 185 * Notify all clients that the provider has been published and ready to use, 186 * or timed out. 187 * 188 * @param status true: successfully published; false: timed out 189 */ onProviderPublishStatusLocked(boolean status)190 void onProviderPublishStatusLocked(boolean status) { 191 final int numOfConns = connections.size(); 192 for (int i = 0; i < numOfConns; i++) { 193 final ContentProviderConnection conn = connections.get(i); 194 if (conn.waiting && conn.client != null) { 195 final ProcessRecord client = conn.client; 196 if (!status) { 197 if (launchingApp == null) { 198 Slog.w(TAG_AM, "Unable to launch app " 199 + appInfo.packageName + "/" 200 + appInfo.uid + " for provider " 201 + info.authority + ": launching app became null"); 202 EventLogTags.writeAmProviderLostProcess( 203 UserHandle.getUserId(appInfo.uid), 204 appInfo.packageName, 205 appInfo.uid, info.authority); 206 } else { 207 Slog.wtf(TAG_AM, "Timeout waiting for provider " 208 + appInfo.packageName + "/" 209 + appInfo.uid + " for provider " 210 + info.authority 211 + " caller=" + client); 212 } 213 } 214 final IApplicationThread thread = client.getThread(); 215 if (thread != null) { 216 try { 217 thread.notifyContentProviderPublishStatus( 218 newHolder(status ? conn : null, false), 219 info.authority, conn.mExpectedUserId, status); 220 } catch (RemoteException e) { 221 } 222 } 223 } 224 conn.waiting = false; 225 } 226 } 227 dump(PrintWriter pw, String prefix, boolean full)228 void dump(PrintWriter pw, String prefix, boolean full) { 229 if (full) { 230 pw.print(prefix); pw.print("package="); 231 pw.print(info.applicationInfo.packageName); 232 pw.print(" process="); pw.println(info.processName); 233 } 234 pw.print(prefix); pw.print("proc="); pw.println(proc); 235 if (launchingApp != null) { 236 pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp); 237 } 238 if (full) { 239 pw.print(prefix); pw.print("uid="); pw.print(uid); 240 pw.print(" provider="); pw.println(provider); 241 } 242 if (singleton) { 243 pw.print(prefix); pw.print("singleton="); pw.println(singleton); 244 } 245 pw.print(prefix); pw.print("authority="); pw.println(info.authority); 246 if (full) { 247 if (info.isSyncable || info.multiprocess || info.initOrder != 0) { 248 pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable); 249 pw.print(" multiprocess="); pw.print(info.multiprocess); 250 pw.print(" initOrder="); pw.println(info.initOrder); 251 } 252 } 253 if (full) { 254 if (hasExternalProcessHandles()) { 255 pw.print(prefix); pw.print("externals:"); 256 if (externalProcessTokenToHandle != null) { 257 pw.print(" w/token="); 258 pw.print(externalProcessTokenToHandle.size()); 259 } 260 if (externalProcessNoHandleCount > 0) { 261 pw.print(" notoken="); 262 pw.print(externalProcessNoHandleCount); 263 } 264 pw.println(); 265 } 266 } else { 267 if (connections.size() > 0 || externalProcessNoHandleCount > 0) { 268 pw.print(prefix); pw.print(connections.size()); 269 pw.print(" connections, "); pw.print(externalProcessNoHandleCount); 270 pw.println(" external handles"); 271 } 272 } 273 if (connections.size() > 0) { 274 if (full) { 275 pw.print(prefix); pw.println("Connections:"); 276 } 277 for (int i=0; i<connections.size(); i++) { 278 ContentProviderConnection conn = connections.get(i); 279 pw.print(prefix); pw.print(" -> "); pw.println(conn.toClientString()); 280 if (conn.provider != this) { 281 pw.print(prefix); pw.print(" *** WRONG PROVIDER: "); 282 pw.println(conn.provider); 283 } 284 } 285 } 286 } 287 288 @Override toString()289 public String toString() { 290 if (stringName != null) { 291 return stringName; 292 } 293 StringBuilder sb = new StringBuilder(128); 294 sb.append("ContentProviderRecord{"); 295 sb.append(Integer.toHexString(System.identityHashCode(this))); 296 sb.append(" u"); 297 sb.append(UserHandle.getUserId(uid)); 298 sb.append(' '); 299 sb.append(name.flattenToShortString()); 300 sb.append('}'); 301 return stringName = sb.toString(); 302 } 303 toShortString()304 public String toShortString() { 305 if (shortStringName != null) { 306 return shortStringName; 307 } 308 StringBuilder sb = new StringBuilder(128); 309 sb.append(Integer.toHexString(System.identityHashCode(this))); 310 sb.append('/'); 311 sb.append(name.flattenToShortString()); 312 return shortStringName = sb.toString(); 313 } 314 315 // This class represents a handle from an external process to a provider. 316 private class ExternalProcessHandle implements DeathRecipient { 317 private static final String LOG_TAG = "ExternalProcessHanldle"; 318 319 final IBinder mToken; 320 final int mOwningUid; 321 final String mOwningProcessName; 322 int mAcquisitionCount; 323 AssociationState.SourceState mAssociation; 324 private Object mProcStatsLock; // Internal lock for accessing AssociationState 325 ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName)326 public ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName) { 327 mToken = token; 328 mOwningUid = owningUid; 329 mOwningProcessName = owningProcessName; 330 try { 331 token.linkToDeath(this, 0); 332 } catch (RemoteException re) { 333 Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re); 334 } 335 } 336 unlinkFromOwnDeathLocked()337 public void unlinkFromOwnDeathLocked() { 338 mToken.unlinkToDeath(this, 0); 339 } 340 startAssociationIfNeeded(ContentProviderRecord provider)341 public void startAssociationIfNeeded(ContentProviderRecord provider) { 342 // If we don't already have an active association, create one... but only if this 343 // is an association between two different processes. 344 if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS 345 && mAssociation == null && provider.proc != null 346 && (provider.appInfo.uid != mOwningUid 347 || !provider.info.processName.equals(mOwningProcessName))) { 348 ProcessStats.ProcessStateHolder holder = 349 provider.proc.getPkgList().get(provider.name.getPackageName()); 350 if (holder == null) { 351 Slog.wtf(TAG_AM, "No package in referenced provider " 352 + provider.name.toShortString() + ": proc=" + provider.proc); 353 } else if (holder.pkg == null) { 354 Slog.wtf(TAG_AM, "Inactive holder in referenced provider " 355 + provider.name.toShortString() + ": proc=" + provider.proc); 356 } else { 357 mProcStatsLock = provider.proc.mService.mProcessStats.mLock; 358 synchronized (mProcStatsLock) { 359 mAssociation = holder.pkg.getAssociationStateLocked(holder.state, 360 provider.name.getClassName()).startSource(mOwningUid, 361 mOwningProcessName, null); 362 } 363 } 364 } 365 } 366 stopAssociation()367 public void stopAssociation() { 368 if (mAssociation != null) { 369 synchronized (mProcStatsLock) { 370 mAssociation.stop(); 371 } 372 mAssociation = null; 373 } 374 } 375 376 @Override binderDied()377 public void binderDied() { 378 synchronized (service) { 379 if (hasExternalProcessHandles() && 380 externalProcessTokenToHandle.get(mToken) != null) { 381 removeExternalProcessHandleInternalLocked(mToken); 382 } 383 } 384 } 385 } 386 getComponentName()387 public ComponentName getComponentName() { 388 return name; 389 } 390 } 391