Home | History | Annotate | Download | only in am
      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