summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityManagerNative.java9
-rw-r--r--core/java/android/app/ActivityThread.java20
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/service/dreams/DreamService.java65
-rwxr-xr-xcore/res/res/values/config.xml9
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--docs/html/guide/topics/ui/dialogs.jd61
-rw-r--r--packages/FusedLocation/AndroidManifest.xml5
-rw-r--r--services/java/com/android/server/BackupManagerService.java3
-rw-r--r--services/java/com/android/server/LocationManagerService.java84
-rw-r--r--services/java/com/android/server/ServiceWatcher.java51
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java61
12 files changed, 261 insertions, 110 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7492629..67d3930 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2809,6 +2809,15 @@ class ActivityManagerProxy implements IActivityManager
return success;
}
+ public void clearPendingBackup() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(CLEAR_PENDING_BACKUP_TRANSACTION, data, reply, 0);
+ reply.recycle();
+ data.recycle();
+ }
+
public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5f65f08..456d757 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -29,6 +29,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ProviderInfo;
@@ -2396,12 +2397,31 @@ public final class ActivityThread {
private void handleCreateBackupAgent(CreateBackupAgentData data) {
if (DEBUG_BACKUP) Slog.v(TAG, "handleCreateBackupAgent: " + data);
+ // Sanity check the requested target package's uid against ours
+ try {
+ PackageInfo requestedPackage = getPackageManager().getPackageInfo(
+ data.appInfo.packageName, 0, UserHandle.myUserId());
+ if (requestedPackage.applicationInfo.uid != Process.myUid()) {
+ Slog.w(TAG, "Asked to instantiate non-matching package "
+ + data.appInfo.packageName);
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Can't reach package manager", e);
+ return;
+ }
+
// no longer idle; we have backup work to do
unscheduleGcIdler();
// instantiate the BackupAgent class named in the manifest
LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
String packageName = packageInfo.mPackageName;
+ if (packageName == null) {
+ Slog.d(TAG, "Asked to create backup agent for nonexistent package");
+ return;
+ }
+
if (mBackupAgents.get(packageName) != null) {
Slog.d(TAG, "BackupAgent " + " for " + packageName
+ " already exists");
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 97250e9..8fc1c86 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -152,6 +152,7 @@ public interface IActivityManager extends IInterface {
public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
throws RemoteException;
+ public void clearPendingBackup() throws RemoteException;
public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException;
public void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException;
public void killApplicationProcess(String processName, int uid) throws RemoteException;
@@ -619,4 +620,5 @@ public interface IActivityManager extends IInterface {
int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156;
int REQUEST_BUG_REPORT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+157;
int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158;
+ int CLEAR_PENDING_BACKUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+159;
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 4820c5e..6c9290b 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -51,12 +51,17 @@ import com.android.internal.policy.PolicyManager;
* an exhibition/lean-back experience.</p>
*
* <p>The Dream lifecycle is as follows:</p>
- * <ul>
- * <li>onAttachedToWindow</li>
- * <li>onDreamingStarted</li>
- * <li>onDreamingStopped</li>
- * <li>onDetachedFromWindow</li>
- * </ul>
+ * <ol>
+ * <li>{@link #onAttachedToWindow}
+ * <p>Use this for initial setup, such as calling {@link #setContentView setContentView()}.</li>
+ * <li>{@link #onDreamingStarted}
+ * <p>Your dream has started, so you should begin animations or other behaviors here.</li>
+ * <li>{@link #onDreamingStopped}
+ * <p>Use this to stop the things you started in {@link #onDreamingStarted}.</li>
+ * <li>{@link #onDetachedFromWindow}
+ * <p>Use this to dismantle resources your dream set up. For example, detach from handlers
+ * and listeners.</li>
+ * </ol>
*
* <p>In addition, onCreate and onDestroy (from the Service interface) will also be called, but
* initialization and teardown should be done by overriding the hooks above.</p>
@@ -80,14 +85,40 @@ import com.android.internal.policy.PolicyManager;
* android:resource="@xml/my_dream" />
* &lt;/service>
* </pre>
- * <p>If specified, additional information for the dream is defined using the
- * <code>&lt;{@link android.R.styleable#Dream dream}&gt;</code> element. For example:</p>
- * <pre>
- * (in res/xml/my_dream.xml)
*
+ * <p>If specified with the {@code &lt;meta-data&gt;} element,
+ * additional information for the dream is defined using the
+ * {@link android.R.styleable#Dream &lt;dream&gt;} element in a separate XML file.
+ * Currently, the only addtional
+ * information you can provide is for a settings activity that allows the user to configure
+ * the dream behavior. For example:</p>
+ * <p class="code-caption">res/xml/my_dream.xml</p>
+ * <pre>
* &lt;dream xmlns:android="http://schemas.android.com/apk/res/android"
* android:settingsActivity="com.example.app/.MyDreamSettingsActivity" />
* </pre>
+ * <p>This makes a Settings button available alongside your dream's listing in the
+ * system settings, which when pressed opens the specified activity.</p>
+ *
+ *
+ * <p>To specify your dream layout, call {@link #setContentView}, typically during the
+ * {@link #onAttachedToWindow} callback. For example:</p>
+ * <pre>
+ * public class MyDream extends DreamService {
+ *
+ * &#64;Override
+ * public void onAttachedToWindow() {
+ * super.onAttachedToWindow();
+ *
+ * // Exit dream upon user touch
+ * setInteractive(false);
+ * // Hide system UI
+ * setFullscreen(true);
+ * // Set the dream layout
+ * setContentView(R.layout.dream);
+ * }
+ * }
+ * </pre>
*/
public class DreamService extends Service implements Window.Callback {
private final String TAG = DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
@@ -323,11 +354,12 @@ public class DreamService extends Service implements Window.Callback {
/**
* Sets a view to be the content view for this Dream.
- * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)},
+ * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)} in an activity,
* including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
*
- * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
- * @param view The desired content to display.
+ * <p>Note: This requires a window, so you should usually call it during
+ * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
+ * during {@link #onCreate}).</p>
*
* @see #setContentView(int)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
@@ -339,9 +371,12 @@ public class DreamService extends Service implements Window.Callback {
/**
* Sets a view to be the content view for this Dream.
* Behaves similarly to
- * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}.
+ * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
+ * in an activity.
*
- * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
+ * <p>Note: This requires a window, so you should usually call it during
+ * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
+ * during {@link #onCreate}).</p>
*
* @param view The desired content to display.
* @param params Layout parameters for the view.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4698002..afd847f 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -636,19 +636,12 @@
of new location providers at run-time. The new package does not
have to be explicitly listed here, however it must have a signature
that matches the signature of at least one package on this list.
- Platforms should overlay additional packages in
- config_overlay_locationProviderPackageNames, instead of overlaying
- this config, if they only want to append packages and not replace
- the entire array.
-->
<string-array name="config_locationProviderPackageNames" translatable="false">
+ <!-- The standard AOSP fused location provider -->
<item>com.android.location.fused</item>
</string-array>
- <!-- Pacakge name(s) supplied by overlay, and appended to
- config_locationProviderPackageNames. -->
- <string-array name="config_overlay_locationProviderPackageNames" translatable="false" />
-
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
<bool name="config_bluetooth_sco_off_call">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b3af161..7c0547e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1475,7 +1475,6 @@
<java-symbol type="array" name="radioAttributes" />
<java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="array" name="config_locationProviderPackageNames" />
- <java-symbol type="array" name="config_overlay_locationProviderPackageNames" />
<java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_sf_limitedAlpha" />
diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
index 62c054a..3cfed13 100644
--- a/docs/html/guide/topics/ui/dialogs.jd
+++ b/docs/html/guide/topics/ui/dialogs.jd
@@ -119,7 +119,7 @@ onCreateDialog()} callback method.</p>
a {@link android.support.v4.app.DialogFragment}:</p>
<pre>
-public class FireMissilesDialog extends DialogFragment {
+public class FireMissilesDialogFragment extends DialogFragment {
&#64;Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
@@ -469,7 +469,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- NoticeDialog.this.getDialog().cancel();
+ LoginDialogFragment.this.getDialog().cancel();
}
});
return builder.create();
@@ -497,15 +497,15 @@ in the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
<p>When the user touches one of the dialog's action buttons or selects an item from its list,
your {@link android.support.v4.app.DialogFragment} might perform the necessary
action itself, but often you'll want to deliver the event to the activity or fragment that
-opened the dialog. To do this, define an interface with a method for each type of click event,
-then implement that interface in the host component that will
+opened the dialog. To do this, define an interface with a method for each type of click event.
+Then implement that interface in the host component that will
receive the action events from the dialog.</p>
<p>For example, here's a {@link android.support.v4.app.DialogFragment} that defines an
interface through which it delivers the events back to the host activity:</p>
<pre>
-public class NoticeDialog extends DialogFragment {
+public class NoticeDialogFragment extends DialogFragment {
/* The activity that creates an instance of this dialog fragment must
* implement this interface in order to receive event callbacks.
@@ -516,48 +516,44 @@ public class NoticeDialog extends DialogFragment {
}
// Use this instance of the interface to deliver action events
- static NoticeDialogListener mListener;
-
- /* Call this to instantiate a new NoticeDialog.
- * @param activity The activity hosting the dialog, which must implement the
- * NoticeDialogListener to receive event callbacks.
- * @returns A new instance of NoticeDialog.
- * @throws ClassCastException if the host activity does not
- * implement NoticeDialogListener
- */
- public static NoticeDialog newInstance(Activity activity) {
+ NoticeDialogListener mListener;
+
+ // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
+ &#64;Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
// Verify that the host activity implements the callback interface
try {
- // Instantiate the NoticeDialogListener so we can send events with it
+ // Instantiate the NoticeDialogListener so we can send events to the host
mListener = (NoticeDialogListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement NoticeDialogListener");
}
- NoticeDialog frag = new NoticeDialog();
- return frag;
}
-
...
}
</pre>
-<p>The activity hosting the dialog creates and shows an instance of the dialog
-by calling {@code NoticeDialog.newInstance()} and receives the dialog's
+<p>The activity hosting the dialog creates an instance of the dialog
+with the dialog fragment's constructor and receives the dialog's
events through an implementation of the {@code NoticeDialogListener} interface:</p>
<pre>
public class MainActivity extends FragmentActivity
- implements NoticeDialog.NoticeDialogListener{
+ implements NoticeDialogFragment.NoticeDialogListener{
...
public void showNoticeDialog() {
// Create an instance of the dialog fragment and show it
- DialogFragment dialog = NoticeDialog.newInstance(this);
- dialog.show(getSupportFragmentManager(), "NoticeDialog");
+ DialogFragment dialog = new NoticeDialogFragment();
+ dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
}
+ // The dialog fragment receives a reference to this Activity through the
+ // Fragment.onAttach() callback, which it uses to call the following methods
+ // defined by the NoticeDialogFragment.NoticeDialogListener interface
&#64;Override
public void onDialogPositiveClick(DialogFragment dialog) {
// User touched the dialog's positive button
@@ -573,11 +569,12 @@ public class MainActivity extends FragmentActivity
</pre>
<p>Because the host activity implements the {@code NoticeDialogListener}&mdash;which is
-enforced by the {@code newInstance()} method shown above&mdash;the dialog fragment can use the
+enforced by the {@link android.support.v4.app.Fragment#onAttach onAttach()}
+callback method shown above&mdash;the dialog fragment can use the
interface callback methods to deliver click events to the activity:</p>
<pre>
-public class NoticeDialog extends DialogFragment {
+public class NoticeDialogFragment extends DialogFragment {
...
&#64;Override
@@ -588,13 +585,13 @@ public class NoticeDialog extends DialogFragment {
.setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Send the positive button event back to the host activity
- mListener.onDialogPositiveClick(NoticeDialog.this);
+ mListener.onDialogPositiveClick(NoticeDialogFragment.this);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Send the negative button event back to the host activity
- mListener.onDialogPositiveClick(NoticeDialog.this);
+ mListener.onDialogPositiveClick(NoticeDialogFragment.this);
}
});
return builder.create();
@@ -604,8 +601,6 @@ public class NoticeDialog extends DialogFragment {
-
-
<h2 id="ShowingADialog">Showing a Dialog</h2>
<p>When you want to show your dialog, create an instance of your {@link
@@ -621,7 +616,7 @@ android.support.v4.app.Fragment}. For example:</p>
<pre>
public void confirmFireMissiles() {
- DialogFragment newFragment = FireMissilesDialog.newInstance(this);
+ DialogFragment newFragment = new FireMissilesDialogFragment();
newFragment.show(getSupportFragmentManager(), "missiles");
}
</pre>
@@ -653,7 +648,7 @@ onCreateView()} callback.</p>
dialog or an embeddable fragment (using a layout named <code>purchase_items.xml</code>):</p>
<pre>
-public class CustomLayoutDialog extends DialogFragment {
+public class CustomDialogFragment extends DialogFragment {
/** The system calls this to get the DialogFragment's layout, regardless
of whether it's being displayed as a dialog or an embedded fragment. */
&#64;Override
@@ -683,7 +678,7 @@ or a fullscreen UI, based on the screen size:</p>
<pre>
public void showDialog() {
FragmentManager fragmentManager = getSupportFragmentManager();
- CustomLayoutDialog newFragment = new CustomLayoutDialog();
+ CustomDialogFragment newFragment = new CustomDialogFragment();
if (mIsLargeLayout) {
// The device is using a large layout, so show the fragment as a dialog
diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml
index 4c57401..10b9064 100644
--- a/packages/FusedLocation/AndroidManifest.xml
+++ b/packages/FusedLocation/AndroidManifest.xml
@@ -18,7 +18,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.location.fused"
- coreApp="true">
+ coreApp="true"
+ android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -39,7 +40,7 @@
<intent-filter>
<action android:name="com.android.location.service.FusedLocationProvider" />
</intent-filter>
- <meta-data android:name="version" android:value="1" />
+ <meta-data android:name="serviceVersion" android:value="0" />
</service>
</application>
</manifest>
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 9f01eca..f241c80 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1474,6 +1474,7 @@ class BackupManagerService extends IBackupManager.Stub {
if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName);
removeEverBackedUp(packageName);
set.remove(packageName);
+ mPendingBackups.remove(packageName);
}
}
@@ -1625,6 +1626,7 @@ class BackupManagerService extends IBackupManager.Stub {
} catch (InterruptedException e) {
// just bail
if (DEBUG) Slog.w(TAG, "Interrupted: " + e);
+ mActivityManager.clearPendingBackup();
return null;
}
}
@@ -1632,6 +1634,7 @@ class BackupManagerService extends IBackupManager.Stub {
// if we timed out with no connect, abort and move on
if (mConnecting == true) {
Slog.w(TAG, "Timeout waiting for agent " + app);
+ mActivityManager.clearPendingBackup();
return null;
}
if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 468f696..37dee19 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -23,8 +23,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.location.Address;
@@ -249,6 +252,74 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
updateProvidersLocked();
}
+ private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
+ PackageManager pm = mContext.getPackageManager();
+ String systemPackageName = mContext.getPackageName();
+ ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
+
+ List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
+ new Intent(FUSED_LOCATION_SERVICE_ACTION),
+ PackageManager.GET_META_DATA, mCurrentUserId);
+ for (ResolveInfo rInfo : rInfos) {
+ String packageName = rInfo.serviceInfo.packageName;
+
+ // Check that the signature is in the list of supported sigs. If it's not in
+ // this list the standard provider binding logic won't bind to it.
+ try {
+ PackageInfo pInfo;
+ pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
+ Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
+ ", but has wrong signature, ignoring");
+ continue;
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "missing package: " + packageName);
+ continue;
+ }
+
+ // Get the version info
+ if (rInfo.serviceInfo.metaData == null) {
+ Log.w(TAG, "Found fused provider without metadata: " + packageName);
+ continue;
+ }
+
+ int version = rInfo.serviceInfo.metaData.getInt(
+ ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
+ if (version == 0) {
+ // This should be the fallback fused location provider.
+
+ // Make sure it's in the system partition.
+ if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
+ continue;
+ }
+
+ // Check that the fallback is signed the same as the OS
+ // as a proxy for coreApp="true"
+ if (pm.checkSignatures(systemPackageName, packageName)
+ != PackageManager.SIGNATURE_MATCH) {
+ if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
+ + packageName);
+ continue;
+ }
+
+ // Found a valid fallback.
+ if (D) Log.d(TAG, "Found fallback provider: " + packageName);
+ return;
+ } else {
+ if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
+ }
+ }
+
+ throw new IllegalStateException("Unable to find a fused location provider that is in the "
+ + "system partition with version 0 and signed with the platform certificate. "
+ + "Such a package is needed to provide a default fused location provider in the "
+ + "event that no other fused location provider has been installed or is currently "
+ + "available. For example, coreOnly boot mode when decrypting the data "
+ + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
+ }
+
private void loadProvidersLocked() {
// create a passive location provider, which is always enabled
PassiveProvider passiveProvider = new PassiveProvider(this);
@@ -278,14 +349,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
*/
Resources resources = mContext.getResources();
ArrayList<String> providerPackageNames = new ArrayList<String>();
- String[] pkgs1 = resources.getStringArray(
+ String[] pkgs = resources.getStringArray(
com.android.internal.R.array.config_locationProviderPackageNames);
- String[] pkgs2 = resources.getStringArray(
- com.android.internal.R.array.config_overlay_locationProviderPackageNames);
- if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
- if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
- if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
- if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
+ if (D) Log.d(TAG, "certificates for location providers pulled from: " +
+ Arrays.toString(pkgs));
+ if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
+
+ ensureFallbackFusedProviderPresentLocked(providerPackageNames);
// bind to network provider
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/java/com/android/server/ServiceWatcher.java
index 5598b0a..2e7c6d1 100644
--- a/services/java/com/android/server/ServiceWatcher.java
+++ b/services/java/com/android/server/ServiceWatcher.java
@@ -43,7 +43,7 @@ import java.util.List;
*/
public class ServiceWatcher implements ServiceConnection {
private static final boolean D = false;
- private static final String EXTRA_VERSION = "version";
+ public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
private final String mTag;
private final Context mContext;
@@ -58,9 +58,27 @@ public class ServiceWatcher implements ServiceConnection {
// all fields below synchronized on mLock
private IBinder mBinder; // connected service
private String mPackageName; // current best package
- private int mVersion; // current best version
+ private int mVersion = Integer.MIN_VALUE; // current best version
private int mCurrentUserId;
+ public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
+ List<String> initialPackageNames) {
+ PackageManager pm = context.getPackageManager();
+ ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>();
+ for (int i = 0, size = initialPackageNames.size(); i < size; i++) {
+ String pkg = initialPackageNames.get(i);
+ try {
+ HashSet<Signature> set = new HashSet<Signature>();
+ Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
+ set.addAll(Arrays.asList(sigs));
+ sigSets.add(set);
+ } catch (NameNotFoundException e) {
+ Log.w("ServiceWatcher", pkg + " not found");
+ }
+ }
+ return sigSets;
+ }
+
public ServiceWatcher(Context context, String logTag, String action,
List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
mContext = context;
@@ -71,20 +89,7 @@ public class ServiceWatcher implements ServiceConnection {
mHandler = handler;
mCurrentUserId = userId;
- mSignatureSets = new ArrayList<HashSet<Signature>>();
- for (int i=0; i < initialPackageNames.size(); i++) {
- String pkg = initialPackageNames.get(i);
- HashSet<Signature> set = new HashSet<Signature>();
- try {
- Signature[] sigs =
- mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
- set.addAll(Arrays.asList(sigs));
- mSignatureSets.add(set);
- } catch (NameNotFoundException e) {
- Log.w(logTag, pkg + " not found");
- }
- }
-
+ mSignatureSets = getSignatureSets(context, initialPackageNames);
}
public boolean start() {
@@ -132,15 +137,16 @@ public class ServiceWatcher implements ServiceConnection {
// check version
int version = 0;
if (rInfo.serviceInfo.metaData != null) {
- version = rInfo.serviceInfo.metaData.getInt(EXTRA_VERSION, 0);
+ version = rInfo.serviceInfo.metaData.getInt(EXTRA_SERVICE_VERSION, 0);
}
+
if (version > mVersion) {
bestVersion = version;
bestPackage = packageName;
}
}
- if (D) Log.d(mTag, String.format("bindBestPackage %s found %d, %s",
+ if (D) Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
(justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "),
rInfos.size(),
(bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));
@@ -174,7 +180,8 @@ public class ServiceWatcher implements ServiceConnection {
| Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId);
}
- private boolean isSignatureMatch(Signature[] signatures) {
+ public static boolean isSignatureMatch(Signature[] signatures,
+ List<HashSet<Signature>> sigSets) {
if (signatures == null) return false;
// build hashset of input to test against
@@ -184,7 +191,7 @@ public class ServiceWatcher implements ServiceConnection {
}
// test input against each of the signature sets
- for (HashSet<Signature> referenceSet : mSignatureSets) {
+ for (HashSet<Signature> referenceSet : sigSets) {
if (referenceSet.equals(inputSet)) {
return true;
}
@@ -192,6 +199,10 @@ public class ServiceWatcher implements ServiceConnection {
return false;
}
+ private boolean isSignatureMatch(Signature[] signatures) {
+ return isSignatureMatch(signatures, mSignatureSets);
+ }
+
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
/**
* Called when package has been reinstalled
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7132e1e..1737876 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -11119,8 +11119,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// instantiated. The backup agent will invoke backupAgentCreated() on the
// activity manager to announce its creation.
public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
- if (DEBUG_BACKUP) Slog.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
- enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
+ if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + app + " mode=" + backupMode);
+ enforceCallingPermission("android.permission.BACKUP", "bindBackupAgent");
synchronized(this) {
// !!! TODO: currently no check here that we're already bound
@@ -11181,6 +11181,17 @@ public final class ActivityManagerService extends ActivityManagerNative
return true;
}
+ @Override
+ public void clearPendingBackup() {
+ if (DEBUG_BACKUP) Slog.v(TAG, "clearPendingBackup");
+ enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup");
+
+ synchronized (this) {
+ mBackupTarget = null;
+ mBackupAppName = null;
+ }
+ }
+
// A backup agent has just come up
public void backupAgentCreated(String agentPackageName, IBinder agent) {
if (DEBUG_BACKUP) Slog.v(TAG, "backupAgentCreated: " + agentPackageName
@@ -11217,32 +11228,34 @@ public final class ActivityManagerService extends ActivityManagerNative
}
synchronized(this) {
- if (mBackupAppName == null) {
- Slog.w(TAG, "Unbinding backup agent with no active backup");
- return;
- }
-
- if (!mBackupAppName.equals(appInfo.packageName)) {
- Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
- return;
- }
+ try {
+ if (mBackupAppName == null) {
+ Slog.w(TAG, "Unbinding backup agent with no active backup");
+ return;
+ }
- ProcessRecord proc = mBackupTarget.app;
- mBackupTarget = null;
- mBackupAppName = null;
+ if (!mBackupAppName.equals(appInfo.packageName)) {
+ Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
+ return;
+ }
- // Not backing this app up any more; reset its OOM adjustment
- updateOomAdjLocked(proc);
+ // Not backing this app up any more; reset its OOM adjustment
+ final ProcessRecord proc = mBackupTarget.app;
+ updateOomAdjLocked(proc);
- // If the app crashed during backup, 'thread' will be null here
- if (proc.thread != null) {
- try {
- proc.thread.scheduleDestroyBackupAgent(appInfo,
- compatibilityInfoForPackageLocked(appInfo));
- } catch (Exception e) {
- Slog.e(TAG, "Exception when unbinding backup agent:");
- e.printStackTrace();
+ // If the app crashed during backup, 'thread' will be null here
+ if (proc.thread != null) {
+ try {
+ proc.thread.scheduleDestroyBackupAgent(appInfo,
+ compatibilityInfoForPackageLocked(appInfo));
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception when unbinding backup agent:");
+ e.printStackTrace();
+ }
}
+ } finally {
+ mBackupTarget = null;
+ mBackupAppName = null;
}
}
}