Loading core/java/com/android/internal/backup/IBackupTransport.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,12 @@ import android.os.ParcelFileDescriptor; /** {@hide} */ interface IBackupTransport { /** * Ask the transport for the name under which it should be registered. This will * typically be its host service's component name, but need not be. */ String name(); /** * Ask the transport for an Intent that can be used to launch any internal * configuration Activity that it wishes to present. For example, the transport Loading core/java/com/android/internal/backup/LocalTransport.java +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.backup; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.RestoreSet; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; Loading Loading @@ -71,6 +72,10 @@ public class LocalTransport extends IBackupTransport.Stub { } } public String name() { return new ComponentName(mContext, this.getClass()).flattenToShortString(); } public Intent configurationIntent() { // The local transport is not user-configurable return null; Loading core/java/com/android/internal/backup/LocalTransportService.java 0 → 100644 +37 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 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.internal.backup; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class LocalTransportService extends Service { private static LocalTransport sTransport = null; @Override public void onCreate() { if (sTransport == null) { sTransport = new LocalTransport(this); } } @Override public IBinder onBind(Intent intent) { return sTransport; } } core/res/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -2689,6 +2689,15 @@ <service android:name="android.hardware.location.GeofenceHardwareService" android:permission="android.permission.LOCATION_HARDWARE" android:exported="false" /> <service android:name="com.android.internal.backup.LocalTransportService" android:permission="android.permission.CONFIRM_FULL_BACKUP" android:exported="false"> <intent-filter> <action android:name="android.backup.TRANSPORT_HOST" /> </intent-filter> </service> </application> </manifest> services/java/com/android/server/BackupManagerService.java +65 −42 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.content.pm.PackageManager.NameNotFoundException; import android.database.ContentObserver; Loading Loading @@ -146,6 +148,7 @@ class BackupManagerService extends IBackupManager.Stub { static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup"; static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST"; // How often we perform a backup pass. Privileged external callers can // trigger an immediate pass. Loading Loading @@ -251,10 +254,13 @@ class BackupManagerService extends IBackupManager.Stub { volatile boolean mClearingData; // Transport bookkeeping final HashMap<String,String> mTransportNames = new HashMap<String,String>(); // component name -> registration name final HashMap<String,IBackupTransport> mTransports = new HashMap<String,IBackupTransport>(); = new HashMap<String,IBackupTransport>(); // registration name -> binder final ArrayList<TransportConnection> mTransportConnections = new ArrayList<TransportConnection>(); String mCurrentTransport; IBackupTransport mLocalTransport, mGoogleTransport; ActiveRestoreSession mActiveRestoreSession; // Watch the device provisioning operation during setup Loading Loading @@ -815,13 +821,7 @@ class BackupManagerService extends IBackupManager.Stub { } // Set up our transport options and initialize the default transport // TODO: Have transports register themselves somehow? // TODO: Don't create transports that we don't need to? mLocalTransport = new LocalTransport(context); // This is actually pretty cheap ComponentName localName = new ComponentName(context, LocalTransport.class); registerTransport(localName.flattenToShortString(), mLocalTransport); mGoogleTransport = null; mCurrentTransport = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT); if ("".equals(mCurrentTransport)) { Loading @@ -829,28 +829,43 @@ class BackupManagerService extends IBackupManager.Stub { } if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport); // Attach to the Google backup transport. When this comes up, it will set // itself as the current transport because we explicitly reset mCurrentTransport // to null. ComponentName transportComponent = new ComponentName("com.google.android.backup", "com.google.android.backup.BackupTransportService"); // Find transport hosts and bind to their services Intent transportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST); List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser( transportServiceIntent, 0, UserHandle.USER_OWNER); if (DEBUG) { Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size())); } if (hosts != null) { if (MORE_DEBUG) { for (int i = 0; i < hosts.size(); i++) { ServiceInfo info = hosts.get(i).serviceInfo; Slog.v(TAG, " " + info.packageName + "/" + info.name); } } for (int i = 0; i < hosts.size(); i++) { try { // If there's something out there that is supposed to be the Google // backup transport, make sure it's legitimately part of the OS build // and not an app lying about its package name. ApplicationInfo info = mPackageManager.getApplicationInfo( transportComponent.getPackageName(), 0); if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { if (DEBUG) Slog.v(TAG, "Binding to Google transport"); Intent intent = new Intent().setComponent(transportComponent); context.bindServiceAsUser(intent, mGoogleConnection, Context.BIND_AUTO_CREATE, ServiceInfo info = hosts.get(i).serviceInfo; PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0); if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { ComponentName svcName = new ComponentName(info.packageName, info.name); if (DEBUG) { Slog.i(TAG, "Binding to transport host " + svcName); } Intent intent = new Intent(transportServiceIntent); intent.setComponent(svcName); TransportConnection connection = new TransportConnection(); mTransportConnections.add(connection); context.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE, UserHandle.OWNER); } else { Slog.w(TAG, "Possible Google transport spoof: ignoring " + info); Slog.w(TAG, "Transport package not privileged: " + info.packageName); } } catch (Exception e) { Slog.e(TAG, "Problem resolving transport service: " + e.getMessage()); } } } catch (PackageManager.NameNotFoundException nnf) { // No such package? No binding. if (DEBUG) Slog.v(TAG, "Google transport not present"); } // Now that we know about valid backup participants, parse any Loading Loading @@ -1298,13 +1313,16 @@ class BackupManagerService extends IBackupManager.Stub { // Add a transport to our set of available backends. If 'transport' is null, this // is an unregistration, and the transport's entry is removed from our bookkeeping. private void registerTransport(String name, IBackupTransport transport) { private void registerTransport(String name, String component, IBackupTransport transport) { synchronized (mTransports) { if (DEBUG) Slog.v(TAG, "Registering transport " + name + " = " + transport); if (DEBUG) Slog.v(TAG, "Registering transport " + component + "::" + name + " = " + transport); if (transport != null) { mTransports.put(name, transport); mTransportNames.put(component, name); } else { mTransports.remove(name); mTransports.remove(mTransportNames.get(component)); mTransportNames.remove(component); // Nothing further to do in the unregistration case return; } Loading Loading @@ -1390,18 +1408,23 @@ class BackupManagerService extends IBackupManager.Stub { } }; // ----- Track connection to GoogleBackupTransport service ----- ServiceConnection mGoogleConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) Slog.v(TAG, "Connected to Google transport"); mGoogleTransport = IBackupTransport.Stub.asInterface(service); registerTransport(name.flattenToShortString(), mGoogleTransport); // ----- Track connection to transports service ----- class TransportConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { if (DEBUG) Slog.v(TAG, "Connected to transport " + component); try { IBackupTransport transport = IBackupTransport.Stub.asInterface(service); registerTransport(transport.name(), component.flattenToShortString(), transport); } catch (RemoteException e) { Slog.e(TAG, "Unable to register transport " + component); } } public void onServiceDisconnected(ComponentName name) { if (DEBUG) Slog.v(TAG, "Disconnected from Google transport"); mGoogleTransport = null; registerTransport(name.flattenToShortString(), null); @Override public void onServiceDisconnected(ComponentName component) { if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component); registerTransport(null, component.flattenToShortString(), null); } }; Loading Loading
core/java/com/android/internal/backup/IBackupTransport.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,12 @@ import android.os.ParcelFileDescriptor; /** {@hide} */ interface IBackupTransport { /** * Ask the transport for the name under which it should be registered. This will * typically be its host service's component name, but need not be. */ String name(); /** * Ask the transport for an Intent that can be used to launch any internal * configuration Activity that it wishes to present. For example, the transport Loading
core/java/com/android/internal/backup/LocalTransport.java +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.backup; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.RestoreSet; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; Loading Loading @@ -71,6 +72,10 @@ public class LocalTransport extends IBackupTransport.Stub { } } public String name() { return new ComponentName(mContext, this.getClass()).flattenToShortString(); } public Intent configurationIntent() { // The local transport is not user-configurable return null; Loading
core/java/com/android/internal/backup/LocalTransportService.java 0 → 100644 +37 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 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.internal.backup; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class LocalTransportService extends Service { private static LocalTransport sTransport = null; @Override public void onCreate() { if (sTransport == null) { sTransport = new LocalTransport(this); } } @Override public IBinder onBind(Intent intent) { return sTransport; } }
core/res/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -2689,6 +2689,15 @@ <service android:name="android.hardware.location.GeofenceHardwareService" android:permission="android.permission.LOCATION_HARDWARE" android:exported="false" /> <service android:name="com.android.internal.backup.LocalTransportService" android:permission="android.permission.CONFIRM_FULL_BACKUP" android:exported="false"> <intent-filter> <action android:name="android.backup.TRANSPORT_HOST" /> </intent-filter> </service> </application> </manifest>
services/java/com/android/server/BackupManagerService.java +65 −42 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.content.pm.PackageManager.NameNotFoundException; import android.database.ContentObserver; Loading Loading @@ -146,6 +148,7 @@ class BackupManagerService extends IBackupManager.Stub { static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup"; static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST"; // How often we perform a backup pass. Privileged external callers can // trigger an immediate pass. Loading Loading @@ -251,10 +254,13 @@ class BackupManagerService extends IBackupManager.Stub { volatile boolean mClearingData; // Transport bookkeeping final HashMap<String,String> mTransportNames = new HashMap<String,String>(); // component name -> registration name final HashMap<String,IBackupTransport> mTransports = new HashMap<String,IBackupTransport>(); = new HashMap<String,IBackupTransport>(); // registration name -> binder final ArrayList<TransportConnection> mTransportConnections = new ArrayList<TransportConnection>(); String mCurrentTransport; IBackupTransport mLocalTransport, mGoogleTransport; ActiveRestoreSession mActiveRestoreSession; // Watch the device provisioning operation during setup Loading Loading @@ -815,13 +821,7 @@ class BackupManagerService extends IBackupManager.Stub { } // Set up our transport options and initialize the default transport // TODO: Have transports register themselves somehow? // TODO: Don't create transports that we don't need to? mLocalTransport = new LocalTransport(context); // This is actually pretty cheap ComponentName localName = new ComponentName(context, LocalTransport.class); registerTransport(localName.flattenToShortString(), mLocalTransport); mGoogleTransport = null; mCurrentTransport = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT); if ("".equals(mCurrentTransport)) { Loading @@ -829,28 +829,43 @@ class BackupManagerService extends IBackupManager.Stub { } if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport); // Attach to the Google backup transport. When this comes up, it will set // itself as the current transport because we explicitly reset mCurrentTransport // to null. ComponentName transportComponent = new ComponentName("com.google.android.backup", "com.google.android.backup.BackupTransportService"); // Find transport hosts and bind to their services Intent transportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST); List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser( transportServiceIntent, 0, UserHandle.USER_OWNER); if (DEBUG) { Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size())); } if (hosts != null) { if (MORE_DEBUG) { for (int i = 0; i < hosts.size(); i++) { ServiceInfo info = hosts.get(i).serviceInfo; Slog.v(TAG, " " + info.packageName + "/" + info.name); } } for (int i = 0; i < hosts.size(); i++) { try { // If there's something out there that is supposed to be the Google // backup transport, make sure it's legitimately part of the OS build // and not an app lying about its package name. ApplicationInfo info = mPackageManager.getApplicationInfo( transportComponent.getPackageName(), 0); if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { if (DEBUG) Slog.v(TAG, "Binding to Google transport"); Intent intent = new Intent().setComponent(transportComponent); context.bindServiceAsUser(intent, mGoogleConnection, Context.BIND_AUTO_CREATE, ServiceInfo info = hosts.get(i).serviceInfo; PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0); if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { ComponentName svcName = new ComponentName(info.packageName, info.name); if (DEBUG) { Slog.i(TAG, "Binding to transport host " + svcName); } Intent intent = new Intent(transportServiceIntent); intent.setComponent(svcName); TransportConnection connection = new TransportConnection(); mTransportConnections.add(connection); context.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE, UserHandle.OWNER); } else { Slog.w(TAG, "Possible Google transport spoof: ignoring " + info); Slog.w(TAG, "Transport package not privileged: " + info.packageName); } } catch (Exception e) { Slog.e(TAG, "Problem resolving transport service: " + e.getMessage()); } } } catch (PackageManager.NameNotFoundException nnf) { // No such package? No binding. if (DEBUG) Slog.v(TAG, "Google transport not present"); } // Now that we know about valid backup participants, parse any Loading Loading @@ -1298,13 +1313,16 @@ class BackupManagerService extends IBackupManager.Stub { // Add a transport to our set of available backends. If 'transport' is null, this // is an unregistration, and the transport's entry is removed from our bookkeeping. private void registerTransport(String name, IBackupTransport transport) { private void registerTransport(String name, String component, IBackupTransport transport) { synchronized (mTransports) { if (DEBUG) Slog.v(TAG, "Registering transport " + name + " = " + transport); if (DEBUG) Slog.v(TAG, "Registering transport " + component + "::" + name + " = " + transport); if (transport != null) { mTransports.put(name, transport); mTransportNames.put(component, name); } else { mTransports.remove(name); mTransports.remove(mTransportNames.get(component)); mTransportNames.remove(component); // Nothing further to do in the unregistration case return; } Loading Loading @@ -1390,18 +1408,23 @@ class BackupManagerService extends IBackupManager.Stub { } }; // ----- Track connection to GoogleBackupTransport service ----- ServiceConnection mGoogleConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) Slog.v(TAG, "Connected to Google transport"); mGoogleTransport = IBackupTransport.Stub.asInterface(service); registerTransport(name.flattenToShortString(), mGoogleTransport); // ----- Track connection to transports service ----- class TransportConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { if (DEBUG) Slog.v(TAG, "Connected to transport " + component); try { IBackupTransport transport = IBackupTransport.Stub.asInterface(service); registerTransport(transport.name(), component.flattenToShortString(), transport); } catch (RemoteException e) { Slog.e(TAG, "Unable to register transport " + component); } } public void onServiceDisconnected(ComponentName name) { if (DEBUG) Slog.v(TAG, "Disconnected from Google transport"); mGoogleTransport = null; registerTransport(name.flattenToShortString(), null); @Override public void onServiceDisconnected(ComponentName component) { if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component); registerTransport(null, component.flattenToShortString(), null); } }; Loading