Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52eba65f authored by nathch's avatar nathch
Browse files

Add BackupEncryptionService which provides an IntermediateEncryptingTransport

BackupEncryptionService (which is in a separate APK) provides a IntermediateTransport
which binds to the real transport.

We do this so that IntermediateEncryptingTransport can encrypt (decrypt) the
data when sending it (receiving it) from the real transport.
In this CL, IntermediateTransport does not do any encryption. It simply forwards
the data on. We will add the actual encryption in the next CL.

Bug: 139269919

Test: atest -v BackupEncryptionUnitTests
Test: atest -v RunBackupFrameworksServicesRoboTests
Test: atest -v $(find frameworks/base/services/tests/servicestests/src/com/android/server/backup -name '\''*Test.java'\'')'
Test: atest -v CtsBackupTestCases CtsBackupHostTestCases
Change-Id: I83a84ed3e638eb1dd165fffe406495f80ff930aa
parent efb5b79f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ android_app {
    name: "BackupEncryption",
    srcs: ["src/**/*.java"],
    libs: ["backup-encryption-protos"],
    static_libs: ["backuplib"],
    optimize: { enabled: false },
    platform_apis: true,
    certificate: "platform",
+10 −1
Original line number Diff line number Diff line
@@ -20,5 +20,14 @@
    package="com.android.server.backup.encryption"
    android:sharedUserId="android.uid.system" >

    <application android:allowBackup="false" />
    <application android:allowBackup="false" >
        <!-- This service does not need to be exported because it shares uid with the system server
        which is the only client. -->
        <service android:name=".BackupEncryptionService"
                 android:exported="false">
            <intent-filter>
                <action android:name="android.encryption.BACKUP_ENCRYPTION" />
            </intent-filter>
        </service>
    </application>
</manifest>
+63 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.backup.encryption;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.encryption.transport.IntermediateEncryptingTransport;
import com.android.server.backup.encryption.transport.IntermediateEncryptingTransportManager;

/**
 * This service provides encryption of backup data. For an intent used to bind to this service, it
 * provides an {@link IntermediateEncryptingTransport} which is an implementation of {@link
 * IBackupTransport} that encrypts (or decrypts) the data when sending it (or receiving it) from the
 * real {@link IBackupTransport}.
 */
public class BackupEncryptionService extends Service {
    public static final String TAG = "BackupEncryption";
    private static IntermediateEncryptingTransportManager sTransportManager = null;

    @Override
    public void onCreate() {
        Log.i(TAG, "onCreate:" + this);
        if (sTransportManager == null) {
            Log.i(TAG, "Creating IntermediateEncryptingTransportManager");
            sTransportManager = new IntermediateEncryptingTransportManager(this);
        }
    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "onDestroy:" + this);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO (b141536117): Check connection with TransportClient.connect and return null on fail.
        return sTransportManager.get(intent);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        sTransportManager.cleanup(intent);
        return false;
    }
}
+64 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.backup.encryption.transport;

import android.os.RemoteException;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.transport.DelegatingTransport;
import com.android.server.backup.transport.TransportClient;

/**
 * This is an implementation of {@link IBackupTransport} that encrypts (or decrypts) the data when
 * sending it (or receiving it) from the {@link IBackupTransport} returned by {@link
 * TransportClient.connect(String)}.
 */
public class IntermediateEncryptingTransport extends DelegatingTransport {
    private final TransportClient mTransportClient;
    private final Object mConnectLock = new Object();
    private volatile IBackupTransport mRealTransport;

    @VisibleForTesting
    IntermediateEncryptingTransport(TransportClient transportClient) {
        mTransportClient = transportClient;
    }

    @Override
    protected IBackupTransport getDelegate() throws RemoteException {
        if (mRealTransport == null) {
            connect();
        }
        return mRealTransport;
    }

    private void connect() throws RemoteException {
        synchronized (mConnectLock) {
            if (mRealTransport == null) {
                mRealTransport = mTransportClient.connect("IntermediateEncryptingTransport");
                if (mRealTransport == null) {
                    throw new RemoteException("Could not connect: " + mTransportClient);
                }
            }
        }
    }

    @VisibleForTesting
    TransportClient getClient() {
        return mTransportClient;
    }
}
+97 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.backup.encryption.transport;

import static com.android.server.backup.encryption.BackupEncryptionService.TAG;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.transport.TransportClientManager;
import com.android.server.backup.transport.TransportStats;

import java.util.HashMap;
import java.util.Map;

/**
 * Handles creation and cleanup of {@link IntermediateEncryptingTransport} instances.
 */
public class IntermediateEncryptingTransportManager {
    private static final String CALLER = "IntermediateEncryptingTransportManager";
    private final TransportClientManager mTransportClientManager;
    private final Object mTransportsLock = new Object();
    private final Map<ComponentName, IntermediateEncryptingTransport> mTransports = new HashMap<>();

    @VisibleForTesting
    IntermediateEncryptingTransportManager(TransportClientManager transportClientManager) {
        mTransportClientManager = transportClientManager;
    }

    public IntermediateEncryptingTransportManager(Context context) {
        this(new TransportClientManager(UserHandle.myUserId(), context, new TransportStats()));
    }

    /**
     * Extract the {@link ComponentName} corresponding to the real {@link IBackupTransport}, and
     * provide a {@link IntermediateEncryptingTransport} which is an implementation of {@link
     * IBackupTransport} that encrypts (or decrypts) the data when sending it (or receiving it) from
     * the real {@link IBackupTransport}.
     * @param intent {@link Intent} created with a call to {@link
     * TransportClientManager.getEncryptingTransportIntent(ComponentName)}.
     * @return
     */
    public IntermediateEncryptingTransport get(Intent intent) {
        Intent transportIntent = TransportClientManager.getRealTransportIntent(intent);
        Log.i(TAG, "get: intent:" + intent + " transportIntent:" + transportIntent);
        synchronized (mTransportsLock) {
            return mTransports.computeIfAbsent(transportIntent.getComponent(),
                    c -> create(transportIntent));
        }
    }

    /**
     * Create an instance of {@link IntermediateEncryptingTransport}.
     */
    private IntermediateEncryptingTransport create(Intent realTransportIntent) {
        return new IntermediateEncryptingTransport(mTransportClientManager.getTransportClient(
                realTransportIntent.getComponent(), realTransportIntent.getExtras(), CALLER));
    }

    /**
     * Cleanup the {@link IntermediateEncryptingTransport} which was created by a call to
     * {@link #get(Intent)} with this {@link Intent}.
     */
    public void cleanup(Intent intent) {
        Intent transportIntent = TransportClientManager.getRealTransportIntent(intent);
        Log.i(TAG, "cleanup: intent:" + intent + " transportIntent:" + transportIntent);

        IntermediateEncryptingTransport transport;
        synchronized (mTransportsLock) {
            transport = mTransports.remove(transportIntent.getComponent());
        }
        if (transport != null) {
            mTransportClientManager.disposeOfTransportClient(transport.getClient(), CALLER);
        } else {
            Log.i(TAG, "Could not find IntermediateEncryptingTransport");
        }
    }
}
Loading