1 //===-- RNBServices.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  Created by Christopher Friesen on 3/21/08.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #import "RNBServices.h"
15 
16 #import <CoreFoundation/CoreFoundation.h>
17 #import <unistd.h>
18 #import "DNBLog.h"
19 
20 #if defined (__arm__)
21 #import <SpringBoardServices/SpringBoardServices.h>
22 #endif
23 
24 int
25 ListApplications(std::string& plist, bool opt_runningApps, bool opt_debuggable)
26 {
27 #if defined (__arm__)
28     int result = -1;
29 
30     CFAllocatorRef alloc = kCFAllocatorDefault;
31 
32     // Create a mutable array that we can populate. Specify zero so it can be of any size.
33     CFReleaser<CFMutableArrayRef> plistMutableArray (::CFArrayCreateMutable (alloc, 0, &kCFTypeArrayCallBacks));
34 
35     CFReleaser<CFStringRef> sbsFrontAppID (::SBSCopyFrontmostApplicationDisplayIdentifier ());
36     CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
37 
38     CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
39     CFIndex i = 0;
40     for (i = 0; i < count; i++)
41     {
42         CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
43 
44         // Create a new mutable dictionary for each application
45         CFReleaser<CFMutableDictionaryRef> appInfoDict (::CFDictionaryCreateMutable (alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
46 
47         // Get the process id for the app (if there is one)
48         pid_t pid = INVALID_NUB_PROCESS;
49         if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &pid) == true)
50         {
51             CFReleaser<CFNumberRef> pidCFNumber (::CFNumberCreate (alloc,  kCFNumberSInt32Type, &pid));
52             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PID_KEY, pidCFNumber.get());
53         }
54 
55         // Set the a boolean to indicate if this is the front most
56         if (sbsFrontAppID.get() && displayIdentifier && (::CFStringCompare (sbsFrontAppID.get(), displayIdentifier, 0) == kCFCompareEqualTo))
57             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanTrue);
58         else
59             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanFalse);
60 
61 
62         CFReleaser<CFStringRef> executablePath (::SBSCopyExecutablePathForDisplayIdentifier (displayIdentifier));
63         if (executablePath.get() != NULL)
64         {
65             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PATH_KEY, executablePath.get());
66         }
67 
68         CFReleaser<CFStringRef> iconImagePath (::SBSCopyIconImagePathForDisplayIdentifier (displayIdentifier)) ;
69         if (iconImagePath.get() != NULL)
70         {
71             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_ICON_PATH_KEY, iconImagePath.get());
72         }
73 
74         CFReleaser<CFStringRef> localizedDisplayName (::SBSCopyLocalizedApplicationNameForDisplayIdentifier (displayIdentifier));
75         if (localizedDisplayName.get() != NULL)
76         {
77             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_DISPLAY_NAME_KEY, localizedDisplayName.get());
78         }
79 
80         // Append the application info to the plist array
81         ::CFArrayAppendValue (plistMutableArray.get(), appInfoDict.get());
82     }
83 
84     CFReleaser<CFDataRef> plistData (::CFPropertyListCreateXMLData (alloc, plistMutableArray.get()));
85 
86     // write plist to service port
87     if (plistData.get() != NULL)
88     {
89         CFIndex size = ::CFDataGetLength (plistData.get());
90         const UInt8 *bytes = ::CFDataGetBytePtr (plistData.get());
91         if (bytes != NULL && size > 0)
92         {
93             plist.assign((char *)bytes, size);
94             return 0;   // Success
95         }
96         else
97         {
98             DNBLogError("empty application property list.");
99             result = -2;
100         }
101     }
102     else
103     {
104         DNBLogError("serializing task list.");
105         result = -3;
106     }
107 
108     return result;
109 #else
110     // TODO: list all current processes
111     DNBLogError("SBS doesn't support getting application list.");
112     return -1;
113 #endif
114 }
115 
116 
117 bool
118 IsSBProcess (nub_process_t pid)
119 {
120 #if defined (__arm__)
121     bool opt_runningApps = true;
122     bool opt_debuggable = false;
123 
124     CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
125     if (sbsAppIDs.get() != NULL)
126     {
127         CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
128         CFIndex i = 0;
129         for (i = 0; i < count; i++)
130         {
131             CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
132 
133             // Get the process id for the app (if there is one)
134             pid_t sbs_pid = INVALID_NUB_PROCESS;
135             if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &sbs_pid) == TRUE)
136             {
137                 if (sbs_pid == pid)
138                     return true;
139             }
140         }
141     }
142 #endif
143     return false;
144 }
145 
146