Skip to content

Commit aad25f0

Browse files
author
Robert Henigan
authored
Merge pull request #1737 from smartdevicelink/bugfix/issue_1736_multi_file_upload
Fix file operations check file system at queue time instead of run time
2 parents 3243c51 + d65d18e commit aad25f0

9 files changed

Lines changed: 136 additions & 58 deletions

File tree

android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/file/FileManagerTests.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,42 @@ public void run() {
850850
});
851851
}
852852

853+
/**
854+
* Tests to make sure files are not being uploaded to head unit multiple times in a row
855+
*/
856+
@Test
857+
public void testFileNotOnHmi() {
858+
final ISdl internalInterface = createISdlMock();
859+
860+
doAnswer(onListFilesSuccess).when(internalInterface).sendRPC(any(ListFiles.class));
861+
doAnswer(onPutFileSuccess).when(internalInterface).sendRPC(any(PutFile.class));
862+
863+
final SdlArtwork validFile2 = new SdlArtwork(TestValues.GENERAL_STRING + "2", FileType.GRAPHIC_JPEG, TestValues.GENERAL_STRING.getBytes(), false);
864+
865+
final List<SdlArtwork> list = Arrays.asList(validFile2, validFile2);
866+
867+
FileManagerConfig fileManagerConfig = new FileManagerConfig();
868+
869+
final FileManager fileManager = new FileManager(internalInterface, mTestContext, fileManagerConfig);
870+
fileManager.start(new CompletionListener() {
871+
@Override
872+
public void onComplete(boolean success) {
873+
fileManager.uploadArtworks(list, new MultipleFileCompletionListener() {
874+
@Override
875+
public void onComplete(final Map<String, String> errors) {
876+
assertOnMainThread(new Runnable() {
877+
@Override
878+
public void run() {
879+
verify(internalInterface, times(1)).sendRPC(any(PutFile.class));
880+
}
881+
});
882+
}
883+
});
884+
}
885+
});
886+
}
887+
888+
853889
/**
854890
* Test custom overridden SdlFile equals method
855891
*/

