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