summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Roos <roosa@google.com>2014-07-24 16:00:46 +0200
committerAdrian Roos <roosa@google.com>2014-07-24 21:44:02 +0200
commitc5f95cea2639b698594a85acbde6a5519941d7b1 (patch)
treefa123927e9bbc021bf1ac0b39733d826dd675546
parent866cf65cc3c53f67836c9157d5c661adfdbd25e1 (diff)
downloadframeworks_base-c5f95cea2639b698594a85acbde6a5519941d7b1.zip
frameworks_base-c5f95cea2639b698594a85acbde6a5519941d7b1.tar.gz
frameworks_base-c5f95cea2639b698594a85acbde6a5519941d7b1.tar.bz2
Restart trust agents when updated or when they are dead
ActivityManager restarts the trust agent service for us when it gets killed automatically. This does not apply when its process crashes too often or when its package gets updated however. To catch the update case, the trust agent connection is removed as soon as the package disappears, and then readded when the new package appears. To catch the repeated crashing case, the connection is reset if it hasn't successfully connected for several minutes. Also adds a button to SampleTrustAgent to simulate a crash. Bug: 16137258 Change-Id: I1b18fc7a3025e23e25ca1623b6af658d5430a94b
-rw-r--r--packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml4
-rw-r--r--packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml10
-rw-r--r--packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java3
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java51
-rw-r--r--services/core/java/com/android/server/trust/TrustArchive.java2
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java68
6 files changed, 119 insertions, 19 deletions
diff --git a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
index f3125f1..a7c9105 100644
--- a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
@@ -38,6 +38,10 @@
android:label="@string/app_name"
android:exported="true"
android:launchMode="singleInstance" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
</activity>
</application>
</manifest>
diff --git a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
index 01b107b..06a06bf 100644
--- a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
@@ -17,9 +17,9 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<Button android:id="@+id/enable_trust"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -28,6 +28,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Revoke trust" />
+ <Button android:id="@+id/crash"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Crash" />
<CheckBox android:id="@+id/report_unlock_attempts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
index 8e293fb..6b5f78b 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
@@ -37,6 +37,7 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi
findViewById(R.id.enable_trust).setOnClickListener(this);
findViewById(R.id.revoke_trust).setOnClickListener(this);
+ findViewById(R.id.crash).setOnClickListener(this);
mReportUnlockAttempts = (CheckBox) findViewById(R.id.report_unlock_attempts);
mReportUnlockAttempts.setOnCheckedChangeListener(this);
@@ -56,6 +57,8 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi
null /* extra */);
} else if (id == R.id.revoke_trust) {
SampleTrustAgent.sendRevokeTrust(this);
+ } else if (id == R.id.crash) {
+ throw new RuntimeException("crash");
}
}
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index f18939f..51009af 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -24,6 +24,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
@@ -41,6 +42,13 @@ public class TrustAgentWrapper {
private static final int MSG_GRANT_TRUST = 1;
private static final int MSG_REVOKE_TRUST = 2;
private static final int MSG_TRUST_TIMEOUT = 3;
+ private static final int MSG_RESTART_TIMEOUT = 4;
+
+ /**
+ * Time in uptime millis that we wait for the service connection, both when starting
+ * and when the service disconnects.
+ */
+ private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000;
/**
* Long extra for {@link #MSG_GRANT_TRUST}
@@ -53,6 +61,8 @@ public class TrustAgentWrapper {
private final ComponentName mName;
private ITrustAgentService mTrustAgentService;
+ private boolean mBound;
+ private long mScheduledRestartUptimeMillis;
// Trust state
private boolean mTrusted;
@@ -95,6 +105,10 @@ public class TrustAgentWrapper {
}
mTrustManagerService.updateTrust(mUserId);
break;
+ case MSG_RESTART_TIMEOUT:
+ unbind();
+ mTrustManagerService.resetAgent(mName, mUserId);
+ break;
}
}
};
@@ -123,6 +137,7 @@ public class TrustAgentWrapper {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
+ mHandler.removeMessages(MSG_RESTART_TIMEOUT);
mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
setCallback(mCallback);
@@ -134,6 +149,9 @@ public class TrustAgentWrapper {
mTrustAgentService = null;
mTrustManagerService.mArchive.logAgentDied(mUserId, name);
mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
+ if (mBound) {
+ scheduleRestart();
+ }
}
};
@@ -144,9 +162,12 @@ public class TrustAgentWrapper {
mTrustManagerService = trustManagerService;
mUserId = user.getIdentifier();
mName = intent.getComponent();
- if (!context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user)) {
- if (DEBUG) Log.v(TAG, "can't bind to TrustAgent " + mName.flattenToShortString());
- // TODO: retry somehow?
+ // Schedules a restart for when connecting times out. If the connection succeeds,
+ // the restart is canceled in mCallback's onConnected.
+ scheduleRestart();
+ mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user);
+ if (!mBound) {
+ Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
}
}
@@ -184,14 +205,38 @@ public class TrustAgentWrapper {
}
public void unbind() {
+ if (!mBound) {
+ return;
+ }
if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
mContext.unbindService(mConnection);
+ mBound = false;
mTrustAgentService = null;
mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
+ mHandler.removeMessages(MSG_RESTART_TIMEOUT);
}
public boolean isConnected() {
return mTrustAgentService != null;
}
+
+ public boolean isBound() {
+ return mBound;
+ }
+
+ /**
+ * If not connected, returns the time at which the agent is restarted.
+ *
+ * @return restart time in uptime millis.
+ */
+ public long getScheduledRestartUptimeMillis() {
+ return mScheduledRestartUptimeMillis;
+ }
+
+ private void scheduleRestart() {
+ mHandler.removeMessages(MSG_RESTART_TIMEOUT);
+ mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
+ mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
+ }
}
diff --git a/services/core/java/com/android/server/trust/TrustArchive.java b/services/core/java/com/android/server/trust/TrustArchive.java
index 56950d2..5e32d86 100644
--- a/services/core/java/com/android/server/trust/TrustArchive.java
+++ b/services/core/java/com/android/server/trust/TrustArchive.java
@@ -130,7 +130,7 @@ public class TrustArchive {
}
}
- private static String formatDuration(long duration) {
+ public static String formatDuration(long duration) {
StringBuilder sb = new StringBuilder();
TimeUtils.formatDuration(duration, sb);
return sb.toString();
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 1aec569..6f72b94 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -45,6 +45,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.trust.TrustAgentService;
@@ -99,12 +100,6 @@ public class TrustManagerService extends SystemService {
private UserManager mUserManager;
- /**
- * Cache for {@link #refreshAgentList()}
- */
- private final ArraySet<AgentInfo> mObsoleteAgents = new ArraySet<AgentInfo>();
-
-
public TrustManagerService(Context context) {
super(context);
mContext = context;
@@ -168,8 +163,8 @@ public class TrustManagerService extends SystemService {
List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
- mObsoleteAgents.clear();
- mObsoleteAgents.addAll(mActiveAgents);
+ ArraySet<AgentInfo> obsoleteAgents = new ArraySet<>();
+ obsoleteAgents.addAll(mActiveAgents);
for (UserInfo userInfo : userInfos) {
int disabledFeatures = lockPatternUtils.getDevicePolicyManager()
@@ -208,14 +203,14 @@ public class TrustManagerService extends SystemService {
new Intent().setComponent(name), userInfo.getUserHandle());
mActiveAgents.add(agentInfo);
} else {
- mObsoleteAgents.remove(agentInfo);
+ obsoleteAgents.remove(agentInfo);
}
}
}
boolean trustMayHaveChanged = false;
- for (int i = 0; i < mObsoleteAgents.size(); i++) {
- AgentInfo info = mObsoleteAgents.valueAt(i);
+ for (int i = 0; i < obsoleteAgents.size(); i++) {
+ AgentInfo info = obsoleteAgents.valueAt(i);
if (info.agent.isTrusted()) {
trustMayHaveChanged = true;
}
@@ -228,6 +223,43 @@ public class TrustManagerService extends SystemService {
}
}
+ private void removeAgentsOfPackage(String packageName) {
+ boolean trustMayHaveChanged = false;
+ for (int i = mActiveAgents.size() - 1; i >= 0; i--) {
+ AgentInfo info = mActiveAgents.valueAt(i);
+ if (packageName.equals(info.component.getPackageName())) {
+ Log.i(TAG, "Resetting agent " + info.component.flattenToShortString());
+ if (info.agent.isTrusted()) {
+ trustMayHaveChanged = true;
+ }
+ info.agent.unbind();
+ mActiveAgents.removeAt(i);
+ }
+ }
+ if (trustMayHaveChanged) {
+ updateTrustAll();
+ }
+ }
+
+ public void resetAgent(ComponentName name, int userId) {
+ boolean trustMayHaveChanged = false;
+ for (int i = mActiveAgents.size() - 1; i >= 0; i--) {
+ AgentInfo info = mActiveAgents.valueAt(i);
+ if (name.equals(info.component) && userId == info.userId) {
+ Log.i(TAG, "Resetting agent " + info.component.flattenToShortString());
+ if (info.agent.isTrusted()) {
+ trustMayHaveChanged = true;
+ }
+ info.agent.unbind();
+ mActiveAgents.removeAt(i);
+ }
+ }
+ if (trustMayHaveChanged) {
+ updateTrust(userId);
+ }
+ refreshAgentList();
+ }
+
private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
if (resolveInfo == null || resolveInfo.serviceInfo == null
|| resolveInfo.serviceInfo.metaData == null) return null;
@@ -448,11 +480,18 @@ public class TrustManagerService extends SystemService {
if (info.userId != user.id) { continue; }
boolean trusted = info.agent.isTrusted();
fout.print(" "); fout.println(info.component.flattenToShortString());
- fout.print(" connected=" + dumpBool(info.agent.isConnected()));
+ fout.print(" bound=" + dumpBool(info.agent.isBound()));
+ fout.print(", connected=" + dumpBool(info.agent.isConnected()));
fout.println(", trusted=" + dumpBool(trusted));
if (trusted) {
fout.println(" message=\"" + info.agent.getMessage() + "\"");
}
+ if (!info.agent.isConnected()) {
+ String restartTime = TrustArchive.formatDuration(
+ info.agent.getScheduledRestartUptimeMillis()
+ - SystemClock.uptimeMillis());
+ fout.println(" restartScheduledAt=" + restartTime);
+ }
if (!simpleNames.add(TrustArchive.getSimpleName(info.component))) {
duplicateSimpleNames = true;
}
@@ -501,6 +540,11 @@ public class TrustManagerService extends SystemService {
// We're interested in all changes, even if just some components get enabled / disabled.
return true;
}
+
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ removeAgentsOfPackage(packageName);
+ }
};
private class DevicePolicyReceiver extends BroadcastReceiver {