1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    The code included in this file is provided under the terms of the ISC license
11    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12    To use, copy, modify, and/or distribute this software for any purpose with or
13    without fee is hereby granted provided that the above copyright notice and
14    this permission notice appear in all copies.
15 
16    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18    DISCLAIMED.
19 
20   ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 //==============================================================================
27 namespace AndroidStatsHelpers
28 {
29     #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
30      STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")
31 
32     DECLARE_JNI_CLASS (SystemClass, "java/lang/System")
33     #undef JNI_CLASS_MEMBERS
34 
35     #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
36      STATICMETHOD (getDefault, "getDefault", "()Ljava/util/Locale;") \
37      METHOD (getCountry, "getCountry", "()Ljava/lang/String;") \
38      METHOD (getLanguage, "getLanguage", "()Ljava/lang/String;")
39 
40     DECLARE_JNI_CLASS (JavaLocale, "java/util/Locale")
41     #undef JNI_CLASS_MEMBERS
42 
getSystemProperty(const String & name)43     static String getSystemProperty (const String& name)
44     {
45         return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass,
46                                                                                           SystemClass.getProperty,
47                                                                                           javaString (name).get())));
48     }
49 
getLocaleValue(bool isRegion)50     static String getLocaleValue (bool isRegion)
51     {
52         auto* env = getEnv();
53         LocalRef<jobject> locale (env->CallStaticObjectMethod (JavaLocale, JavaLocale.getDefault));
54 
55         auto stringResult = isRegion ? env->CallObjectMethod (locale.get(), JavaLocale.getCountry)
56                                      : env->CallObjectMethod (locale.get(), JavaLocale.getLanguage);
57 
58         return juceString (LocalRef<jstring> ((jstring) stringResult));
59     }
60 
getAndroidOsBuildValue(const char * fieldName)61     static String getAndroidOsBuildValue (const char* fieldName)
62     {
63         return juceString (LocalRef<jstring> ((jstring) getEnv()->GetStaticObjectField (
64                             AndroidBuild, getEnv()->GetStaticFieldID (AndroidBuild, fieldName, "Ljava/lang/String;"))));
65     }
66 }
67 
68 //==============================================================================
getOperatingSystemType()69 SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
70 {
71     return Android;
72 }
73 
getOperatingSystemName()74 String SystemStats::getOperatingSystemName()
75 {
76     return "Android " + AndroidStatsHelpers::getSystemProperty ("os.version");
77 }
78 
getDeviceDescription()79 String SystemStats::getDeviceDescription()
80 {
81     return AndroidStatsHelpers::getAndroidOsBuildValue ("MODEL")
82             + "-" + AndroidStatsHelpers::getAndroidOsBuildValue ("SERIAL");
83 }
84 
getDeviceManufacturer()85 String SystemStats::getDeviceManufacturer()
86 {
87     return AndroidStatsHelpers::getAndroidOsBuildValue ("MANUFACTURER");
88 }
89 
isOperatingSystem64Bit()90 bool SystemStats::isOperatingSystem64Bit()
91 {
92    #if JUCE_64BIT
93     return true;
94    #else
95     return false;
96    #endif
97 }
98 
getCpuVendor()99 String SystemStats::getCpuVendor()
100 {
101     return AndroidStatsHelpers::getSystemProperty ("os.arch");
102 }
103 
getCpuModel()104 String SystemStats::getCpuModel()
105 {
106     return readPosixConfigFileValue ("/proc/cpuinfo", "Hardware");
107 }
108 
getCpuSpeedInMegahertz()109 int SystemStats::getCpuSpeedInMegahertz()
110 {
111     int maxFreqKHz = 0;
112 
113     for (int i = 0; i < getNumCpus(); ++i)
114     {
115         int freqKHz = File ("/sys/devices/system/cpu/cpu" + String(i) + "/cpufreq/cpuinfo_max_freq")
116                         .loadFileAsString()
117                         .getIntValue();
118 
119         maxFreqKHz = jmax (freqKHz, maxFreqKHz);
120     }
121 
122     return maxFreqKHz / 1000;
123 }
124 
getMemorySizeInMegabytes()125 int SystemStats::getMemorySizeInMegabytes()
126 {
127    #if __ANDROID_API__ >= 9
128     struct sysinfo sysi;
129 
130     if (sysinfo (&sysi) == 0)
131         return static_cast<int> ((sysi.totalram * sysi.mem_unit) / (1024 * 1024));
132    #endif
133 
134     return 0;
135 }
136 
getPageSize()137 int SystemStats::getPageSize()
138 {
139     return static_cast<int> (sysconf (_SC_PAGESIZE));
140 }
141 
142 //==============================================================================
getLogonName()143 String SystemStats::getLogonName()
144 {
145     if (const char* user = getenv ("USER"))
146         return CharPointer_UTF8 (user);
147 
148     if (struct passwd* const pw = getpwuid (getuid()))
149         return CharPointer_UTF8 (pw->pw_name);
150 
151     return {};
152 }
153 
getFullUserName()154 String SystemStats::getFullUserName()
155 {
156     return getLogonName();
157 }
158 
getComputerName()159 String SystemStats::getComputerName()
160 {
161     char name [256] = { 0 };
162     if (gethostname (name, sizeof (name) - 1) == 0)
163         return name;
164 
165     return {};
166 }
167 
168 
getUserLanguage()169 String SystemStats::getUserLanguage()    { return AndroidStatsHelpers::getLocaleValue (false); }
getUserRegion()170 String SystemStats::getUserRegion()      { return AndroidStatsHelpers::getLocaleValue (true); }
getDisplayLanguage()171 String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
172 
173 //==============================================================================
initialise()174 void CPUInformation::initialise() noexcept
175 {
176     numPhysicalCPUs = numLogicalCPUs = jmax ((int) 1, (int) android_getCpuCount());
177 
178     auto cpuFamily   = android_getCpuFamily();
179     auto cpuFeatures = android_getCpuFeatures();
180 
181     if (cpuFamily == ANDROID_CPU_FAMILY_X86 || cpuFamily == ANDROID_CPU_FAMILY_X86_64)
182     {
183         hasMMX = hasSSE = hasSSE2 = (cpuFamily == ANDROID_CPU_FAMILY_X86_64);
184 
185         hasSSSE3 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_SSSE3)  != 0);
186         hasSSE41 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_SSE4_1) != 0);
187         hasSSE42 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_SSE4_2) != 0);
188         hasAVX   = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_AVX)    != 0);
189         hasAVX2  = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_AVX2)   != 0);
190 
191         // Google does not distinguish between MMX, SSE, SSE2, SSE3 and SSSE3. So
192         // I assume (and quick Google searches seem to confirm this) that there are
193         // only devices out there that either support all of this or none of this.
194         if (hasSSSE3)
195             hasMMX = hasSSE = hasSSE2 = hasSSE3 = true;
196     }
197     else if (cpuFamily == ANDROID_CPU_FAMILY_ARM)
198     {
199         hasNeon = ((cpuFeatures & ANDROID_CPU_ARM_FEATURE_NEON) != 0);
200     }
201     else if (cpuFamily == ANDROID_CPU_FAMILY_ARM64)
202     {
203         // all arm 64-bit cpus have neon
204         hasNeon = true;
205     }
206 }
207 
208 //==============================================================================
juce_millisecondsSinceStartup()209 uint32 juce_millisecondsSinceStartup() noexcept
210 {
211     timespec t;
212     clock_gettime (CLOCK_MONOTONIC, &t);
213 
214     return static_cast<uint32> (t.tv_sec) * 1000U + static_cast<uint32> (t.tv_nsec) / 1000000U;
215 }
216 
getHighResolutionTicks()217 int64 Time::getHighResolutionTicks() noexcept
218 {
219     timespec t;
220     clock_gettime (CLOCK_MONOTONIC, &t);
221 
222     return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
223 }
224 
getHighResolutionTicksPerSecond()225 int64 Time::getHighResolutionTicksPerSecond() noexcept
226 {
227     return 1000000;  // (microseconds)
228 }
229 
getMillisecondCounterHiRes()230 double Time::getMillisecondCounterHiRes() noexcept
231 {
232     return (double) getHighResolutionTicks() * 0.001;
233 }
234 
setSystemTimeToThisTime() const235 bool Time::setSystemTimeToThisTime() const
236 {
237     jassertfalse;
238     return false;
239 }
240 
241 } // namespace juce
242