1264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu/*
2264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu * Copyright (C) 2017 The Android Open Source Project
3264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu *
4264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu * Licensed under the Apache License, Version 2.0 (the "License");
5264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu * you may not use this file except in compliance with the License.
6264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu * You may obtain a copy of the License at
7264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu *
8264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu *      http://www.apache.org/licenses/LICENSE-2.0
9264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu *
10264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu * Unless required by applicable law or agreed to in writing, software
11264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu * distributed under the License is distributed on an "AS IS" BASIS,
12264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu * See the License for the specific language governing permissions and
14264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu * limitations under the License
15264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu */
16264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
17264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liupackage com.android.phone.testapps.embmsmw;
18264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
19264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.app.Activity;
20264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.app.Service;
21264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.content.BroadcastReceiver;
22264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.content.ComponentName;
23264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.content.Context;
24264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.content.Intent;
25264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.net.Uri;
26264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.os.Binder;
27264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.os.Bundle;
28264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.os.Handler;
29264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.os.HandlerThread;
30264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.os.IBinder;
31264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.os.ParcelFileDescriptor;
32eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liuimport android.os.RemoteException;
33d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liuimport android.telephony.MbmsDownloadSession;
34264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.telephony.mbms.DownloadRequest;
35de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebingerimport android.telephony.mbms.DownloadStateCallback;
36eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liuimport android.telephony.mbms.FileInfo;
37eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liuimport android.telephony.mbms.FileServiceInfo;
38d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liuimport android.telephony.mbms.MbmsDownloadSessionCallback;
396f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liuimport android.telephony.mbms.MbmsErrors;
40264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.telephony.mbms.UriPathPair;
41264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.telephony.mbms.vendor.IMbmsDownloadService;
42264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.telephony.mbms.vendor.MbmsDownloadServiceBase;
43c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liuimport android.telephony.mbms.vendor.VendorUtils;
44264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport android.util.Log;
45264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
46264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport java.io.IOException;
47264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport java.io.InputStream;
48264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport java.io.OutputStream;
49264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport java.util.ArrayList;
50264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport java.util.Arrays;
51434fb4c1f2796b91b79c5a6646518305487802abHall Liuimport java.util.Collections;
52eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liuimport java.util.HashMap;
53eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liuimport java.util.HashSet;
54264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liuimport java.util.List;
55eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liuimport java.util.Map;
56eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liuimport java.util.Set;
57eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liuimport java.util.concurrent.ConcurrentHashMap;
58264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
59264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liupublic class EmbmsSampleDownloadService extends Service {
60eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private static final Set<String> ALLOWED_PACKAGES = new HashSet<String>() {{
61eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        add("com.android.phone.testapps.embmsdownload");
62eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    }};
63eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
64264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    private static final String LOG_TAG = "EmbmsSampleDownload";
6547f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu    private static final long INITIALIZATION_DELAY = 200;
66eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private static final long SEND_FILE_SERVICE_INFO_DELAY = 500;
67264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    private static final long DOWNLOAD_DELAY_MS = 1000;
68eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private static final long FILE_SEPARATION_DELAY = 500;
69264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
70264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    private final IMbmsDownloadService mBinder = new MbmsDownloadServiceBase() {
71264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        @Override
72d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liu        public int initialize(int subId, MbmsDownloadSessionCallback callback) {
7347f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu            int packageUid = Binder.getCallingUid();
7447f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu            String[] packageNames = getPackageManager().getPackagesForUid(packageUid);
75264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            if (packageNames == null) {
766f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu                return MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED;
77264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            }
78eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            boolean isUidAllowed = Arrays.stream(packageNames).anyMatch(ALLOWED_PACKAGES::contains);
79eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            if (!isUidAllowed) {
806f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu                return MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED;
81eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            }
82264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
8347f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu            // Do initialization with a bit of a delay to simulate work being done.
8447f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu            mHandler.postDelayed(() -> {
851b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                FrontendAppIdentifier appKey = new FrontendAppIdentifier(packageUid, subId);
8647f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu                if (!mAppCallbacks.containsKey(appKey)) {
87779ff5fab7677f6ac5ac20db93a906d38a20ebcaHall Liu                    mAppCallbacks.put(appKey, callback);
88c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu                    ComponentName appReceiver = VendorUtils.getAppReceiverFromPackageName(
89c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu                            EmbmsSampleDownloadService.this,
90c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu                            getPackageManager().getNameForUid(packageUid));
9147f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu                    mAppReceivers.put(appKey, appReceiver);
9247f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu                } else {
9380d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu                    callback.onError(
946f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu                            MbmsErrors.InitializationErrors.ERROR_DUPLICATE_INITIALIZE, "");
9547f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu                    return;
9647f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu                }
9780d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu                callback.onMiddlewareReady();
9847f9e74cbb51427c9d1c8a47d414b7976a7d554cHall Liu            }, INITIALIZATION_DELAY);
99b17262ce28a4fbd64e6209b7d0c64305785d499eHall Liu
1006f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu            return MbmsErrors.SUCCESS;
101eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        }
102eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
103eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        @Override
104d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liu        public int requestUpdateFileServices(int subscriptionId,
105eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                List<String> serviceClasses) throws RemoteException {
106eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            FrontendAppIdentifier appKey =
1071b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
108eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            checkInitialized(appKey);
109eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
110eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            List<FileServiceInfo> serviceInfos =
111eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                    FileServiceRepository.getInstance(EmbmsSampleDownloadService.this)
112eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                    .getFileServicesForClasses(serviceClasses);
113eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
114eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            mHandler.postDelayed(() -> {
115d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liu                MbmsDownloadSessionCallback appCallback = mAppCallbacks.get(appKey);
11680d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu                appCallback.onFileServicesUpdated(serviceInfos);
117eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            }, SEND_FILE_SERVICE_INFO_DELAY);
1186f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu            return MbmsErrors.SUCCESS;
119eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        }
120eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
121eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        @Override
1221b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu        public int setTempFileRootDirectory(int subscriptionId,
123eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                String rootDirectoryPath) throws RemoteException {
124eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            FrontendAppIdentifier appKey =
1251b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
126eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            checkInitialized(appKey);
127eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
1281b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu            if (mActiveDownloadRequests.getOrDefault(appKey, Collections.emptySet()).size() > 0) {
1296f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu                return MbmsErrors.DownloadErrors.ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT;
130eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            }
131eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            mAppTempFileRoots.put(appKey, rootDirectoryPath);
1326f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu            return MbmsErrors.SUCCESS;
133eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        }
134264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
135eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        @Override
136d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liu        public int download(DownloadRequest downloadRequest) {
137eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            FrontendAppIdentifier appKey = new FrontendAppIdentifier(
1381b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                    Binder.getCallingUid(), downloadRequest.getSubscriptionId());
139eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            checkInitialized(appKey);
140264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
141eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            mHandler.post(() -> sendFdRequest(downloadRequest, appKey));
1426f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu            return MbmsErrors.SUCCESS;
143264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        }
1441b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu
1451b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu        @Override
146de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        public int registerStateCallback(DownloadRequest downloadRequest,
147de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger                DownloadStateCallback callback) throws RemoteException {
148de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger            mDownloadStateCallbacks.put(downloadRequest, callback);
149de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger            return MbmsErrors.SUCCESS;
150de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        }
151de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger
152de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        @Override
1531b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu        public int cancelDownload(DownloadRequest downloadRequest) {
1541b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu            FrontendAppIdentifier appKey = new FrontendAppIdentifier(
1551b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                    Binder.getCallingUid(), downloadRequest.getSubscriptionId());
1561b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu            checkInitialized(appKey);
1571b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu            if (!mActiveDownloadRequests.getOrDefault(
1581b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                    appKey, Collections.emptySet()).contains(downloadRequest)) {
1596f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu                return MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST;
1601b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu            }
1611b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu            mActiveDownloadRequests.get(appKey).remove(downloadRequest);
1626f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu            return MbmsErrors.SUCCESS;
1631b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu        }
16480d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu
16580d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu        @Override
16680d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu        public void onAppCallbackDied(int uid, int subscriptionId) {
16780d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu            FrontendAppIdentifier appKey = new FrontendAppIdentifier(uid, subscriptionId);
16880d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu
16980d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu            Log.i(LOG_TAG, "Disposing app " + appKey + " due to binder death");
17080d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu            mAppCallbacks.remove(appKey);
17180d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu            // TODO: call dispose
17280d0d75521fa8d539bbb5afb506b1e632dfdab7dHall Liu        }
173264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    };
174264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
175434fb4c1f2796b91b79c5a6646518305487802abHall Liu    private static EmbmsSampleDownloadService sInstance = null;
176434fb4c1f2796b91b79c5a6646518305487802abHall Liu
177d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liu    private final Map<FrontendAppIdentifier, MbmsDownloadSessionCallback> mAppCallbacks =
178eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            new HashMap<>();
179eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private final Map<FrontendAppIdentifier, ComponentName> mAppReceivers = new HashMap<>();
180eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private final Map<FrontendAppIdentifier, String> mAppTempFileRoots = new HashMap<>();
1811b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu    private final Map<FrontendAppIdentifier, Set<DownloadRequest>> mActiveDownloadRequests =
182eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            new ConcurrentHashMap<>();
183434fb4c1f2796b91b79c5a6646518305487802abHall Liu    // A map of app-identifiers to (maps of service-ids to sets of temp file uris in use)
184434fb4c1f2796b91b79c5a6646518305487802abHall Liu    private final Map<FrontendAppIdentifier, Map<String, Set<Uri>>> mTempFilesInUse =
185434fb4c1f2796b91b79c5a6646518305487802abHall Liu            new ConcurrentHashMap<>();
186de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger    private final Map<DownloadRequest, DownloadStateCallback> mDownloadStateCallbacks =
187de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger            new ConcurrentHashMap<>();
188eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
189264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    private HandlerThread mHandlerThread;
190264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    private Handler mHandler;
191434fb4c1f2796b91b79c5a6646518305487802abHall Liu    private int mDownloadDelayFactor = 1;
192264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
193264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    @Override
194264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    public IBinder onBind(Intent intent) {
195264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        mHandlerThread = new HandlerThread("EmbmsTestDownloadServiceWorker");
196264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        mHandlerThread.start();
197264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        mHandler = new Handler(mHandlerThread.getLooper());
198434fb4c1f2796b91b79c5a6646518305487802abHall Liu        sInstance = this;
199264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        return mBinder.asBinder();
200264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    }
201264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
202434fb4c1f2796b91b79c5a6646518305487802abHall Liu    public static EmbmsSampleDownloadService getInstance() {
203434fb4c1f2796b91b79c5a6646518305487802abHall Liu        return sInstance;
204434fb4c1f2796b91b79c5a6646518305487802abHall Liu    }
205434fb4c1f2796b91b79c5a6646518305487802abHall Liu
206434fb4c1f2796b91b79c5a6646518305487802abHall Liu    public void requestCleanup() {
207434fb4c1f2796b91b79c5a6646518305487802abHall Liu        // Assume that there's only one app, and do it for all the services.
208434fb4c1f2796b91b79c5a6646518305487802abHall Liu        FrontendAppIdentifier registeredAppId = mAppReceivers.keySet().iterator().next();
209434fb4c1f2796b91b79c5a6646518305487802abHall Liu        ComponentName appReceiver = mAppReceivers.values().iterator().next();
210434fb4c1f2796b91b79c5a6646518305487802abHall Liu        for (FileServiceInfo fileServiceInfo :
211434fb4c1f2796b91b79c5a6646518305487802abHall Liu                FileServiceRepository.getInstance(this).getAllFileServices()) {
212c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu            Intent cleanupIntent = new Intent(VendorUtils.ACTION_CLEANUP);
213434fb4c1f2796b91b79c5a6646518305487802abHall Liu            cleanupIntent.setComponent(appReceiver);
2147662a90beac0aa6af9dbe96276826a5c8e7f39e4Hall Liu            cleanupIntent.putExtra(VendorUtils.EXTRA_SERVICE_ID, fileServiceInfo.getServiceId());
215c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu            cleanupIntent.putExtra(VendorUtils.EXTRA_TEMP_FILE_ROOT,
216434fb4c1f2796b91b79c5a6646518305487802abHall Liu                    mAppTempFileRoots.get(registeredAppId));
217434fb4c1f2796b91b79c5a6646518305487802abHall Liu            Set<Uri> tempFilesInUse =
218434fb4c1f2796b91b79c5a6646518305487802abHall Liu                    mTempFilesInUse.getOrDefault(registeredAppId, Collections.emptyMap())
219434fb4c1f2796b91b79c5a6646518305487802abHall Liu                            .getOrDefault(fileServiceInfo.getServiceId(), Collections.emptySet());
220c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu            cleanupIntent.putExtra(VendorUtils.EXTRA_TEMP_FILES_IN_USE,
221434fb4c1f2796b91b79c5a6646518305487802abHall Liu                    new ArrayList<>(tempFilesInUse));
222434fb4c1f2796b91b79c5a6646518305487802abHall Liu            sendBroadcast(cleanupIntent);
223434fb4c1f2796b91b79c5a6646518305487802abHall Liu        }
224434fb4c1f2796b91b79c5a6646518305487802abHall Liu    }
225434fb4c1f2796b91b79c5a6646518305487802abHall Liu
226434fb4c1f2796b91b79c5a6646518305487802abHall Liu    public void requestExtraTempFiles(FileServiceInfo serviceInfo) {
227434fb4c1f2796b91b79c5a6646518305487802abHall Liu        // Assume one app, and do it for the specified service.
228434fb4c1f2796b91b79c5a6646518305487802abHall Liu        FrontendAppIdentifier registeredAppId = mAppReceivers.keySet().iterator().next();
229434fb4c1f2796b91b79c5a6646518305487802abHall Liu        ComponentName appReceiver = mAppReceivers.values().iterator().next();
230c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu        Intent fdRequestIntent = new Intent(VendorUtils.ACTION_FILE_DESCRIPTOR_REQUEST);
2317662a90beac0aa6af9dbe96276826a5c8e7f39e4Hall Liu        fdRequestIntent.putExtra(VendorUtils.EXTRA_SERVICE_ID, serviceInfo.getServiceId());
232c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu        fdRequestIntent.putExtra(VendorUtils.EXTRA_FD_COUNT, 10);
233c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu        fdRequestIntent.putExtra(VendorUtils.EXTRA_TEMP_FILE_ROOT,
234434fb4c1f2796b91b79c5a6646518305487802abHall Liu                mAppTempFileRoots.get(registeredAppId));
235434fb4c1f2796b91b79c5a6646518305487802abHall Liu        fdRequestIntent.setComponent(appReceiver);
236434fb4c1f2796b91b79c5a6646518305487802abHall Liu
237434fb4c1f2796b91b79c5a6646518305487802abHall Liu        sendOrderedBroadcast(fdRequestIntent,
238434fb4c1f2796b91b79c5a6646518305487802abHall Liu                null, // receiverPermission
239434fb4c1f2796b91b79c5a6646518305487802abHall Liu                new BroadcastReceiver() {
240434fb4c1f2796b91b79c5a6646518305487802abHall Liu                    @Override
241434fb4c1f2796b91b79c5a6646518305487802abHall Liu                    public void onReceive(Context context, Intent intent) {
242434fb4c1f2796b91b79c5a6646518305487802abHall Liu                        int result = getResultCode();
243434fb4c1f2796b91b79c5a6646518305487802abHall Liu                        Bundle extras = getResultExtras(false);
244434fb4c1f2796b91b79c5a6646518305487802abHall Liu                        Log.i(LOG_TAG, "Received extra temp files. Result " + result);
245434fb4c1f2796b91b79c5a6646518305487802abHall Liu                        if (extras != null) {
246434fb4c1f2796b91b79c5a6646518305487802abHall Liu                            Log.i(LOG_TAG, "Got "
247434fb4c1f2796b91b79c5a6646518305487802abHall Liu                                    + extras.getParcelableArrayList(
248c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu                                    VendorUtils.EXTRA_FREE_URI_LIST).size()
249434fb4c1f2796b91b79c5a6646518305487802abHall Liu                                    + " fds");
250434fb4c1f2796b91b79c5a6646518305487802abHall Liu                        }
251434fb4c1f2796b91b79c5a6646518305487802abHall Liu                    }
252434fb4c1f2796b91b79c5a6646518305487802abHall Liu                },
253434fb4c1f2796b91b79c5a6646518305487802abHall Liu                null, // scheduler
254434fb4c1f2796b91b79c5a6646518305487802abHall Liu                Activity.RESULT_OK,
255434fb4c1f2796b91b79c5a6646518305487802abHall Liu                null, // initialData
256434fb4c1f2796b91b79c5a6646518305487802abHall Liu                null /* initialExtras */);
257434fb4c1f2796b91b79c5a6646518305487802abHall Liu    }
258434fb4c1f2796b91b79c5a6646518305487802abHall Liu
259434fb4c1f2796b91b79c5a6646518305487802abHall Liu    public void delayDownloads(int factor) {
260434fb4c1f2796b91b79c5a6646518305487802abHall Liu        mDownloadDelayFactor = factor;
261434fb4c1f2796b91b79c5a6646518305487802abHall Liu    }
262434fb4c1f2796b91b79c5a6646518305487802abHall Liu
263eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private void sendFdRequest(DownloadRequest request, FrontendAppIdentifier appKey) {
264eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        int numFds = getNumFdsNeededForRequest(request);
265264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        // Compose the FILE_DESCRIPTOR_REQUEST_INTENT
266c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu        Intent requestIntent = new Intent(VendorUtils.ACTION_FILE_DESCRIPTOR_REQUEST);
2677662a90beac0aa6af9dbe96276826a5c8e7f39e4Hall Liu        requestIntent.putExtra(VendorUtils.EXTRA_SERVICE_ID, request.getFileServiceId());
268c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu        requestIntent.putExtra(VendorUtils.EXTRA_FD_COUNT, numFds);
269c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu        requestIntent.putExtra(VendorUtils.EXTRA_TEMP_FILE_ROOT,
270eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                mAppTempFileRoots.get(appKey));
271eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        requestIntent.setComponent(mAppReceivers.get(appKey));
272264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
273264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        // Send as an ordered broadcast, using a BroadcastReceiver to capture the result
274264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        // containing UriPathPairs.
275264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        sendOrderedBroadcast(requestIntent,
276264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                null, // receiverPermission
277264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                new BroadcastReceiver() {
278264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                    @Override
279264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                    public void onReceive(Context context, Intent intent) {
280264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                        Bundle resultExtras = getResultExtras(false);
281264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                        // This delay is to emulate the time it'd usually take to fetch the file
282264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                        // off the network.
283264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                        mHandler.postDelayed(
284eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                                () -> performDownload(request, appKey, resultExtras),
285264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                                DOWNLOAD_DELAY_MS);
286264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                    }
287264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                },
288264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                null, // scheduler
289264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                Activity.RESULT_OK,
290264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                null, // initialData
291264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                null /* initialExtras */);
292264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    }
293264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
294eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private void performDownload(DownloadRequest request, FrontendAppIdentifier appKey,
295eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            Bundle extras) {
296264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        List<UriPathPair> tempFiles = extras.getParcelableArrayList(
297c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu                VendorUtils.EXTRA_FREE_URI_LIST);
298d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu        List<FileInfo> filesToDownload = FileServiceRepository.getInstance(this)
299d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu                .getFileServiceInfoForId(request.getFileServiceId())
300d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu                .getFiles();
301264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
302eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        if (tempFiles.size() != filesToDownload.size()) {
303eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            Log.w(LOG_TAG, "Different numbers of temp files and files to download...");
304eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        }
305eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
3061b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu        if (!mActiveDownloadRequests.containsKey(appKey)) {
3071b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu            mActiveDownloadRequests.put(appKey, Collections.synchronizedSet(new HashSet<>()));
3081b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu        }
3091b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu        mActiveDownloadRequests.get(appKey).add(request);
3101b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu
311eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        // Go through the files one-by-one and send them to the frontend app with a delay between
312eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        // each one.
313eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        for (int i = 0; i < tempFiles.size(); i++) {
314eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            if (i >= filesToDownload.size()) {
315eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                break;
316eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            }
317eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            UriPathPair tempFile = tempFiles.get(i);
318d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu            addTempFileInUse(appKey, request.getFileServiceId(),
319434fb4c1f2796b91b79c5a6646518305487802abHall Liu                    tempFile.getFilePathUri());
320eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            FileInfo fileToDownload = filesToDownload.get(i);
321eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            mHandler.postDelayed(() -> {
3221b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                if (mActiveDownloadRequests.get(appKey) == null ||
3231b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                        !mActiveDownloadRequests.get(appKey).contains(request)) {
3241b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                    return;
3251b74eafe40bbe7480e4ad65dffd851b49455d2b9Hall Liu                }
326eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                downloadSingleFile(appKey, request, tempFile, fileToDownload);
327d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu                removeTempFileInUse(appKey, request.getFileServiceId(),
328434fb4c1f2796b91b79c5a6646518305487802abHall Liu                        tempFile.getFilePathUri());
329434fb4c1f2796b91b79c5a6646518305487802abHall Liu            }, FILE_SEPARATION_DELAY * i * mDownloadDelayFactor);
330eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        }
331eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    }
332eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
333eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private void downloadSingleFile(FrontendAppIdentifier appKey, DownloadRequest request,
334eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            UriPathPair tempFile, FileInfo fileToDownload) {
335d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liu        int result = MbmsDownloadSession.RESULT_SUCCESSFUL;
336de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        // Test Callback
337de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        DownloadStateCallback c = mDownloadStateCallbacks.get(request);
338de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        if (c != null) {
339de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger            c.onProgressUpdated(request, fileToDownload, 0, 10, 0, 10);
340de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        }
341de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        // Test Callback
342de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        if (c != null) {
343de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger            c.onStateUpdated(request, fileToDownload,
344de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger                    MbmsDownloadSession.STATUS_ACTIVELY_DOWNLOADING);
345de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        }
346264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        try {
347264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            // Get the ParcelFileDescriptor for the single temp file we requested
348eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            ParcelFileDescriptor tempFileFd = getContentResolver().openFileDescriptor(
349eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                    tempFile.getContentUri(), "rw");
350264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            OutputStream destinationStream =
351eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                    new ParcelFileDescriptor.AutoCloseOutputStream(tempFileFd);
352264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
353264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            // This is how you get the native fd
354eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            Log.i(LOG_TAG, "Native fd: " + tempFileFd.getFd());
355264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
356eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            int resourceId = FileServiceRepository.getInstance(this)
357eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                    .getResourceForFileUri(fileToDownload.getUri());
358264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            // Open the picture we have in our res/raw directory
359eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            InputStream image = getResources().openRawResource(resourceId);
360264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
361264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            // Copy it into the temp file in the app's file space (crudely)
362264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            byte[] imageBuffer = new byte[image.available()];
363264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            image.read(imageBuffer);
364264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            destinationStream.write(imageBuffer);
365264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu            destinationStream.flush();
366264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        } catch (IOException e) {
367d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liu            result = MbmsDownloadSession.RESULT_CANCELLED;
368264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        }
369de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        // Test Callback
370de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        if (c != null) {
371de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger            c.onProgressUpdated(request, fileToDownload, 10, 10, 10, 10);
372de2c90206b0eb691160731ea2f54b8344d2483f9Brad Ebinger        }
373d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu        // Take a round-trip through the download request serialization to exercise it
37408aa7e2f8478d4adbe9e5bfee6a76be8ee6bed6aBrad Ebinger        DownloadRequest request1 = new DownloadRequest.Builder(request.getSourceUri())
375d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu                .setSubscriptionId(request.getSubscriptionId())
376d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu                .setServiceId(request.getFileServiceId())
377d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu                .setOpaqueData(request.getOpaqueData())
378d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu                .build();
379d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu
380264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        Intent downloadResultIntent =
381c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu                new Intent(VendorUtils.ACTION_DOWNLOAD_RESULT_INTERNAL);
3826f37f0cc96e5b28ef9d60a5b17fd2e8b008c39c0Hall Liu        downloadResultIntent.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, request1);
383c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu        downloadResultIntent.putExtra(VendorUtils.EXTRA_FINAL_URI,
384eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                tempFile.getFilePathUri());
385d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liu        downloadResultIntent.putExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO, fileToDownload);
386c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu        downloadResultIntent.putExtra(VendorUtils.EXTRA_TEMP_FILE_ROOT,
387eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu                mAppTempFileRoots.get(appKey));
388264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        ArrayList<Uri> tempFileList = new ArrayList<>(1);
389eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        tempFileList.add(tempFile.getFilePathUri());
390264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        downloadResultIntent.getExtras().putParcelableArrayList(
391c6b89ec244886b4d5223c8698d173f7dc5164bddHall Liu                VendorUtils.EXTRA_TEMP_LIST, tempFileList);
392d625298cd6d828d59ea41df2b6be24d0c44150b9Hall Liu        downloadResultIntent.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT, result);
393eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        downloadResultIntent.setComponent(mAppReceivers.get(appKey));
394264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu
395264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu        sendOrderedBroadcast(downloadResultIntent,
396264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                null, // receiverPermission
397264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                new BroadcastReceiver() {
398264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                    @Override
399264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                    public void onReceive(Context context, Intent intent) {
400264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                        int resultCode = getResultCode();
401264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                        Log.i(LOG_TAG, "Download result ack: " + resultCode);
402264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                    }
403264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                },
404264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                null, // scheduler
405264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                Activity.RESULT_OK,
406264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                null, // initialData
407264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu                null /* initialExtras */);
408264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu    }
409eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
410eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private void checkInitialized(FrontendAppIdentifier appKey) {
411eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        if (!mAppCallbacks.containsKey(appKey)) {
412eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu            throw new IllegalStateException("Not yet initialized");
413eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu        }
414eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    }
415eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu
416eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    private int getNumFdsNeededForRequest(DownloadRequest request) {
417d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu        return FileServiceRepository.getInstance(this)
418d2860c33f4b1854fcfb13f2247c0e004463d034fHall Liu                .getFileServiceInfoForId(request.getFileServiceId()).getFiles().size();
419eab21d93e8bd66da35a770f7e61ae3f9483babdaHall Liu    }
420434fb4c1f2796b91b79c5a6646518305487802abHall Liu
421434fb4c1f2796b91b79c5a6646518305487802abHall Liu    private void addTempFileInUse(FrontendAppIdentifier appKey, String serviceId, Uri tempFileUri) {
422434fb4c1f2796b91b79c5a6646518305487802abHall Liu        Map<String, Set<Uri>> tempFileByService = mTempFilesInUse.get(appKey);
423434fb4c1f2796b91b79c5a6646518305487802abHall Liu        if (tempFileByService == null) {
424434fb4c1f2796b91b79c5a6646518305487802abHall Liu            tempFileByService = new ConcurrentHashMap<>();
425434fb4c1f2796b91b79c5a6646518305487802abHall Liu            mTempFilesInUse.put(appKey, tempFileByService);
426434fb4c1f2796b91b79c5a6646518305487802abHall Liu        }
427434fb4c1f2796b91b79c5a6646518305487802abHall Liu        Set<Uri> tempFilesInUse = tempFileByService.get(serviceId);
428434fb4c1f2796b91b79c5a6646518305487802abHall Liu        if (tempFilesInUse == null) {
429434fb4c1f2796b91b79c5a6646518305487802abHall Liu            tempFilesInUse = ConcurrentHashMap.newKeySet();
430434fb4c1f2796b91b79c5a6646518305487802abHall Liu            tempFileByService.put(serviceId, tempFilesInUse);
431434fb4c1f2796b91b79c5a6646518305487802abHall Liu        }
432434fb4c1f2796b91b79c5a6646518305487802abHall Liu        tempFilesInUse.add(tempFileUri);
433434fb4c1f2796b91b79c5a6646518305487802abHall Liu    }
434434fb4c1f2796b91b79c5a6646518305487802abHall Liu
435434fb4c1f2796b91b79c5a6646518305487802abHall Liu    private void removeTempFileInUse(FrontendAppIdentifier appKey, String serviceId,
436434fb4c1f2796b91b79c5a6646518305487802abHall Liu            Uri tempFileUri) {
437434fb4c1f2796b91b79c5a6646518305487802abHall Liu        Set<Uri> tempFilesInUse = mTempFilesInUse.getOrDefault(appKey, Collections.emptyMap())
438434fb4c1f2796b91b79c5a6646518305487802abHall Liu                .getOrDefault(serviceId, Collections.emptySet());
439434fb4c1f2796b91b79c5a6646518305487802abHall Liu        if (tempFilesInUse.contains(tempFileUri)) {
440434fb4c1f2796b91b79c5a6646518305487802abHall Liu            tempFilesInUse.remove(tempFileUri);
441434fb4c1f2796b91b79c5a6646518305487802abHall Liu        } else {
442434fb4c1f2796b91b79c5a6646518305487802abHall Liu            Log.w(LOG_TAG, "Trying to remove unknown temp file in use " + tempFileUri + " for app" +
443434fb4c1f2796b91b79c5a6646518305487802abHall Liu                    appKey + " and service id " + serviceId);
444434fb4c1f2796b91b79c5a6646518305487802abHall Liu        }
445434fb4c1f2796b91b79c5a6646518305487802abHall Liu    }
446264773f4a5c58f8d71e13e44ca74327621dc6365Hall Liu}
447