android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/screen/TextAndGraphicManagerTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ public void testDispose() {
275275

276276
@Test
277277
public void testOperationManagement() {
278+
textAndGraphicManager.transactionQueue.pause();
278279
textAndGraphicManager.isDirty = true;
279280
textAndGraphicManager.updateOperation = null;
280281
textAndGraphicManager.update(null);

android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import com.smartdevicelink.proxy.rpc.enums.FileType;
4141
import com.smartdevicelink.proxy.rpc.enums.ImageType;
4242
import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
43-
import com.smartdevicelink.util.DebugTool;
4443

4544
/**
4645
* A class that extends SdlFile, representing artwork (JPEG, PNG, or BMP) to be uploaded to core
@@ -159,16 +158,10 @@ private Image createImageRPC() {
159158
*/
160159
@Override
161160
public SdlArtwork clone() {
162-
try {
163-
SdlArtwork artwork = (SdlArtwork) super.clone();
164-
if (artwork != null) {
165-
artwork.imageRPC = artwork.createImageRPC();
166-
}
161+
SdlArtwork artwork = (SdlArtwork) super.clone();
162+
if (artwork != null) {
163+
artwork.imageRPC = artwork.createImageRPC();
167164
return artwork;
168-
} catch (CloneNotSupportedException e) {
169-
if (DebugTool.isDebugEnabled()) {
170-
throw new RuntimeException("Clone not supported by super class");
171-
}
172165
}
173166
return null;
174167
}

android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
import com.smartdevicelink.proxy.rpc.enums.FileType;
4040
import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
41+
import com.smartdevicelink.util.DebugTool;
4142

4243
import java.security.MessageDigest;
4344
import java.security.NoSuchAlgorithmException;
@@ -46,7 +47,7 @@
4647
/**
4748
* A class representing data to be uploaded to core
4849
*/
49-
public class SdlFile {
50+
public class SdlFile implements Cloneable {
5051
private String fileName;
5152
private int id = -1;
5253
private Uri uri;
@@ -368,4 +369,22 @@ public boolean equals(Object o) {
368369
// return comparison
369370
return hashCode() == o.hashCode();
370371
}
372+
373+
/**
374+
* Creates a deep copy of the object
375+
*
376+
* @return deep copy of the object, null if an exception occurred
377+
*/
378+
@Override
379+
public SdlFile clone() {
380+
try {
381+
SdlFile fileClone = (SdlFile) super.clone();
382+
return fileClone;
383+
} catch (CloneNotSupportedException e) {
384+
if (DebugTool.isDebugEnabled()) {
385+
throw new RuntimeException("Clone not supported by super class");
386+
}
387+
}
388+
return null;
389+
}
371390
}

base/src/main/java/com/smartdevicelink/managers/file/BaseFileManager.java

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ abstract class BaseFileManager extends BaseSubManager {
7070
private HashMap<String, Integer> failedFileUploadsCount;
7171
private final int maxFileUploadAttempts;
7272
private final int maxArtworkUploadAttempts;
73+
final String fileManagerCannotOverwriteError = "Cannot overwrite remote file. The remote file system already has a file of this name, and the file manager is set to not automatically overwrite files.";
74+
7375

7476
/**
7577
* Constructor for BaseFileManager
@@ -194,13 +196,7 @@ public void onComplete(boolean success, int bytesAvailable, Collection<String> f
194196
}
195197

196198
private void deleteRemoteFileWithNamePrivate(@NonNull final String fileName, final FileManagerCompletionListener listener) {
197-
if (!mutableRemoteFileNames.contains(fileName) && listener != null) {
198-
String errorMessage = "No such remote file is currently known";
199-
listener.onComplete(false, bytesAvailable, mutableRemoteFileNames, errorMessage);
200-
return;
201-
}
202-
203-
DeleteFileOperation operation = new DeleteFileOperation(internalInterface, fileName, new FileManagerCompletionListener() {
199+
DeleteFileOperation operation = new DeleteFileOperation(internalInterface, fileName, mutableRemoteFileNames, new FileManagerCompletionListener() {
204200
@Override
205201
public void onComplete(boolean success, int bytesAvailable, Collection<String> fileNames, String errorMessage) {
206202
if (success) {
@@ -405,46 +401,29 @@ private void uploadFilePrivate(@NonNull final SdlFile file, final FileManagerCom
405401
return;
406402
}
407403

408-
// HAX: [#827](https://github.com/smartdevicelink/sdl_ios/issues/827) Older versions of Core
409-
// had a bug where list files would cache incorrectly. This led to attempted uploads failing
410-
// due to the system thinking they were already there when they were not. This is only needed
411-
// if connecting to Core v4.3.1 or less which corresponds to RPC v4.3.1 or less
412-
Version rpcVersion = new Version(internalInterface.getSdlMsgVersion());
413-
if (!file.isPersistent() && !hasUploadedFile(file) && new Version(4, 4, 0).isNewerThan(rpcVersion) == 1) {
414-
file.setOverwrite(true);
415-
}
416-
417-
// Check our overwrite settings and error out if it would overwrite
418-
if (!file.getOverwrite() && mutableRemoteFileNames.contains(file.getName())) {
419-
String errorMessage = "Cannot overwrite remote file. The remote file system already has a file of this name, and the file manager is set to not automatically overwrite files.";
420-
DebugTool.logWarning(TAG, errorMessage);
421-
if (listener != null) {
422-
listener.onComplete(true, bytesAvailable, null, errorMessage);
423-
}
424-
return;
425-
}
426-
427404
// If we didn't error out over the overwrite, then continue on
428405
sdl_uploadFilePrivate(file, listener);
429406
}
430407

431408
private void sdl_uploadFilePrivate(@NonNull final SdlFile file, final FileManagerCompletionListener listener) {
432-
final String fileName = file.getName();
409+
final SdlFile fileClone = file.clone();
433410

434-
SdlFileWrapper fileWrapper = new SdlFileWrapper(file, new FileManagerCompletionListener() {
411+
SdlFileWrapper fileWrapper = new SdlFileWrapper(fileClone, new FileManagerCompletionListener() {
435412
@Override
436413
public void onComplete(boolean success, int bytesAvailable, Collection<String> fileNames, String errorMessage) {
437414
if (success) {
438415
BaseFileManager.this.bytesAvailable = bytesAvailable;
439-
BaseFileManager.this.mutableRemoteFileNames.add(fileName);
440-
BaseFileManager.this.uploadedEphemeralFileNames.add(fileName);
416+
BaseFileManager.this.mutableRemoteFileNames.add(fileClone.getName());
417+
if (!file.isPersistent()) {
418+
BaseFileManager.this.uploadedEphemeralFileNames.add(fileClone.getName());
419+
}
441420
} else {
442-
incrementFailedUploadCountForFileName(file.getName(), BaseFileManager.this.failedFileUploadsCount);
421+
incrementFailedUploadCountForFileName(fileClone.getName(), BaseFileManager.this.failedFileUploadsCount);
443422

444-
int maxUploadCount = file instanceof SdlArtwork ? maxArtworkUploadAttempts : maxFileUploadAttempts;
445-
if (canFileBeUploadedAgain(file, maxUploadCount, failedFileUploadsCount)) {
423+
int maxUploadCount = fileClone instanceof SdlArtwork ? maxArtworkUploadAttempts : maxFileUploadAttempts;
424+
if (canFileBeUploadedAgain(fileClone, maxUploadCount, failedFileUploadsCount)) {
446425
DebugTool.logInfo(TAG, String.format("Attempting to resend file with name %s after a failed upload attempt", file.getName()));
447-
sdl_uploadFilePrivate(file, listener);
426+
sdl_uploadFilePrivate(fileClone, listener);
448427
return;
449428
}
450429
}

base/src/main/java/com/smartdevicelink/managers/file/DeleteFileOperation.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@
3838
import com.smartdevicelink.proxy.rpc.DeleteFile;
3939
import com.smartdevicelink.proxy.rpc.DeleteFileResponse;
4040
import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
41+
import com.smartdevicelink.util.DebugTool;
4142

4243
import java.lang.ref.WeakReference;
44+
import java.util.Set;
4345

4446
/**
4547
* Created by Bilal Alsharifi on 12/1/20.
@@ -49,12 +51,14 @@ class DeleteFileOperation extends Task {
4951
private final WeakReference<ISdl> internalInterface;
5052
private String fileName;
5153
private FileManagerCompletionListener completionListener;
54+
private Set<String> mutableRemoteFileNames;
5255

53-
DeleteFileOperation(ISdl internalInterface, String fileName, FileManagerCompletionListener completionListener) {
56+
DeleteFileOperation(ISdl internalInterface, String fileName, Set<String> mutableRemoteFileNames, FileManagerCompletionListener completionListener) {
5457
super("DeleteFileOperation");
5558
this.internalInterface = new WeakReference<>(internalInterface);
5659
this.fileName = fileName;
5760
this.completionListener = completionListener;
61+
this.mutableRemoteFileNames = mutableRemoteFileNames;
5862
}
5963

6064
@Override
@@ -66,6 +70,15 @@ private void start() {
6670
if (getState() == Task.CANCELED) {
6771
return;
6872
}
73+
if (!mutableRemoteFileNames.contains(fileName)) {
74+
if (completionListener != null) {
75+
String errorMessage = "File to delete is no longer on the head unit, aborting operation";
76+
// Returning BaseFileManager.SPACE_AVAILABLE_MAX_VALUE for bytesAvaialble as a placeHolder, it will not get updated in BaseFileManager as long as success returned is false.
77+
completionListener.onComplete(false, BaseFileManager.SPACE_AVAILABLE_MAX_VALUE, mutableRemoteFileNames, errorMessage);
78+
}
79+
onFinished();
80+
return;
81+
}
6982

7083
deleteFile();
7184
}
@@ -77,12 +90,15 @@ private void deleteFile() {
7790
public void onResponse(int correlationId, RPCResponse response) {
7891
DeleteFileResponse deleteFileResponse = (DeleteFileResponse) response;
7992
boolean success = deleteFileResponse.getSuccess();
93+
String errorMessage = success ? null : response.getInfo() + ": " + response.getResultCode();
94+
if (errorMessage != null) {
95+
DebugTool.logInfo(TAG, "Error deleting file: " + errorMessage);
96+
}
8097

8198
// If spaceAvailable is null, set it to the max value
8299
int bytesAvailable = deleteFileResponse.getSpaceAvailable() != null ? deleteFileResponse.getSpaceAvailable() : BaseFileManager.SPACE_AVAILABLE_MAX_VALUE;
83100

84101
if (completionListener != null) {
85-
String errorMessage = success ? null : response.getInfo() + ": " + response.getResultCode();
86102
completionListener.onComplete(success, bytesAvailable, null, errorMessage);
87103
}
88104

base/src/main/java/com/smartdevicelink/managers/file/UploadFileOperation.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.smartdevicelink.proxy.rpc.PutFileResponse;
4545
import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener;
4646
import com.smartdevicelink.util.DebugTool;
47+
import com.smartdevicelink.util.Version;
4748

4849
import java.io.IOException;
4950
import java.io.InputStream;
@@ -81,6 +82,27 @@ private void start() {
8182
return;
8283
}
8384

85+
SdlFile file = fileWrapper.getFile();
86+
// HAX: [#827](https://github.com/smartdevicelink/sdl_ios/issues/827) Older versions of Core
87+
// had a bug where list files would cache incorrectly. This led to attempted uploads failing
88+
// due to the system thinking they were already there when they were not. This is only needed
89+
// if connecting to Core v4.3.1 or less which corresponds to RPC v4.3.1 or less
90+
if (internalInterface.get() != null && fileManager.get() != null) {
91+
Version rpcVersion = new Version(internalInterface.get().getSdlMsgVersion());
92+
if (!file.isPersistent() && !fileManager.get().hasUploadedFile(file) && new Version(4, 4, 0).isNewerThan(rpcVersion) == 1) {
93+
file.setOverwrite(true);
94+
}
95+
// Check our overwrite settings and error out if it would overwrite
96+
if (!file.getOverwrite() && fileManager.get().mutableRemoteFileNames.contains(file.getName())) {
97+
DebugTool.logWarning(TAG, fileManager.get().fileManagerCannotOverwriteError);
98+
if (this.fileWrapper.getCompletionListener() != null) {
99+
this.fileWrapper.getCompletionListener().onComplete(true, bytesAvailable, null, fileManager.get().fileManagerCannotOverwriteError);
100+
}
101+
onFinished();
102+
return;
103+
}
104+
}
105+
84106
int mtuSize = 0;
85107
if (internalInterface.get() != null) {
86108
mtuSize = (int) internalInterface.get().getMtu(SessionType.RPC);

javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import com.smartdevicelink.proxy.rpc.enums.FileType;
3838
import com.smartdevicelink.proxy.rpc.enums.ImageType;
3939
import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
40-
import com.smartdevicelink.util.DebugTool;
4140

4241
import java.net.URI;
4342

@@ -159,16 +158,10 @@ private Image createImageRPC() {
159158
*/
160159
@Override
161160
public SdlArtwork clone() {
162-
try {
163-
SdlArtwork artwork = (SdlArtwork) super.clone();
164-
if (artwork != null) {
165-
artwork.imageRPC = artwork.createImageRPC();
166-
}
161+
SdlArtwork artwork = (SdlArtwork) super.clone();
162+
if (artwork != null) {
163+
artwork.imageRPC = artwork.createImageRPC();
167164
return artwork;
168-
} catch (CloneNotSupportedException e) {
169-
if (DebugTool.isDebugEnabled()) {
170-
throw new RuntimeException("Clone not supported by super class");
171-
}
172165
}
173166
return null;
174167
}

javaSE/javaSE/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
import com.smartdevicelink.proxy.rpc.enums.FileType;
3737
import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
38+
import com.smartdevicelink.util.DebugTool;
3839

3940
import java.net.URI;
4041
import java.security.MessageDigest;
@@ -44,7 +45,7 @@
4445
/**
4546
* A class representing data to be uploaded to core
4647
*/
47-
public class SdlFile {
48+
public class SdlFile implements Cloneable {
4849
private String fileName;
4950
private String filePath;
5051
private URI uri;
@@ -366,4 +367,22 @@ public boolean equals(Object o) {
366367
// return comparison
367368
return hashCode() == o.hashCode();
368369
}
370+
371+
/**
372+
* Creates a deep copy of the object
373+
*
374+
* @return deep copy of the object, null if an exception occurred
375+
*/
376+
@Override
377+
public SdlFile clone() {
378+
try {
379+
SdlFile fileClone = (SdlFile) super.clone();
380+
return fileClone;
381+
} catch (CloneNotSupportedException e) {
382+
if (DebugTool.isDebugEnabled()) {
383+
throw new RuntimeException("Clone not supported by super class");
384+
}
385+
}
386+
return null;
387+
}
369388
}

0 commit comments

Comments
 (0)