blob: 795bbc1903363b654d8f63097e223a46a18e3936 [file] [log] [blame]
Daichi Hirono8ba41912015-07-30 21:22:57 +09001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.mtp;
18
19import android.os.ParcelFileDescriptor;
20import android.util.Log;
21
22import java.io.IOException;
23import java.util.concurrent.ExecutorService;
24import java.util.concurrent.Executors;
Daichi Hirono24ab92a2016-03-04 17:53:03 +090025import java.util.concurrent.TimeUnit;
Daichi Hirono8ba41912015-07-30 21:22:57 +090026
27class PipeManager {
Daichi Hirono24ab92a2016-03-04 17:53:03 +090028 /**
29 * Milliseconds we wait for background thread when pausing.
30 */
31 private final static long AWAIT_TERMINATION_TIMEOUT = 2000;
32
Daichi Hirono8ba41912015-07-30 21:22:57 +090033 final ExecutorService mExecutor;
Daichi Hironof578fa22016-02-19 18:05:42 +090034 final MtpDatabase mDatabase;
Daichi Hirono8ba41912015-07-30 21:22:57 +090035
Daichi Hironof578fa22016-02-19 18:05:42 +090036 PipeManager(MtpDatabase database) {
37 this(database, Executors.newSingleThreadExecutor());
Daichi Hirono8ba41912015-07-30 21:22:57 +090038 }
39
Daichi Hironof578fa22016-02-19 18:05:42 +090040 PipeManager(MtpDatabase database, ExecutorService executor) {
41 this.mDatabase = database;
Daichi Hirono8ba41912015-07-30 21:22:57 +090042 this.mExecutor = executor;
43 }
44
Daichi Hirono3faa43a2015-08-05 17:15:35 +090045 ParcelFileDescriptor readDocument(MtpManager model, Identifier identifier) throws IOException {
Tomasz Mikolajewski52652ac2015-08-05 17:33:33 +090046 final Task task = new ImportFileTask(model, identifier);
Daichi Hirono8ba41912015-07-30 21:22:57 +090047 mExecutor.execute(task);
48 return task.getReadingFileDescriptor();
49 }
50
Daichi Hirono3faa43a2015-08-05 17:15:35 +090051 ParcelFileDescriptor readThumbnail(MtpManager model, Identifier identifier) throws IOException {
52 final Task task = new GetThumbnailTask(model, identifier);
53 mExecutor.execute(task);
54 return task.getReadingFileDescriptor();
55 }
56
Daichi Hirono8ba41912015-07-30 21:22:57 +090057 private static abstract class Task implements Runnable {
Daichi Hirono2ff024f2015-08-11 20:02:58 +090058 protected final MtpManager mManager;
Tomasz Mikolajewski52652ac2015-08-05 17:33:33 +090059 protected final Identifier mIdentifier;
60 protected final ParcelFileDescriptor[] mDescriptors;
Daichi Hirono8ba41912015-07-30 21:22:57 +090061
Daichi Hirono2ff024f2015-08-11 20:02:58 +090062 Task(MtpManager manager, Identifier identifier) throws IOException {
63 mManager = manager;
Tomasz Mikolajewski52652ac2015-08-05 17:33:33 +090064 mIdentifier = identifier;
Daichi Hirono8ba41912015-07-30 21:22:57 +090065 mDescriptors = ParcelFileDescriptor.createReliablePipe();
66 }
67
Daichi Hirono8ba41912015-07-30 21:22:57 +090068 ParcelFileDescriptor getReadingFileDescriptor() {
69 return mDescriptors[0];
70 }
71 }
72
Tomasz Mikolajewski52652ac2015-08-05 17:33:33 +090073 private static class ImportFileTask extends Task {
74 ImportFileTask(MtpManager model, Identifier identifier) throws IOException {
75 super(model, identifier);
76 }
77
78 @Override
79 public void run() {
80 try {
Daichi Hirono2ff024f2015-08-11 20:02:58 +090081 mManager.importFile(
Daichi Hirono3faa43a2015-08-05 17:15:35 +090082 mIdentifier.mDeviceId, mIdentifier.mObjectHandle, mDescriptors[1]);
Tomasz Mikolajewski52652ac2015-08-05 17:33:33 +090083 mDescriptors[1].close();
84 } catch (IOException error) {
85 try {
86 mDescriptors[1].closeWithError("Failed to stream a file.");
87 } catch (IOException closeError) {
88 Log.w(MtpDocumentsProvider.TAG, closeError.getMessage());
89 }
90 }
91 }
92 }
93
Daichi Hirono3faa43a2015-08-05 17:15:35 +090094 private static class GetThumbnailTask extends Task {
95 GetThumbnailTask(MtpManager model, Identifier identifier) throws IOException {
96 super(model, identifier);
97 }
98
99 @Override
100 public void run() {
101 try {
102 try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
103 new ParcelFileDescriptor.AutoCloseOutputStream(mDescriptors[1])) {
104 try {
Daichi Hirono2ff024f2015-08-11 20:02:58 +0900105 stream.write(mManager.getThumbnail(
Daichi Hirono3faa43a2015-08-05 17:15:35 +0900106 mIdentifier.mDeviceId, mIdentifier.mObjectHandle));
107 } catch (IOException error) {
108 mDescriptors[1].closeWithError("Failed to stream a thumbnail.");
109 }
110 }
111 } catch (IOException closeError) {
112 Log.w(MtpDocumentsProvider.TAG, closeError.getMessage());
113 }
114 }
115 }
116
Daichi Hirono24ab92a2016-03-04 17:53:03 +0900117 boolean close() throws InterruptedException {
118 mExecutor.shutdownNow();
119 return mExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS);
Daichi Hirono8ba41912015-07-30 21:22:57 +0900120 }
121}