Skip to content

Commit fababd9

Browse files
committed
* cancellable afc operation
1 parent c2f86ea commit fababd9

5 files changed

Lines changed: 524 additions & 332 deletions

File tree

Src/devicebridge.cpp

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,16 @@ bool DeviceBridge::CreateClient(MobileOperation op, QStringList service_ids, QSt
2525
// make sure it killed
2626
RemoveClient(op);
2727

28+
m_cancelFlags[op] = std::make_shared<std::atomic_bool>(false);
29+
2830
// create mew client
29-
m_clients[op] = m_isRemote ? new DeviceClient(m_remoteAddress, service_ids, service_ids_2) : new DeviceClient(m_currentUdid, service_ids, service_ids_2);
30-
bool ok = m_clients[op]->device_error == IDEVICE_E_SUCCESS && m_clients[op]->lockdownd_error == LOCKDOWN_E_SUCCESS;
31+
std::shared_ptr<DeviceClient> client;
32+
if (m_isRemote)
33+
client = std::make_shared<DeviceClient>(m_remoteAddress, service_ids, service_ids_2);
34+
else
35+
client = std::make_shared<DeviceClient>(m_currentUdid, service_ids, service_ids_2);
36+
m_clients[op] = client;
37+
bool ok = client->device_error == IDEVICE_E_SUCCESS && client->lockdownd_error == LOCKDOWN_E_SUCCESS;
3138
if (!ok)
3239
{
3340
emit MessagesReceived(MessagesType::MSG_ERROR, m_isRemote ? ("ERROR: No device with " + m_remoteAddress.toString())
@@ -39,19 +46,31 @@ bool DeviceBridge::CreateClient(MobileOperation op, QStringList service_ids, QSt
3946

4047
void DeviceBridge::RemoveClient(MobileOperation operation)
4148
{
49+
auto cancel = m_cancelFlags.value(operation);
50+
if (cancel) {
51+
cancel->store(true);
52+
}
53+
m_cancelFlags.remove(operation);
54+
4255
if (m_clients.contains(operation))
4356
{
44-
delete m_clients[operation];
4557
m_clients.remove(operation);
4658
}
4759
}
4860

4961
lockdownd_service_descriptor_t DeviceBridge::GetService(MobileOperation operation, QStringList service_ids)
5062
{
63+
auto client = m_clients.value(operation);
64+
if (!client)
65+
{
66+
emit MessagesReceived(MessagesType::MSG_ERROR, "ERROR: No active client for requested operation.");
67+
return nullptr;
68+
}
69+
5170
for (auto& id : service_ids)
5271
{
53-
if (m_clients[operation]->services.contains(id))
54-
return m_clients[operation]->services[id];
72+
if (client->services.contains(id))
73+
return client->services[id];
5574
}
5675
RemoveClient(operation);
5776
emit MessagesReceived(MessagesType::MSG_ERROR, "ERROR: No available service!" + service_ids.join(", "));
@@ -108,9 +127,13 @@ void DeviceBridge::ResetConnection()
108127

109128
for (auto& client : m_clients.keys())
110129
{
111-
delete m_clients[client];
130+
auto cancel = m_cancelFlags.value(client);
131+
if (cancel) {
132+
cancel->store(true);
133+
}
112134
}
113135
m_clients.clear();
136+
m_cancelFlags.clear();
114137

115138
if(m_device)
116139
{
@@ -169,8 +192,12 @@ bool DeviceBridge::IsConnected()
169192

170193
void DeviceBridge::UpdateDeviceInfo()
171194
{
195+
auto client = m_clients.value(MobileOperation::DEVICE_INFO);
196+
if (!client)
197+
return;
198+
172199
plist_t node = nullptr;
173-
if(lockdownd_get_value(m_clients[MobileOperation::DEVICE_INFO]->client, nullptr, nullptr, &node) == LOCKDOWN_E_SUCCESS) {
200+
if(lockdownd_get_value(client->client, nullptr, nullptr, &node) == LOCKDOWN_E_SUCCESS) {
174201
if (node) {
175202
QJsonDocument deviceInfo = PlistToJson(node);
176203
m_currentUdid = deviceInfo["UniqueDeviceID"].toString();

Src/devicebridge.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <QJsonArray>
88
#include <QMutex>
99
#include <QFileInfo>
10+
#include <memory>
11+
#include <atomic>
1012
#include <libimobiledevice/libimobiledevice.h>
1113
#include <libimobiledevice/lockdown.h>
1214
#include <libimobiledevice-glue/utils.h>
@@ -140,7 +142,8 @@ class DeviceBridge : public QObject
140142
static bool m_destroyed;
141143

142144
idevice_t m_device;
143-
QMap<MobileOperation,DeviceClient*> m_clients;
145+
QMap<MobileOperation,std::shared_ptr<DeviceClient>> m_clients;
146+
QMap<MobileOperation,std::shared_ptr<std::atomic_bool>> m_cancelFlags;
144147
QMap<QString, QJsonDocument> m_deviceInfo;
145148
QMap<QString, idevice_connection_type> m_deviceList;
146149
QString m_currentUdid;
@@ -165,19 +168,19 @@ class DeviceBridge : public QObject
165168

166169
//AFCUtils
167170
private:
168-
int afc_upload_file(afc_client_t &afc, const QString &filename, const QString &dstfn, std::function<void(uint32_t,uint32_t)> callback = nullptr);
169-
int afc_download_file(afc_client_t &afc, const QString &srcfn, const QString &dstfn, std::function<void(uint32_t,uint32_t)> callback = nullptr);
170-
bool afc_upload_dir(afc_client_t &afc, const QString &path, const QString &afcpath, std::function<void(int,int,QString)> callback = nullptr);
171+
int afc_upload_file(afc_client_t &afc, const QString &filename, const QString &dstfn, std::function<void(uint32_t,uint32_t)> callback = nullptr, std::function<bool()> should_stop = nullptr);
172+
int afc_download_file(afc_client_t &afc, const QString &srcfn, const QString &dstfn, std::function<void(uint32_t,uint32_t)> callback = nullptr, std::function<bool()> should_stop = nullptr);
173+
bool afc_upload_dir(afc_client_t &afc, const QString &path, const QString &afcpath, std::function<void(int,int,QString)> callback = nullptr, std::function<bool()> should_stop = nullptr);
171174
int afc_copy_crash_reports(afc_client_t &afc, const char* device_directory, const char* host_directory, const char* target_dir = nullptr, const char* filename_filter = nullptr);
172-
int afc_count_recursive(afc_client_t afc, const char* path);
175+
int afc_count_recursive(afc_client_t afc, const char* path, std::function<bool()> should_stop = nullptr);
173176
// Recursively walks an AFC path and populates m_accessibleStorage.
174177
// Parameters:
175178
// - afc: active AFC client used for directory reads and file info lookups.
176179
// - path: AFC path to start traversal (e.g. "/" or "/Documents").
177180
// - visited: optional counter of visited entries; incremented as each file/dir is processed.
178181
// - total: total number of entries expected; used with visited to compute percentage.
179182
// - progress_cb: optional callback invoked as progress_cb(visited, total) after each entry.
180-
void afc_traverse_recursive(afc_client_t afc, const char* path, int* visited = nullptr, int total = 0, std::function<void(int,int)> progress_cb = nullptr);
183+
void afc_traverse_recursive(afc_client_t afc, const char* path, int* visited = nullptr, int total = 0, std::function<void(int,int)> progress_cb = nullptr, std::function<bool()> should_stop = nullptr);
181184

182185
//Mounter
183186
public:
@@ -215,7 +218,7 @@ class DeviceBridge : public QObject
215218
void MakeDirectoryToStorage(QString devicePath, QString bundleId = "");
216219
void RenameToStorage(QString oldPath, QString newPath, QString bundleId = "");
217220
private:
218-
void afc_filemanager_action(MobileOperation op, std::function<void(afc_client_t &afc)> action, const QString& bundleId = "");
221+
void afc_filemanager_action(MobileOperation op, std::function<void(afc_client_t &afc, std::shared_ptr<DeviceClient> client, std::shared_ptr<std::atomic_bool> cancel_flag)> action, const QString& bundleId = "");
219222
QMap<QString, FileProperty> m_accessibleStorage;
220223
signals:
221224
void AccessibleStorageReceived(QMap<QString, FileProperty> contents);
@@ -228,7 +231,7 @@ class DeviceBridge : public QObject
228231
void UninstallApp(QString bundleId);
229232
void InstallApp(InstallerMode cmd, QString path);
230233
private:
231-
void install_app(instproxy_client_t& installer, afc_client_t &afc, InstallerMode cmd, QString path);
234+
void install_app(instproxy_client_t& installer, afc_client_t &afc, InstallerMode cmd, QString path, std::function<bool()> should_stop = nullptr);
232235
static void InstallerCallback(plist_t command, plist_t status, void *unused);
233236
void TriggetInstallerStatus(QJsonDocument command, QJsonDocument status);
234237
QMap<QString, QJsonDocument> m_installedApps;

Src/devicebridge_afc.cpp

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include "utils.h"
1111

1212

13-
int DeviceBridge::afc_upload_file(afc_client_t &afc, const QString &filename, const QString &dstfn, std::function<void(uint32_t,uint32_t)> callback)
13+
int DeviceBridge::afc_upload_file(afc_client_t &afc, const QString &filename, const QString &dstfn, std::function<void(uint32_t,uint32_t)> callback, std::function<bool()> should_stop)
1414
{
1515
FILE *f = NULL;
1616
uint64_t af = 0;
@@ -32,11 +32,22 @@ int DeviceBridge::afc_upload_file(afc_client_t &afc, const QString &filename, co
3232

3333
size_t amount = 0;
3434
do {
35+
if (should_stop && should_stop()) {
36+
afc_file_close(afc, af);
37+
fclose(f);
38+
return -3;
39+
}
40+
3541
amount = fread(buf, 1, sizeof(buf), f);
3642
if (amount > 0) {
3743
uint32_t written, total = 0;
3844
afc_error_t aerr = AFC_E_SUCCESS;
3945
while (total < amount) {
46+
if (should_stop && should_stop()) {
47+
afc_file_close(afc, af);
48+
fclose(f);
49+
return -3;
50+
}
4051
written = 0;
4152
aerr = afc_file_write(afc, af, buf, amount, &written);
4253
if (aerr != AFC_E_SUCCESS) {
@@ -60,7 +71,7 @@ int DeviceBridge::afc_upload_file(afc_client_t &afc, const QString &filename, co
6071
return AFC_E_SUCCESS;
6172
}
6273

63-
int DeviceBridge::afc_download_file(afc_client_t &afc, const QString &srcfn, const QString &dstfn, std::function<void(uint32_t,uint32_t)> callback)
74+
int DeviceBridge::afc_download_file(afc_client_t &afc, const QString &srcfn, const QString &dstfn, std::function<void(uint32_t,uint32_t)> callback, std::function<bool()> should_stop)
6475
{
6576
FILE *f = NULL;
6677
uint64_t af = 0;
@@ -97,6 +108,12 @@ int DeviceBridge::afc_download_file(afc_client_t &afc, const QString &srcfn, con
97108
afc_error_t aerr = AFC_E_SUCCESS;
98109
uint32_t bytes_read = 0;
99110
do {
111+
if (should_stop && should_stop()) {
112+
fclose(f);
113+
afc_file_close(afc, af);
114+
return -3;
115+
}
116+
100117
bytes_read = 0;
101118
aerr = afc_file_read(afc, af, buf, sizeof(buf), &bytes_read);
102119
if (aerr != AFC_E_SUCCESS) {
@@ -120,7 +137,7 @@ int DeviceBridge::afc_download_file(afc_client_t &afc, const QString &srcfn, con
120137
return AFC_E_SUCCESS;
121138
}
122139

123-
bool DeviceBridge::afc_upload_dir(afc_client_t &afc, const QString &path, const QString &afcpath, std::function<void(int,int,QString)> callback)
140+
bool DeviceBridge::afc_upload_dir(afc_client_t &afc, const QString &path, const QString &afcpath, std::function<void(int,int,QString)> callback, std::function<bool()> should_stop)
124141
{
125142
QStringList list_dirs, list_files;
126143
QDir dirpath(path);
@@ -137,6 +154,9 @@ bool DeviceBridge::afc_upload_dir(afc_client_t &afc, const QString &path, const
137154
int total = list_dirs.count() + list_files.count();
138155
foreach (QString dir_name, list_dirs)
139156
{
157+
if (should_stop && should_stop())
158+
return false;
159+
140160
idx++;
141161
QString targetpath = afcpath + "/" + dirpath.relativeFilePath(dir_name);
142162
if (callback) callback(idx, total, QString::asprintf("Adding `%s' to device...", targetpath.toUtf8().data()));
@@ -149,6 +169,9 @@ bool DeviceBridge::afc_upload_dir(afc_client_t &afc, const QString &path, const
149169
}
150170
foreach (QString file_name, list_files)
151171
{
172+
if (should_stop && should_stop())
173+
return false;
174+
152175
idx++;
153176
QString targetpath = afcpath + "/" + dirpath.relativeFilePath(file_name);
154177
auto afc_callback = [&](uint32_t uploaded_bytes, uint32_t total_bytes)
@@ -158,7 +181,7 @@ bool DeviceBridge::afc_upload_dir(afc_client_t &afc, const QString &path, const
158181
BytesToString(total_bytes).toUtf8().data(),
159182
targetpath.toUtf8().data()));
160183
};
161-
int result = afc_upload_file(afc, file_name, targetpath, afc_callback);
184+
int result = afc_upload_file(afc, file_name, targetpath, afc_callback, should_stop);
162185
if (result != 0)
163186
{
164187
if (callback) callback(idx, total, QString::asprintf("Can't send `%s' to device : afc error code %d", targetpath.toUtf8().data(), result));
@@ -168,8 +191,12 @@ bool DeviceBridge::afc_upload_dir(afc_client_t &afc, const QString &path, const
168191
return true;
169192
}
170193

171-
int DeviceBridge::afc_count_recursive(afc_client_t afc, const char *path)
194+
int DeviceBridge::afc_count_recursive(afc_client_t afc, const char *path, std::function<bool()> should_stop)
172195
{
196+
if (should_stop && should_stop()) {
197+
return 0;
198+
}
199+
173200
char **file_list = NULL;
174201
int count = 0;
175202

@@ -178,6 +205,10 @@ int DeviceBridge::afc_count_recursive(afc_client_t afc, const char *path)
178205
}
179206

180207
for (int i = 0; file_list[i]; i++) {
208+
if (should_stop && should_stop()) {
209+
break;
210+
}
211+
181212
if (strcmp(file_list[i], ".") == 0 || strcmp(file_list[i], "..") == 0) continue;
182213

183214
char full_path[2048];
@@ -202,22 +233,30 @@ int DeviceBridge::afc_count_recursive(afc_client_t afc, const char *path)
202233

203234
count++;
204235
if (is_dir) {
205-
count += afc_count_recursive(afc, full_path);
236+
count += afc_count_recursive(afc, full_path, should_stop);
206237
}
207238
}
208239
afc_dictionary_free(file_list);
209240
return count;
210241
}
211242

212-
void DeviceBridge::afc_traverse_recursive(afc_client_t afc, const char *path, int* visited, int total, std::function<void(int,int)> progress_cb)
243+
void DeviceBridge::afc_traverse_recursive(afc_client_t afc, const char *path, int* visited, int total, std::function<void(int,int)> progress_cb, std::function<bool()> should_stop)
213244
{
245+
if (should_stop && should_stop()) {
246+
return;
247+
}
248+
214249
char **file_list = NULL;
215250

216251
if (afc_read_directory(afc, path, &file_list) != AFC_E_SUCCESS || !file_list) {
217252
return;
218253
}
219254

220255
for (int i = 0; file_list[i]; i++) {
256+
if (should_stop && should_stop()) {
257+
break;
258+
}
259+
221260
if (strcmp(file_list[i], ".") == 0 || strcmp(file_list[i], "..") == 0) continue;
222261

223262
char full_path[2048];
@@ -258,7 +297,7 @@ void DeviceBridge::afc_traverse_recursive(afc_client_t afc, const char *path, in
258297
}
259298

260299
if (is_dir) {
261-
afc_traverse_recursive(afc, full_path, visited, total, progress_cb);
300+
afc_traverse_recursive(afc, full_path, visited, total, progress_cb, should_stop);
262301
}
263302
}
264303
afc_dictionary_free(file_list);

0 commit comments

Comments
 (0)