summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java470
-rw-r--r--services/java/com/android/server/am/ContentProviderConnection.java87
-rw-r--r--services/java/com/android/server/am/ContentProviderRecord.java102
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java40
-rw-r--r--services/java/com/android/server/am/ProviderMap.java30
5 files changed, 496 insertions, 233 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6464d7f..9d9b5b8 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -62,6 +62,7 @@ import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.IContentProvider;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
@@ -1810,12 +1811,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
}
- if (app.conProviders.size() > 0) {
- for (ContentProviderRecord cpr : app.conProviders.keySet()) {
- if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cpr.proc, oomAdj,
- updateActivityTime, i+1);
- }
+ for (int j=app.conProviders.size()-1; j>=0; j--) {
+ ContentProviderRecord cpr = app.conProviders.get(j).provider;
+ if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
+ updateLruProcessInternalLocked(cpr.proc, oomAdj,
+ updateActivityTime, i+1);
}
}
@@ -3742,7 +3742,7 @@ public final class ActivityManagerService extends ActivityManagerNative
N = providers.size();
for (i=0; i<N; i++) {
- removeDyingProviderLocked(null, providers.get(i));
+ removeDyingProviderLocked(null, providers.get(i), true);
}
if (doit) {
@@ -6058,53 +6058,72 @@ public final class ActivityManagerService extends ActivityManagerNative
return msg;
}
- boolean incProviderCount(ProcessRecord r, final ContentProviderRecord cpr,
- IBinder externalProcessToken) {
+ ContentProviderConnection incProviderCountLocked(ProcessRecord r,
+ final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (r != null) {
- Integer cnt = r.conProviders.get(cpr);
- if (DEBUG_PROVIDER) Slog.v(TAG,
- "Adding provider requested by "
- + r.processName + " from process "
- + cpr.info.processName + ": " + cpr.name.flattenToShortString()
- + " cnt=" + (cnt == null ? 1 : cnt));
- if (cnt == null) {
- cpr.clients.add(r);
- r.conProviders.put(cpr, new Integer(1));
- return true;
+ for (int i=0; i<r.conProviders.size(); i++) {
+ ContentProviderConnection conn = r.conProviders.get(i);
+ if (conn.provider == cpr) {
+ if (DEBUG_PROVIDER) Slog.v(TAG,
+ "Adding provider requested by "
+ + r.processName + " from process "
+ + cpr.info.processName + ": " + cpr.name.flattenToShortString()
+ + " scnt=" + conn.stableCount + " uscnt=" + conn.unstableCount);
+ if (stable) {
+ conn.stableCount++;
+ conn.numStableIncs++;
+ } else {
+ conn.unstableCount++;
+ conn.numUnstableIncs++;
+ }
+ return conn;
+ }
+ }
+ ContentProviderConnection conn = new ContentProviderConnection(cpr, r);
+ if (stable) {
+ conn.stableCount = 1;
+ conn.numStableIncs = 1;
} else {
- r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
+ conn.unstableCount = 1;
+ conn.numUnstableIncs = 1;
}
- } else {
- cpr.addExternalProcessHandleLocked(externalProcessToken);
+ cpr.connections.add(conn);
+ r.conProviders.add(conn);
+ return conn;
}
- return false;
+ cpr.addExternalProcessHandleLocked(externalProcessToken);
+ return null;
}
- boolean decProviderCount(ProcessRecord r, final ContentProviderRecord cpr,
- IBinder externalProcessToken) {
- if (r != null) {
- Integer cnt = r.conProviders.get(cpr);
+ boolean decProviderCountLocked(ContentProviderConnection conn,
+ ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
+ if (conn != null) {
+ cpr = conn.provider;
if (DEBUG_PROVIDER) Slog.v(TAG,
"Removing provider requested by "
- + r.processName + " from process "
+ + conn.client.processName + " from process "
+ cpr.info.processName + ": " + cpr.name.flattenToShortString()
- + " cnt=" + cnt);
- if (cnt == null || cnt.intValue() <= 1) {
- cpr.clients.remove(r);
- r.conProviders.remove(cpr);
- return true;
+ + " scnt=" + conn.stableCount + " uscnt=" + conn.unstableCount);
+ if (stable) {
+ conn.stableCount--;
} else {
- r.conProviders.put(cpr, new Integer(cnt.intValue()-1));
+ conn.unstableCount--;
}
- } else {
- cpr.removeExternalProcessHandleLocked(externalProcessToken);
+ if (conn.stableCount == 0 && conn.unstableCount == 0) {
+ cpr.connections.remove(conn);
+ conn.client.conProviders.remove(conn);
+ return true;
+ }
+ return false;
}
+ cpr.removeExternalProcessHandleLocked(externalProcessToken);
return false;
}
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
- String name, IBinder token) {
+ String name, IBinder token, boolean stable) {
ContentProviderRecord cpr;
+ ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
@@ -6135,20 +6154,19 @@ public final class ActivityManagerService extends ActivityManagerNative
// of being published... but it is also allowed to run
// in the caller's process, so don't make a connection
// and just let the caller instantiate its own instance.
- if (cpr.provider != null) {
- // don't give caller the provider object, it needs
- // to make its own.
- cpr = new ContentProviderRecord(cpr);
- }
- return cpr;
+ ContentProviderHolder holder = cpr.newHolder(null);
+ // don't give caller the provider object, it needs
+ // to make its own.
+ holder.provider = null;
+ return holder;
}
final long origId = Binder.clearCallingIdentity();
// In this case the provider instance already exists, so we can
// return it right away.
- final boolean countChanged = incProviderCount(r, cpr, token);
- if (countChanged) {
+ conn = incProviderCountLocked(r, cpr, token, stable);
+ if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// If this is a perceptible app accessing the provider,
// make sure to count it as being accessed and thus
@@ -6181,7 +6199,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.i(TAG,
"Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
- boolean lastRef = decProviderCount(r, cpr, token);
+ boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
appDiedLocked(cpr.proc, cpr.proc.pid, cpr.proc.thread);
if (!lastRef) {
// This wasn't the last ref our process had on
@@ -6189,6 +6207,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return null;
}
providerRunning = false;
+ conn = null;
}
}
@@ -6251,7 +6270,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// info and allow the caller to instantiate it. Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
- return cpr;
+ return cpr.newHolder(null);
}
if (DEBUG_PROVIDER) {
@@ -6312,7 +6331,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
mProviderMap.putProviderByName(name, cpr);
- incProviderCount(r, cpr, token);
+ conn = incProviderCountLocked(r, cpr, token, stable);
+ if (conn != null) {
+ conn.waiting = true;
+ }
}
}
@@ -6334,16 +6356,23 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.v(TAG_MU, "Waiting to start provider " + cpr + " launchingApp="
+ cpr.launchingApp);
}
+ if (conn != null) {
+ conn.waiting = true;
+ }
cpr.wait();
} catch (InterruptedException ex) {
+ } finally {
+ if (conn != null) {
+ conn.waiting = false;
+ }
}
}
}
- return cpr;
+ return cpr != null ? cpr.newHolder(conn) : null;
}
public final ContentProviderHolder getContentProvider(
- IApplicationThread caller, String name) {
+ IApplicationThread caller, String name, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
@@ -6352,7 +6381,7 @@ public final class ActivityManagerService extends ActivityManagerNative
throw new SecurityException(msg);
}
- return getContentProviderImpl(caller, name, null);
+ return getContentProviderImpl(caller, name, null, stable);
}
public ContentProviderHolder getContentProviderExternal(String name, IBinder token) {
@@ -6362,45 +6391,30 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private ContentProviderHolder getContentProviderExternalUnchecked(String name,IBinder token) {
- return getContentProviderImpl(null, name, token);
+ return getContentProviderImpl(null, name, token, true);
}
/**
* Drop a content provider from a ProcessRecord's bookkeeping
* @param cpr
*/
- public void removeContentProvider(IApplicationThread caller, String name) {
+ public void removeContentProvider(IBinder connection, boolean stable) {
enforceNotIsolatedCaller("removeContentProvider");
synchronized (this) {
- int userId = UserId.getUserId(Binder.getCallingUid());
- ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
- if(cpr == null) {
- // remove from mProvidersByClass
- if (DEBUG_PROVIDER) Slog.v(TAG, name +
- " provider not found in providers list");
- return;
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection)connection;
+ } catch (ClassCastException e) {
+ String msg ="removeContentProvider: " + connection
+ + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
}
- final ProcessRecord r = getRecordForAppLocked(caller);
- if (r == null) {
- throw new SecurityException(
- "Unable to find app for caller " + caller +
- " when removing content provider " + name);
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
}
- //update content provider record entry info
- ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
- ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
- if (DEBUG_PROVIDER) Slog.v(TAG, "Removing provider requested by "
- + r.info.processName + " from process "
- + localCpr.appInfo.processName);
- if (localCpr.launchingApp == r) {
- //should not happen. taken care of as a local provider
- Slog.w(TAG, "removeContentProvider called on local provider: "
- + cpr.info.name + " in process " + r.processName);
- return;
- } else {
- if (decProviderCount(r, localCpr, null)) {
- updateOomAdjLocked();
- }
+ if (decProviderCountLocked(conn, null, null, stable)) {
+ updateOomAdjLocked();
}
}
}
@@ -6447,7 +6461,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
enforceNotIsolatedCaller("publishContentProviders");
- synchronized(this) {
+ synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (DEBUG_MU)
Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
@@ -6499,6 +6513,103 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ public boolean refContentProvider(IBinder connection, int stable, int unstable) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection)connection;
+ } catch (ClassCastException e) {
+ String msg ="refContentProvider: " + connection
+ + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+
+ synchronized (this) {
+ if (stable > 0) {
+ conn.numStableIncs += stable;
+ }
+ stable = conn.stableCount + stable;
+ if (stable < 0) {
+ throw new IllegalStateException("stableCount < 0: " + stable);
+ }
+
+ if (unstable > 0) {
+ conn.numUnstableIncs += unstable;
+ }
+ unstable = conn.unstableCount + unstable;
+ if (unstable < 0) {
+ throw new IllegalStateException("unstableCount < 0: " + unstable);
+ }
+
+ if ((stable+unstable) <= 0) {
+ throw new IllegalStateException("ref counts can't go to zero here: stable="
+ + stable + " unstable=" + unstable);
+ }
+ conn.stableCount = stable;
+ conn.unstableCount = unstable;
+ return !conn.dead;
+ }
+ }
+
+ public void unstableProviderDied(IBinder connection) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection)connection;
+ } catch (ClassCastException e) {
+ String msg ="refContentProvider: " + connection
+ + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+
+ // Safely retrieve the content provider associated with the connection.
+ IContentProvider provider;
+ synchronized (this) {
+ provider = conn.provider.provider;
+ }
+
+ if (provider == null) {
+ // Um, yeah, we're way ahead of you.
+ return;
+ }
+
+ // Make sure the caller is being honest with us.
+ if (provider.asBinder().pingBinder()) {
+ // Er, no, still looks good to us.
+ synchronized (this) {
+ Slog.w(TAG, "unstableProviderDied: caller " + Binder.getCallingUid()
+ + " says " + conn + " died, but we don't agree");
+ return;
+ }
+ }
+
+ // Well look at that! It's dead!
+ synchronized (this) {
+ if (conn.provider.provider != provider) {
+ // But something changed... good enough.
+ return;
+ }
+
+ ProcessRecord proc = conn.provider.proc;
+ if (proc == null || proc.thread == null) {
+ // Seems like the process is already cleaned up.
+ return;
+ }
+
+ // As far as we're concerned, this is just like receiving a
+ // death notification... just a bit prematurely.
+ Slog.i(TAG, "Process " + proc.processName + " (pid " + proc.pid
+ + ") early provider death");
+ appDiedLocked(proc, proc.pid, proc.thread);
+ }
+ }
+
public static final void installSystemProviders() {
List<ProviderInfo> providers;
synchronized (mSelf) {
@@ -10515,36 +10626,62 @@ public final class ActivityManagerService extends ActivityManagerNative
app.executingServices.clear();
}
- private final void removeDyingProviderLocked(ProcessRecord proc,
- ContentProviderRecord cpr) {
- synchronized (cpr) {
- cpr.launchingApp = null;
- cpr.notifyAll();
- }
-
- mProviderMap.removeProviderByClass(cpr.name, UserId.getUserId(cpr.uid));
- String names[] = cpr.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- mProviderMap.removeProviderByName(names[j], UserId.getUserId(cpr.uid));
+ private final boolean removeDyingProviderLocked(ProcessRecord proc,
+ ContentProviderRecord cpr, boolean always) {
+ final boolean inLaunching = mLaunchingProviders.contains(cpr);
+
+ if (!inLaunching || always) {
+ synchronized (cpr) {
+ cpr.launchingApp = null;
+ cpr.notifyAll();
+ }
+ mProviderMap.removeProviderByClass(cpr.name, UserId.getUserId(cpr.uid));
+ String names[] = cpr.info.authority.split(";");
+ for (int j = 0; j < names.length; j++) {
+ mProviderMap.removeProviderByName(names[j], UserId.getUserId(cpr.uid));
+ }
}
-
- Iterator<ProcessRecord> cit = cpr.clients.iterator();
- while (cit.hasNext()) {
- ProcessRecord capp = cit.next();
- if (!capp.persistent && capp.thread != null
- && capp.pid != 0
- && capp.pid != MY_PID) {
- Slog.i(TAG, "Kill " + capp.processName
- + " (pid " + capp.pid + "): provider " + cpr.info.name
- + " in dying process " + (proc != null ? proc.processName : "??"));
- EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
- capp.processName, capp.setAdj, "dying provider "
- + cpr.name.toShortString());
- Process.killProcessQuiet(capp.pid);
+
+ for (int i=0; i<cpr.connections.size(); i++) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ if (conn.waiting) {
+ // If this connection is waiting for the provider, then we don't
+ // need to mess with its process unless we are always removing
+ // or for some reason the provider is not currently launching.
+ if (inLaunching && !always) {
+ continue;
+ }
+ }
+ ProcessRecord capp = conn.client;
+ conn.dead = true;
+ if (conn.stableCount > 0) {
+ if (!capp.persistent && capp.thread != null
+ && capp.pid != 0
+ && capp.pid != MY_PID) {
+ Slog.i(TAG, "Kill " + capp.processName
+ + " (pid " + capp.pid + "): provider " + cpr.info.name
+ + " in dying process " + (proc != null ? proc.processName : "??"));
+ EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
+ capp.processName, capp.setAdj, "dying provider "
+ + cpr.name.toShortString());
+ Process.killProcessQuiet(capp.pid);
+ }
+ } else if (capp.thread != null && conn.provider.provider != null) {
+ try {
+ capp.thread.unstableProviderDied(conn.provider.provider.asBinder());
+ } catch (RemoteException e) {
+ }
+ // In the protocol here, we don't expect the client to correctly
+ // clean up this connection, we'll just remove it.
+ cpr.connections.remove(i);
+ conn.client.conProviders.remove(conn);
}
}
-
- mLaunchingProviders.remove(cpr);
+
+ if (inLaunching && always) {
+ mLaunchingProviders.remove(cpr);
+ }
+ return inLaunching;
}
/**
@@ -10590,34 +10727,21 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean restart = false;
- int NL = mLaunchingProviders.size();
-
// Remove published content providers.
if (!app.pubProviders.isEmpty()) {
Iterator<ContentProviderRecord> it = app.pubProviders.values().iterator();
while (it.hasNext()) {
ContentProviderRecord cpr = it.next();
- cpr.provider = null;
- cpr.proc = null;
- // See if someone is waiting for this provider... in which
- // case we don't remove it, but just let it restart.
- int i = 0;
- if (!app.bad && allowRestart) {
- for (; i<NL; i++) {
- if (mLaunchingProviders.get(i) == cpr) {
- restart = true;
- break;
- }
- }
- } else {
- i = NL;
+ final boolean always = app.bad || !allowRestart;
+ if (removeDyingProviderLocked(app, cpr, always) || always) {
+ // We left the provider in the launching list, need to
+ // restart it.
+ restart = true;
}
- if (i >= NL) {
- removeDyingProviderLocked(app, cpr);
- NL = mLaunchingProviders.size();
- }
+ cpr.provider = null;
+ cpr.proc = null;
}
app.pubProviders.clear();
}
@@ -10629,10 +10753,9 @@ public final class ActivityManagerService extends ActivityManagerNative
// Unregister from connected content providers.
if (!app.conProviders.isEmpty()) {
- Iterator it = app.conProviders.keySet().iterator();
- while (it.hasNext()) {
- ContentProviderRecord cpr = (ContentProviderRecord)it.next();
- cpr.clients.remove(app);
+ for (int i=0; i<app.conProviders.size(); i++) {
+ ContentProviderConnection conn = app.conProviders.get(i);
+ conn.provider.connections.remove(conn);
}
app.conProviders.clear();
}
@@ -10643,10 +10766,10 @@ public final class ActivityManagerService extends ActivityManagerNative
// XXX Commented out for now. Trying to figure out a way to reproduce
// the actual situation to identify what is actually going on.
if (false) {
- for (int i=0; i<NL; i++) {
+ for (int i=0; i<mLaunchingProviders.size(); i++) {
ContentProviderRecord cpr = (ContentProviderRecord)
mLaunchingProviders.get(i);
- if (cpr.clients.size() <= 0 && !cpr.hasExternalProcessHandles()) {
+ if (cpr.connections.size() <= 0 && !cpr.hasExternalProcessHandles()) {
synchronized (cpr) {
cpr.launchingApp = null;
cpr.notifyAll();
@@ -10743,7 +10866,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (!alwaysBad && !app.bad) {
restart = true;
} else {
- removeDyingProviderLocked(app, cpr);
+ removeDyingProviderLocked(app, cpr, true);
NL = mLaunchingProviders.size();
}
}
@@ -13948,48 +14071,49 @@ public final class ActivityManagerService extends ActivityManagerNative
while (jt.hasNext() && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
ContentProviderRecord cpr = jt.next();
- if (cpr.clients.size() != 0) {
- Iterator<ProcessRecord> kt = cpr.clients.iterator();
- while (kt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
- ProcessRecord client = kt.next();
- if (client == app) {
- // Being our own client is not interesting.
- continue;
+ for (int i = cpr.connections.size()-1;
+ i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ i--) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ ProcessRecord client = conn.client;
+ if (client == app) {
+ // Being our own client is not interesting.
+ continue;
+ }
+ int myHiddenAdj = hiddenAdj;
+ if (myHiddenAdj > client.hiddenAdj) {
+ if (client.hiddenAdj > ProcessList.FOREGROUND_APP_ADJ) {
+ myHiddenAdj = client.hiddenAdj;
+ } else {
+ myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
}
- int myHiddenAdj = hiddenAdj;
- if (myHiddenAdj > client.hiddenAdj) {
- if (client.hiddenAdj > ProcessList.FOREGROUND_APP_ADJ) {
- myHiddenAdj = client.hiddenAdj;
- } else {
- myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
- }
+ }
+ int clientAdj = computeOomAdjLocked(
+ client, myHiddenAdj, TOP_APP, true, doingAll);
+ if (adj > clientAdj) {
+ if (app.hasShownUi && app != mHomeProcess
+ && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ app.adjType = "bg-ui-provider";
+ } else {
+ adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
+ ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
+ app.adjType = "provider";
}
- int clientAdj = computeOomAdjLocked(
- client, myHiddenAdj, TOP_APP, true, doingAll);
- if (adj > clientAdj) {
- if (app.hasShownUi && app != mHomeProcess
- && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- app.adjType = "bg-ui-provider";
- } else {
- adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
- ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
- app.adjType = "provider";
- }
- if (!client.hidden) {
- app.hidden = false;
- }
- if (client.keeping) {
- app.keeping = true;
- }
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_PROVIDER_IN_USE;
- app.adjSource = client;
- app.adjSourceOom = clientAdj;
- app.adjTarget = cpr.name;
+ if (!client.hidden) {
+ app.hidden = false;
}
- if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ if (client.keeping) {
+ app.keeping = true;
}
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_PROVIDER_IN_USE;
+ app.adjSource = client;
+ app.adjSourceOom = clientAdj;
+ app.adjTarget = cpr.name;
+ }
+ if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
}
}
// If the provider has external (non-framework) process
diff --git a/services/java/com/android/server/am/ContentProviderConnection.java b/services/java/com/android/server/am/ContentProviderConnection.java
new file mode 100644
index 0000000..84f8f02
--- /dev/null
+++ b/services/java/com/android/server/am/ContentProviderConnection.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.os.Binder;
+
+/**
+ * Represents a link between a content provider and client.
+ */
+public class ContentProviderConnection extends Binder {
+ public final ContentProviderRecord provider;
+ public final ProcessRecord client;
+ public int stableCount;
+ public int unstableCount;
+ // The client of this connection is currently waiting for the provider to appear.
+ // Protected by the provider lock.
+ public boolean waiting;
+ // The provider of this connection is now dead.
+ public boolean dead;
+
+ // For debugging.
+ public int numStableIncs;
+ public int numUnstableIncs;
+
+ public ContentProviderConnection(ContentProviderRecord _provider, ProcessRecord _client) {
+ provider = _provider;
+ client = _client;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("ContentProviderConnection{");
+ toShortString(sb);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public String toShortString() {
+ StringBuilder sb = new StringBuilder(128);
+ toShortString(sb);
+ return sb.toString();
+ }
+
+ public String toClientString() {
+ StringBuilder sb = new StringBuilder(128);
+ toClientString(sb);
+ return sb.toString();
+ }
+
+ public void toShortString(StringBuilder sb) {
+ sb.append(provider.toShortString());
+ sb.append("->");
+ toClientString(sb);
+ }
+
+ public void toClientString(StringBuilder sb) {
+ sb.append(client.toShortString());
+ sb.append(" s");
+ sb.append(stableCount);
+ sb.append("/");
+ sb.append(numStableIncs);
+ sb.append(" u");
+ sb.append(unstableCount);
+ sb.append("/");
+ sb.append(numUnstableIncs);
+ if (waiting) {
+ sb.append(" WAITING");
+ }
+ if (dead) {
+ sb.append(" DEAD");
+ }
+ }
+}
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index 608b09a..fb21b06 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -18,6 +18,7 @@ package com.android.server.am;
import android.app.IActivityManager.ContentProviderHolder;
import android.content.ComponentName;
+import android.content.IContentProvider;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
import android.os.IBinder;
@@ -27,28 +28,35 @@ import android.os.RemoteException;
import android.util.Slog;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-class ContentProviderRecord extends ContentProviderHolder {
+class ContentProviderRecord {
+ final ActivityManagerService service;
+ public final ProviderInfo info;
+ final int uid;
+ final ApplicationInfo appInfo;
+ final ComponentName name;
+ public IContentProvider provider;
+ public boolean noReleaseNeeded;
// All attached clients
- final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
+ final ArrayList<ContentProviderConnection> connections
+ = new ArrayList<ContentProviderConnection>();
+ //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
// Handles for non-framework processes supported by this provider
HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
// Count for external process for which we have no handles.
int externalProcessNoHandleCount;
- final ActivityManagerService service;
- final int uid;
- final ApplicationInfo appInfo;
- final ComponentName name;
ProcessRecord proc; // if non-null, hosting process.
ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
String stringName;
+ String shortStringName;
public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info,
ApplicationInfo ai, ComponentName _name) {
- super(_info);
service = _service;
+ info = _info;
uid = ai.uid;
appInfo = ai;
name = _name;
@@ -56,12 +64,20 @@ class ContentProviderRecord extends ContentProviderHolder {
}
public ContentProviderRecord(ContentProviderRecord cpr) {
- super(cpr.info);
+ service = cpr.service;
+ info = cpr.info;
uid = cpr.uid;
appInfo = cpr.appInfo;
name = cpr.name;
noReleaseNeeded = cpr.noReleaseNeeded;
- service = cpr.service;
+ }
+
+ public ContentProviderHolder newHolder(ContentProviderConnection conn) {
+ ContentProviderHolder holder = new ContentProviderHolder(info);
+ holder.provider = provider;
+ holder.noReleaseNeeded = noReleaseNeeded;
+ holder.connection = conn;
+ return holder;
}
public boolean canRunHere(ProcessRecord app) {
@@ -120,30 +136,51 @@ class ContentProviderRecord extends ContentProviderHolder {
return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0);
}
- void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.print("package=");
- pw.print(info.applicationInfo.packageName);
- pw.print(" process="); pw.println(info.processName);
+ void dump(PrintWriter pw, String prefix, boolean full) {
+ if (full) {
+ pw.print(prefix); pw.print("package=");
+ pw.print(info.applicationInfo.packageName);
+ pw.print(" process="); pw.println(info.processName);
+ }
pw.print(prefix); pw.print("proc="); pw.println(proc);
if (launchingApp != null) {
pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp);
}
- pw.print(prefix); pw.print("uid="); pw.print(uid);
- pw.print(" provider="); pw.println(provider);
- pw.print(prefix); pw.print("name="); pw.println(info.authority);
- if (info.isSyncable || info.multiprocess || info.initOrder != 0) {
- pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable);
- pw.print("multiprocess="); pw.print(info.multiprocess);
- pw.print(" initOrder="); pw.println(info.initOrder);
+ if (full) {
+ pw.print(prefix); pw.print("uid="); pw.print(uid);
+ pw.print(" provider="); pw.println(provider);
}
- if (hasExternalProcessHandles()) {
- pw.print(prefix); pw.print("externals=");
- pw.println(externalProcessTokenToHandle.size());
+ pw.print(prefix); pw.print("authority="); pw.println(info.authority);
+ if (full) {
+ if (info.isSyncable || info.multiprocess || info.initOrder != 0) {
+ pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable);
+ pw.print(" multiprocess="); pw.print(info.multiprocess);
+ pw.print(" initOrder="); pw.println(info.initOrder);
+ }
}
- if (clients.size() > 0) {
- pw.print(prefix); pw.println("Clients:");
- for (ProcessRecord cproc : clients) {
- pw.print(prefix); pw.print(" - "); pw.println(cproc.toShortString());
+ if (full) {
+ if (hasExternalProcessHandles()) {
+ pw.print(prefix); pw.print("externals=");
+ pw.println(externalProcessTokenToHandle.size());
+ }
+ } else {
+ if (connections.size() > 0 || externalProcessNoHandleCount > 0) {
+ pw.print(prefix); pw.print(connections.size());
+ pw.print(" connections, "); pw.print(externalProcessNoHandleCount);
+ pw.println(" external handles");
+ }
+ }
+ if (connections.size() > 0) {
+ if (full) {
+ pw.print(prefix); pw.println("Connections:");
+ }
+ for (int i=0; i<connections.size(); i++) {
+ ContentProviderConnection conn = connections.get(i);
+ pw.print(prefix); pw.print(" -> "); pw.println(conn.toClientString());
+ if (conn.provider != this) {
+ pw.print(prefix); pw.print(" *** WRONG PROVIDER: ");
+ pw.println(conn.provider);
+ }
}
}
}
@@ -162,6 +199,17 @@ class ContentProviderRecord extends ContentProviderHolder {
return stringName = sb.toString();
}
+ public String toShortString() {
+ if (shortStringName != null) {
+ return shortStringName;
+ }
+ StringBuilder sb = new StringBuilder(128);
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append('/');
+ sb.append(name.flattenToShortString());
+ return shortStringName = sb.toString();
+ }
+
// This class represents a handle from an external process to a provider.
private class ExternalProcessHandle implements DeathRecipient {
private static final String LOG_TAG = "ExternalProcessHanldle";
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 4529ecc..8a3ba7f 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -125,8 +125,8 @@ class ProcessRecord {
final HashMap<String, ContentProviderRecord> pubProviders
= new HashMap<String, ContentProviderRecord>();
// All ContentProviderRecord process is using
- final HashMap<ContentProviderRecord, Integer> conProviders
- = new HashMap<ContentProviderRecord, Integer>();
+ final ArrayList<ContentProviderConnection> conProviders
+ = new ArrayList<ContentProviderConnection>();
boolean persistent; // always keep this application running?
boolean crashing; // are we in the process of crashing?
@@ -257,25 +257,47 @@ class ProcessRecord {
pw.println();
}
if (activities.size() > 0) {
- pw.print(prefix); pw.print("activities="); pw.println(activities);
+ pw.print(prefix); pw.println("Activities:");
+ for (int i=0; i<activities.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(activities.get(i));
+ }
}
if (services.size() > 0) {
- pw.print(prefix); pw.print("services="); pw.println(services);
+ pw.print(prefix); pw.println("Services:");
+ for (ServiceRecord sr : services) {
+ pw.print(prefix); pw.print(" - "); pw.println(sr);
+ }
}
if (executingServices.size() > 0) {
- pw.print(prefix); pw.print("executingServices="); pw.println(executingServices);
+ pw.print(prefix); pw.println("Executing Services:");
+ for (ServiceRecord sr : executingServices) {
+ pw.print(prefix); pw.print(" - "); pw.println(sr);
+ }
}
if (connections.size() > 0) {
- pw.print(prefix); pw.print("connections="); pw.println(connections);
+ pw.print(prefix); pw.println("Connections:");
+ for (ConnectionRecord cr : connections) {
+ pw.print(prefix); pw.print(" - "); pw.println(cr);
+ }
}
if (pubProviders.size() > 0) {
- pw.print(prefix); pw.print("pubProviders="); pw.println(pubProviders);
+ pw.print(prefix); pw.println("Published Providers:");
+ for (HashMap.Entry<String, ContentProviderRecord> ent : pubProviders.entrySet()) {
+ pw.print(prefix); pw.print(" - "); pw.println(ent.getKey());
+ pw.print(prefix); pw.print(" -> "); pw.println(ent.getValue());
+ }
}
if (conProviders.size() > 0) {
- pw.print(prefix); pw.print("conProviders="); pw.println(conProviders);
+ pw.print(prefix); pw.println("Connected Providers:");
+ for (int i=0; i<conProviders.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(conProviders.get(i).toShortString());
+ }
}
if (receivers.size() > 0) {
- pw.print(prefix); pw.print("receivers="); pw.println(receivers);
+ pw.print(prefix); pw.println("Receivers:");
+ for (ReceiverList rl : receivers) {
+ pw.print(prefix); pw.print(" - "); pw.println(rl);
+ }
}
}
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index ccc928f..d148ec3 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -177,27 +177,9 @@ public class ProviderMap {
while (it.hasNext()) {
Map.Entry<ComponentName, ContentProviderRecord> e = it.next();
ContentProviderRecord r = e.getValue();
- if (dumpAll) {
- pw.print(" * ");
- pw.println(r);
- r.dump(pw, " ");
- } else {
- pw.print(" * ");
- pw.println(r);
- if (r.proc != null) {
- pw.print(" proc=");
- pw.println(r.proc);
- }
- if (r.launchingApp != null) {
- pw.print(" launchingApp=");
- pw.println(r.launchingApp);
- }
- if (r.clients.size() > 0 || r.externalProcessNoHandleCount > 0) {
- pw.print(" "); pw.print(r.clients.size());
- pw.print(" clients, "); pw.print(r.externalProcessNoHandleCount);
- pw.println(" external handles");
- }
- }
+ pw.print(" * ");
+ pw.println(r);
+ r.dump(pw, " ", dumpAll);
}
}
@@ -210,7 +192,7 @@ public class ProviderMap {
pw.print(" ");
pw.print(e.getKey());
pw.print(": ");
- pw.println(r);
+ pw.println(r.toShortString());
}
}
@@ -221,10 +203,10 @@ public class ProviderMap {
pw.println(" ");
pw.println(" Published content providers (by class):");
dumpProvidersByClassLocked(pw, dumpAll, mGlobalByClass);
- pw.println("");
}
if (mProvidersByClassPerUser.size() > 1) {
+ pw.println("");
for (int i = 0; i < mProvidersByClassPerUser.size(); i++) {
HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(i);
pw.println(" User " + mProvidersByClassPerUser.keyAt(i) + ":");
@@ -321,7 +303,7 @@ public class ProviderMap {
if (r.proc != null) pw.println(r.proc.pid);
else pw.println("(not running)");
if (dumpAll) {
- r.dump(pw, innerPrefix);
+ r.dump(pw, innerPrefix, true);
}
}
if (r.proc != null && r.proc.thread != null) {