Remove ideviceinfo, idevice_id artifacts (#50248)
diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index 5533082..ebf6fcf 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart
@@ -43,8 +43,6 @@ /// The summary dill for the dartdevc target. webPlatformKernelDill, iosDeploy, - ideviceinfo, - ideviceId, idevicesyslog, idevicescreenshot, ideviceinstaller, @@ -108,10 +106,6 @@ return 'kernel_worker.dart.snapshot'; case Artifact.iosDeploy: return 'ios-deploy'; - case Artifact.ideviceinfo: - return 'ideviceinfo'; - case Artifact.ideviceId: - return 'idevice_id'; case Artifact.idevicesyslog: return 'idevicesyslog'; case Artifact.idevicescreenshot: @@ -256,8 +250,6 @@ final String artifactFileName = _artifactToFileName(artifact); final String engineDir = _getEngineArtifactsPath(platform, mode); return _fileSystem.path.join(engineDir, artifactFileName); - case Artifact.ideviceId: - case Artifact.ideviceinfo: case Artifact.idevicescreenshot: case Artifact.idevicesyslog: final String artifactFileName = _artifactToFileName(artifact); @@ -512,8 +504,6 @@ return _fileSystem.path.join(dartSdkPath, 'bin', 'snapshots', artifactFileName); case Artifact.kernelWorkerSnapshot: return _fileSystem.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', 'snapshots', artifactFileName); - case Artifact.ideviceId: - case Artifact.ideviceinfo: case Artifact.idevicescreenshot: case Artifact.idevicesyslog: return _cache.getArtifactDirectory('libimobiledevice').childFile(artifactFileName).path;
diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 545cbb6..81cb244 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart
@@ -1272,8 +1272,8 @@ // missing. static const Map<String, List<String>> _kExecutables = <String, List<String>>{ 'libimobiledevice': <String>[ - 'idevice_id', - 'ideviceinfo', + 'idevicescreenshot', + 'idevicesyslog', ], };
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index e48b16b..7792fbe 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -24,83 +24,18 @@ import 'code_signing.dart'; import 'xcodeproj.dart'; -/// Specialized exception for expected situations where the ideviceinfo -/// tool responds with exit code 255 / 'No device found' message -class IOSDeviceNotFoundError implements Exception { - const IOSDeviceNotFoundError(this.message); - - final String message; - - @override - String toString() => message; -} - -/// Exception representing an attempt to find information on an iOS device -/// that failed because the user had not paired the device with the host yet. -class IOSDeviceNotTrustedError implements Exception { - const IOSDeviceNotTrustedError(this.message, this.lockdownCode); - - /// The error message to show to the user. - final String message; - - /// The associated `lockdownd` error code. - final LockdownReturnCode lockdownCode; - - @override - String toString() => '$message (lockdownd error code ${lockdownCode.code})'; -} - -/// Class specifying possible return codes from `lockdownd`. -/// -/// This contains only a subset of the return codes that `lockdownd` can return, -/// as we only care about a limited subset. These values should be kept in sync with -/// https://github.com/libimobiledevice/libimobiledevice/blob/26373b3/include/libimobiledevice/lockdown.h#L37 -class LockdownReturnCode { - const LockdownReturnCode._(this.code); - - /// Creates a new [LockdownReturnCode] from the specified OS exit code. - /// - /// If the [code] maps to one of the known codes, a `const` instance will be - /// returned. - factory LockdownReturnCode.fromCode(int code) { - final Map<int, LockdownReturnCode> knownCodes = <int, LockdownReturnCode>{ - pairingDialogResponsePending.code: pairingDialogResponsePending, - invalidHostId.code: invalidHostId, - }; - - return knownCodes.containsKey(code) ? knownCodes[code] : LockdownReturnCode._(code); - } - - /// The OS exit code. - final int code; - - /// Error code indicating that the pairing dialog has been shown to the user, - /// and the user has not yet responded as to whether to trust the host. - static const LockdownReturnCode pairingDialogResponsePending = LockdownReturnCode._(19); - - /// Error code indicating that the host is not trusted. - /// - /// This can happen if the user explicitly says "do not trust this computer" - /// or if they revoke all trusted computers in the device settings. - static const LockdownReturnCode invalidHostId = LockdownReturnCode._(21); -} - class IMobileDevice { IMobileDevice() - : _ideviceIdPath = globals.artifacts.getArtifactPath(Artifact.ideviceId, platform: TargetPlatform.ios), - _ideviceinfoPath = globals.artifacts.getArtifactPath(Artifact.ideviceinfo, platform: TargetPlatform.ios), - _idevicesyslogPath = globals.artifacts.getArtifactPath(Artifact.idevicesyslog, platform: TargetPlatform.ios), + : _idevicesyslogPath = globals.artifacts.getArtifactPath(Artifact.idevicesyslog, platform: TargetPlatform.ios), _idevicescreenshotPath = globals.artifacts.getArtifactPath(Artifact.idevicescreenshot, platform: TargetPlatform.ios); - final String _ideviceIdPath; - final String _ideviceinfoPath; final String _idevicesyslogPath; final String _idevicescreenshotPath; bool get isInstalled { _isInstalled ??= processUtils.exitsHappySync( <String>[ - _ideviceIdPath, + _idevicescreenshotPath, '-h', ], environment: Map<String, String>.fromEntries( @@ -111,68 +46,6 @@ } bool _isInstalled; - Future<String> getAvailableDeviceIDs() async { - try { - final ProcessResult result = await globals.processManager.run( - <String>[ - _ideviceIdPath, - '-l', - ], - environment: Map<String, String>.fromEntries( - <MapEntry<String, String>>[globals.cache.dyLdLibEntry] - ), - ); - if (result.exitCode != 0) { - throw ToolExit('idevice_id returned an error:\n${result.stderr}'); - } - return result.stdout as String; - } on ProcessException { - throw ToolExit('Failed to invoke idevice_id. Run flutter doctor.'); - } - } - - Future<String> getInfoForDevice(String deviceID, String key) async { - try { - final ProcessResult result = await globals.processManager.run( - <String>[ - _ideviceinfoPath, - '-u', - deviceID, - '-k', - key, - ], - environment: Map<String, String>.fromEntries( - <MapEntry<String, String>>[globals.cache.dyLdLibEntry] - ), - ); - final String stdout = result.stdout as String; - final String stderr = result.stderr as String; - if (result.exitCode == 255 && stdout != null && stdout.contains('No device found')) { - throw IOSDeviceNotFoundError('ideviceinfo could not find device:\n$stdout. Try unlocking attached devices.'); - } - if (result.exitCode == 255 && stderr != null && stderr.contains('Could not connect to lockdownd')) { - if (stderr.contains('error code -${LockdownReturnCode.pairingDialogResponsePending.code}')) { - throw const IOSDeviceNotTrustedError( - 'Device info unavailable. Is the device asking to "Trust This Computer?"', - LockdownReturnCode.pairingDialogResponsePending, - ); - } - if (stderr.contains('error code -${LockdownReturnCode.invalidHostId.code}')) { - throw const IOSDeviceNotTrustedError( - 'Device info unavailable. Device pairing "trust" may have been revoked.', - LockdownReturnCode.invalidHostId, - ); - } - } - if (result.exitCode != 0) { - throw ToolExit('ideviceinfo returned an error:\n$stderr'); - } - return stdout.trim(); - } on ProcessException { - throw ToolExit('Failed to invoke ideviceinfo. Run flutter doctor.'); - } - } - /// Starts `idevicesyslog` and returns the running process. Future<Process> startLogger(String deviceID) { return processUtils.start(
diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index 814ad73..fb0a0b0 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart
@@ -420,14 +420,14 @@ final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('libimobiledevice', mockCache); when(mockCache.getArtifactDirectory(any)).thenReturn(globals.fs.currentDirectory); iosUsbArtifacts.location.createSync(); - final File ideviceIdFile = iosUsbArtifacts.location.childFile('idevice_id') + final File ideviceScreenshotFile = iosUsbArtifacts.location.childFile('idevicescreenshot') ..createSync(); - iosUsbArtifacts.location.childFile('ideviceinfo') + iosUsbArtifacts.location.childFile('idevicesyslog') ..createSync(); expect(iosUsbArtifacts.isUpToDateInner(), true); - ideviceIdFile.deleteSync(); + ideviceScreenshotFile.deleteSync(); expect(iosUsbArtifacts.isUpToDateInner(), false); }, overrides: <Type, Generator>{
diff --git a/packages/flutter_tools/test/general.shard/ios/mac_test.dart b/packages/flutter_tools/test/general.shard/ios/mac_test.dart index f79208c..e9afd81 100644 --- a/packages/flutter_tools/test/general.shard/ios/mac_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/mac_test.dart
@@ -7,7 +7,7 @@ import 'package:file/file.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/base/io.dart' show ProcessException, ProcessResult; +import 'package:flutter_tools/src/base/io.dart' show ProcessResult; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/ios/mac.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; @@ -38,136 +38,20 @@ group('IMobileDevice', () { final FakePlatform osx = FakePlatform.fromPlatform(const LocalPlatform()) ..operatingSystem = 'macos'; - MockProcessManager mockProcessManager; final String libimobiledevicePath = globals.fs.path.join('bin', 'cache', 'artifacts', 'libimobiledevice'); - final String ideviceIdPath = globals.fs.path.join(libimobiledevicePath, 'idevice_id'); - final String ideviceInfoPath = globals.fs.path.join(libimobiledevicePath, 'ideviceinfo'); final String idevicescreenshotPath = globals.fs.path.join(libimobiledevicePath, 'idevicescreenshot'); MockArtifacts mockArtifacts; MockCache mockCache; setUp(() { - mockProcessManager = MockProcessManager(); mockCache = MockCache(); mockArtifacts = MockArtifacts(); - when(mockArtifacts.getArtifactPath(Artifact.ideviceId, platform: anyNamed('platform'))).thenReturn(ideviceIdPath); + when(mockArtifacts.getArtifactPath(Artifact.idevicescreenshot, platform: anyNamed('platform'))).thenReturn(idevicescreenshotPath); when(mockCache.dyLdLibEntry).thenReturn( MapEntry<String, String>('DYLD_LIBRARY_PATH', libimobiledevicePath) ); }); - testUsingContext('getAvailableDeviceIDs throws ToolExit when libimobiledevice is not installed', () async { - when(mockProcessManager.run( - <String>[ideviceIdPath, '-l'], - environment: <String, String>{'DYLD_LIBRARY_PATH': libimobiledevicePath}, - )).thenThrow(ProcessException(ideviceIdPath, <String>['-l'])); - expect(() async => await globals.iMobileDevice.getAvailableDeviceIDs(), throwsToolExit()); - }, overrides: <Type, Generator>{ - ProcessManager: () => mockProcessManager, - Cache: () => mockCache, - Artifacts: () => mockArtifacts, - }); - - testUsingContext('getAvailableDeviceIDs throws ToolExit when idevice_id returns non-zero', () async { - when(mockProcessManager.run( - <String>[ideviceIdPath, '-l'], - environment: <String, String>{'DYLD_LIBRARY_PATH': libimobiledevicePath}, - )).thenAnswer((_) => Future<ProcessResult>.value(ProcessResult(1, 1, '', 'Sad today'))); - expect(() async => await globals.iMobileDevice.getAvailableDeviceIDs(), throwsToolExit()); - }, overrides: <Type, Generator>{ - ProcessManager: () => mockProcessManager, - Cache: () => mockCache, - Artifacts: () => mockArtifacts, - }); - - testUsingContext('getAvailableDeviceIDs returns idevice_id output when installed', () async { - when(mockProcessManager.run( - <String>[ideviceIdPath, '-l'], - environment: <String, String>{'DYLD_LIBRARY_PATH': libimobiledevicePath}, - )).thenAnswer((_) => Future<ProcessResult>.value(ProcessResult(1, 0, 'foo', ''))); - expect(await globals.iMobileDevice.getAvailableDeviceIDs(), 'foo'); - }, overrides: <Type, Generator>{ - ProcessManager: () => mockProcessManager, - Cache: () => mockCache, - Artifacts: () => mockArtifacts, - }); - - testUsingContext('getInfoForDevice throws IOSDeviceNotFoundError when ideviceinfo returns specific error code and message', () async { - when(mockArtifacts.getArtifactPath(Artifact.ideviceinfo, platform: anyNamed('platform'))).thenReturn(ideviceInfoPath); - when(mockProcessManager.run( - <String>[ideviceInfoPath, '-u', 'foo', '-k', 'bar'], - environment: <String, String>{'DYLD_LIBRARY_PATH': libimobiledevicePath}, - )).thenAnswer((_) => Future<ProcessResult>.value(ProcessResult(1, 255, 'No device found with udid foo, is it plugged in?', ''))); - expect(() async => await globals.iMobileDevice.getInfoForDevice('foo', 'bar'), throwsA(isA<IOSDeviceNotFoundError>())); - }, overrides: <Type, Generator>{ - ProcessManager: () => mockProcessManager, - Cache: () => mockCache, - Artifacts: () => mockArtifacts, - }); - - testUsingContext('getInfoForDevice throws IOSDeviceNotFoundError when user has not yet trusted the host', () async { - when(mockArtifacts.getArtifactPath(Artifact.ideviceinfo, platform: anyNamed('platform'))).thenReturn(ideviceInfoPath); - when(mockProcessManager.run( - <String>[ideviceInfoPath, '-u', 'foo', '-k', 'bar'], - environment: <String, String>{'DYLD_LIBRARY_PATH': libimobiledevicePath}, - )).thenAnswer((_) { - final ProcessResult result = ProcessResult( - 1, - 255, - '', - 'ERROR: Could not connect to lockdownd, error code -${LockdownReturnCode.pairingDialogResponsePending.code}', - ); - return Future<ProcessResult>.value(result); - }); - expect(() async => await globals.iMobileDevice.getInfoForDevice('foo', 'bar'), throwsA(isA<IOSDeviceNotTrustedError>())); - }, overrides: <Type, Generator>{ - ProcessManager: () => mockProcessManager, - Cache: () => mockCache, - Artifacts: () => mockArtifacts, - }); - - testUsingContext('getInfoForDevice throws ToolExit lockdownd fails for unknown reason', () async { - when(mockArtifacts.getArtifactPath(Artifact.ideviceinfo, platform: anyNamed('platform'))).thenReturn(ideviceInfoPath); - when(mockProcessManager.run( - <String>[ideviceInfoPath, '-u', 'foo', '-k', 'bar'], - environment: <String, String>{'DYLD_LIBRARY_PATH': libimobiledevicePath}, - )).thenAnswer((_) { - final ProcessResult result = ProcessResult( - 1, - 255, - '', - 'ERROR: Could not connect to lockdownd, error code -12345', - ); - return Future<ProcessResult>.value(result); - }); - expect(() async => await globals.iMobileDevice.getInfoForDevice('foo', 'bar'), throwsToolExit()); - }, overrides: <Type, Generator>{ - ProcessManager: () => mockProcessManager, - Cache: () => mockCache, - Artifacts: () => mockArtifacts, - }); - - testUsingContext('getInfoForDevice throws IOSDeviceNotFoundError when host trust is revoked', () async { - when(mockArtifacts.getArtifactPath(Artifact.ideviceinfo, platform: anyNamed('platform'))).thenReturn(ideviceInfoPath); - when(mockProcessManager.run( - <String>[ideviceInfoPath, '-u', 'foo', '-k', 'bar'], - environment: <String, String>{'DYLD_LIBRARY_PATH': libimobiledevicePath}, - )).thenAnswer((_) { - final ProcessResult result = ProcessResult( - 1, - 255, - '', - 'ERROR: Could not connect to lockdownd, error code -${LockdownReturnCode.invalidHostId.code}', - ); - return Future<ProcessResult>.value(result); - }); - expect(() async => await globals.iMobileDevice.getInfoForDevice('foo', 'bar'), throwsA(isA<IOSDeviceNotTrustedError>())); - }, overrides: <Type, Generator>{ - ProcessManager: () => mockProcessManager, - Cache: () => mockCache, - Artifacts: () => mockArtifacts, - }); - group('screenshot', () { final String outputPath = globals.fs.path.join('some', 'test', 'path', 'image.png'); MockProcessManager mockProcessManager;