1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_NDEBUG 0
18 #define LOG_TAG "BootAnimation"
19 
20 #include <vector>
21 
22 #include <stdint.h>
23 #include <inttypes.h>
24 #include <sys/inotify.h>
25 #include <sys/poll.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <math.h>
29 #include <fcntl.h>
30 #include <utils/misc.h>
31 #include <signal.h>
32 #include <time.h>
33 
34 #include <cutils/atomic.h>
35 #include <cutils/properties.h>
36 
37 #include <androidfw/AssetManager.h>
38 #include <binder/IPCThreadState.h>
39 #include <utils/Errors.h>
40 #include <utils/Log.h>
41 #include <utils/SystemClock.h>
42 
43 #include <android-base/properties.h>
44 
45 #include <ui/DisplayConfig.h>
46 #include <ui/PixelFormat.h>
47 #include <ui/Rect.h>
48 #include <ui/Region.h>
49 
50 #include <gui/ISurfaceComposer.h>
51 #include <gui/DisplayEventReceiver.h>
52 #include <gui/Surface.h>
53 #include <gui/SurfaceComposerClient.h>
54 
55 // TODO: Fix Skia.
56 #pragma GCC diagnostic push
57 #pragma GCC diagnostic ignored "-Wunused-parameter"
58 #include <SkBitmap.h>
59 #include <SkImage.h>
60 #include <SkStream.h>
61 #pragma GCC diagnostic pop
62 
63 #include <GLES/gl.h>
64 #include <GLES/glext.h>
65 #include <EGL/eglext.h>
66 
67 #include "BootAnimation.h"
68 
69 #define ANIM_PATH_MAX 255
70 #define STR(x)   #x
71 #define STRTO(x) STR(x)
72 
73 namespace android {
74 
75 static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
76 static const char PRODUCT_BOOTANIMATION_DARK_FILE[] = "/product/media/bootanimation-dark.zip";
77 static const char PRODUCT_BOOTANIMATION_FILE[] = "/product/media/bootanimation.zip";
78 static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
79 static const char APEX_BOOTANIMATION_FILE[] = "/apex/com.android.bootanimation/etc/bootanimation.zip";
80 static const char PRODUCT_ENCRYPTED_BOOTANIMATION_FILE[] = "/product/media/bootanimation-encrypted.zip";
81 static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
82 static const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip";
83 static const char PRODUCT_SHUTDOWNANIMATION_FILE[] = "/product/media/shutdownanimation.zip";
84 static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";
85 
86 static constexpr const char* PRODUCT_USERSPACE_REBOOT_ANIMATION_FILE = "/product/media/userspace-reboot.zip";
87 static constexpr const char* OEM_USERSPACE_REBOOT_ANIMATION_FILE = "/oem/media/userspace-reboot.zip";
88 static constexpr const char* SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE = "/system/media/userspace-reboot.zip";
89 
90 static const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
91 static const char SYSTEM_TIME_DIR_NAME[] = "time";
92 static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
93 static const char CLOCK_FONT_ASSET[] = "images/clock_font.png";
94 static const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png";
95 static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
96 static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
97 static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
98 static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
99 static const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/system/time/time_format_12_hour";
100 // Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00.
101 static const long long ACCURATE_TIME_EPOCH = 946684800000;
102 static constexpr char FONT_BEGIN_CHAR = ' ';
103 static constexpr char FONT_END_CHAR = '~' + 1;
104 static constexpr size_t FONT_NUM_CHARS = FONT_END_CHAR - FONT_BEGIN_CHAR + 1;
105 static constexpr size_t FONT_NUM_COLS = 16;
106 static constexpr size_t FONT_NUM_ROWS = FONT_NUM_CHARS / FONT_NUM_COLS;
107 static const int TEXT_CENTER_VALUE = INT_MAX;
108 static const int TEXT_MISSING_VALUE = INT_MIN;
109 static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
110 static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
111 static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
112 static constexpr size_t TEXT_POS_LEN_MAX = 16;
113 
114 // ---------------------------------------------------------------------------
115 
BootAnimation(sp<Callbacks> callbacks)116 BootAnimation::BootAnimation(sp<Callbacks> callbacks)
117         : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), mTimeFormat12Hour(false),
118         mTimeCheckThread(nullptr), mCallbacks(callbacks), mLooper(new Looper(false)) {
119     mSession = new SurfaceComposerClient();
120 
121     std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
122     if (powerCtl.empty()) {
123         mShuttingDown = false;
124     } else {
125         mShuttingDown = true;
126     }
127     ALOGD("%sAnimationStartTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
128             elapsedRealtime());
129 }
130 
~BootAnimation()131 BootAnimation::~BootAnimation() {
132     if (mAnimation != nullptr) {
133         releaseAnimation(mAnimation);
134         mAnimation = nullptr;
135     }
136     ALOGD("%sAnimationStopTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
137             elapsedRealtime());
138 }
139 
onFirstRef()140 void BootAnimation::onFirstRef() {
141     status_t err = mSession->linkToComposerDeath(this);
142     SLOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
143     if (err == NO_ERROR) {
144         // Load the animation content -- this can be slow (eg 200ms)
145         // called before waitForSurfaceFlinger() in main() to avoid wait
146         ALOGD("%sAnimationPreloadTiming start time: %" PRId64 "ms",
147                 mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
148         preloadAnimation();
149         ALOGD("%sAnimationPreloadStopTiming start time: %" PRId64 "ms",
150                 mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
151     }
152 }
153 
session() const154 sp<SurfaceComposerClient> BootAnimation::session() const {
155     return mSession;
156 }
157 
binderDied(const wp<IBinder> &)158 void BootAnimation::binderDied(const wp<IBinder>&) {
159     // woah, surfaceflinger died!
160     SLOGD("SurfaceFlinger died, exiting...");
161 
162     // calling requestExit() is not enough here because the Surface code
163     // might be blocked on a condition variable that will never be updated.
164     kill( getpid(), SIGKILL );
165     requestExit();
166 }
167 
initTexture(Texture * texture,AssetManager & assets,const char * name)168 status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
169         const char* name) {
170     Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
171     if (asset == nullptr)
172         return NO_INIT;
173     SkBitmap bitmap;
174     sk_sp<SkData> data = SkData::MakeWithoutCopy(asset->getBuffer(false),
175             asset->getLength());
176     sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
177     image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
178     asset->close();
179     delete asset;
180 
181     const int w = bitmap.width();
182     const int h = bitmap.height();
183     const void* p = bitmap.getPixels();
184 
185     GLint crop[4] = { 0, h, w, -h };
186     texture->w = w;
187     texture->h = h;
188 
189     glGenTextures(1, &texture->name);
190     glBindTexture(GL_TEXTURE_2D, texture->name);
191 
192     switch (bitmap.colorType()) {
193         case kAlpha_8_SkColorType:
194             glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
195                     GL_UNSIGNED_BYTE, p);
196             break;
197         case kARGB_4444_SkColorType:
198             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
199                     GL_UNSIGNED_SHORT_4_4_4_4, p);
200             break;
201         case kN32_SkColorType:
202             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
203                     GL_UNSIGNED_BYTE, p);
204             break;
205         case kRGB_565_SkColorType:
206             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
207                     GL_UNSIGNED_SHORT_5_6_5, p);
208             break;
209         default:
210             break;
211     }
212 
213     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
214     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
215     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
216     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
217     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
218 
219     return NO_ERROR;
220 }
221 
initTexture(FileMap * map,int * width,int * height)222 status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
223     SkBitmap bitmap;
224     sk_sp<SkData> data = SkData::MakeWithoutCopy(map->getDataPtr(),
225             map->getDataLength());
226     sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
227     image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
228 
229     // FileMap memory is never released until application exit.
230     // Release it now as the texture is already loaded and the memory used for
231     // the packed resource can be released.
232     delete map;
233 
234     const int w = bitmap.width();
235     const int h = bitmap.height();
236     const void* p = bitmap.getPixels();
237 
238     GLint crop[4] = { 0, h, w, -h };
239     int tw = 1 << (31 - __builtin_clz(w));
240     int th = 1 << (31 - __builtin_clz(h));
241     if (tw < w) tw <<= 1;
242     if (th < h) th <<= 1;
243 
244     switch (bitmap.colorType()) {
245         case kN32_SkColorType:
246             if (!mUseNpotTextures && (tw != w || th != h)) {
247                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
248                         GL_UNSIGNED_BYTE, nullptr);
249                 glTexSubImage2D(GL_TEXTURE_2D, 0,
250                         0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
251             } else {
252                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
253                         GL_UNSIGNED_BYTE, p);
254             }
255             break;
256 
257         case kRGB_565_SkColorType:
258             if (!mUseNpotTextures && (tw != w || th != h)) {
259                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
260                         GL_UNSIGNED_SHORT_5_6_5, nullptr);
261                 glTexSubImage2D(GL_TEXTURE_2D, 0,
262                         0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
263             } else {
264                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
265                         GL_UNSIGNED_SHORT_5_6_5, p);
266             }
267             break;
268         default:
269             break;
270     }
271 
272     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
273 
274     *width = w;
275     *height = h;
276 
277     return NO_ERROR;
278 }
279 
280 class BootAnimation::DisplayEventCallback : public LooperCallback {
281     BootAnimation* mBootAnimation;
282 
283 public:
DisplayEventCallback(BootAnimation * bootAnimation)284     DisplayEventCallback(BootAnimation* bootAnimation) {
285         mBootAnimation = bootAnimation;
286     }
287 
handleEvent(int,int events,void *)288     int handleEvent(int /* fd */, int events, void* /* data */) {
289         if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
290             ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x",
291                     events);
292             return 0; // remove the callback
293         }
294 
295         if (!(events & Looper::EVENT_INPUT)) {
296             ALOGW("Received spurious callback for unhandled poll event.  events=0x%x", events);
297             return 1; // keep the callback
298         }
299 
300         constexpr int kBufferSize = 100;
301         DisplayEventReceiver::Event buffer[kBufferSize];
302         ssize_t numEvents;
303         do {
304             numEvents = mBootAnimation->mDisplayEventReceiver->getEvents(buffer, kBufferSize);
305             for (size_t i = 0; i < static_cast<size_t>(numEvents); i++) {
306                 const auto& event = buffer[i];
307                 if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
308                     SLOGV("Hotplug received");
309 
310                     if (!event.hotplug.connected) {
311                         // ignore hotplug disconnect
312                         continue;
313                     }
314                     auto token = SurfaceComposerClient::getPhysicalDisplayToken(
315                         event.header.displayId);
316 
317                     if (token != mBootAnimation->mDisplayToken) {
318                         // ignore hotplug of a secondary display
319                         continue;
320                     }
321 
322                     DisplayConfig displayConfig;
323                     const status_t error = SurfaceComposerClient::getActiveDisplayConfig(
324                         mBootAnimation->mDisplayToken, &displayConfig);
325                     if (error != NO_ERROR) {
326                         SLOGE("Can't get active display configuration.");
327                     }
328                     mBootAnimation->resizeSurface(displayConfig.resolution.getWidth(),
329                         displayConfig.resolution.getHeight());
330                 }
331             }
332         } while (numEvents > 0);
333 
334         return 1;  // keep the callback
335     }
336 };
337 
getEglConfig(const EGLDisplay & display)338 EGLConfig BootAnimation::getEglConfig(const EGLDisplay& display) {
339     const EGLint attribs[] = {
340         EGL_RED_SIZE,   8,
341         EGL_GREEN_SIZE, 8,
342         EGL_BLUE_SIZE,  8,
343         EGL_DEPTH_SIZE, 0,
344         EGL_NONE
345     };
346     EGLint numConfigs;
347     EGLConfig config;
348     eglChooseConfig(display, attribs, &config, 1, &numConfigs);
349     return config;
350 }
351 
limitSurfaceSize(int width,int height) const352 ui::Size BootAnimation::limitSurfaceSize(int width, int height) const {
353     ui::Size limited(width, height);
354     bool wasLimited = false;
355     const float aspectRatio = float(width) / float(height);
356     if (mMaxWidth != 0 && width > mMaxWidth) {
357         limited.height = mMaxWidth / aspectRatio;
358         limited.width = mMaxWidth;
359         wasLimited = true;
360     }
361     if (mMaxHeight != 0 && limited.height > mMaxHeight) {
362         limited.height = mMaxHeight;
363         limited.width = mMaxHeight * aspectRatio;
364         wasLimited = true;
365     }
366     SLOGV_IF(wasLimited, "Surface size has been limited to [%dx%d] from [%dx%d]",
367              limited.width, limited.height, width, height);
368     return limited;
369 }
370 
readyToRun()371 status_t BootAnimation::readyToRun() {
372     mAssets.addDefaultAssets();
373 
374     mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
375     if (mDisplayToken == nullptr)
376         return NAME_NOT_FOUND;
377 
378     DisplayConfig displayConfig;
379     const status_t error =
380             SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &displayConfig);
381     if (error != NO_ERROR)
382         return error;
383 
384     mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
385     mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
386     ui::Size resolution = displayConfig.resolution;
387     resolution = limitSurfaceSize(resolution.width, resolution.height);
388     // create the native surface
389     sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
390             resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);
391 
392     SurfaceComposerClient::Transaction t;
393 
394     // this guest property specifies multi-display IDs to show the boot animation
395     // multiple ids can be set with comma (,) as separator, for example:
396     // setprop persist.boot.animation.displays 19260422155234049,19261083906282754
397     Vector<uint64_t> physicalDisplayIds;
398     char displayValue[PROPERTY_VALUE_MAX] = "";
399     property_get(DISPLAYS_PROP_NAME, displayValue, "");
400     bool isValid = displayValue[0] != '\0';
401     if (isValid) {
402         char *p = displayValue;
403         while (*p) {
404             if (!isdigit(*p) && *p != ',') {
405                 isValid = false;
406                 break;
407             }
408             p ++;
409         }
410         if (!isValid)
411             SLOGE("Invalid syntax for the value of system prop: %s", DISPLAYS_PROP_NAME);
412     }
413     if (isValid) {
414         std::istringstream stream(displayValue);
415         for (PhysicalDisplayId id; stream >> id; ) {
416             physicalDisplayIds.add(id);
417             if (stream.peek() == ',')
418                 stream.ignore();
419         }
420 
421         // In the case of multi-display, boot animation shows on the specified displays
422         // in addition to the primary display
423         auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
424         constexpr uint32_t LAYER_STACK = 0;
425         for (auto id : physicalDisplayIds) {
426             if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
427                 sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(id);
428                 if (token != nullptr)
429                     t.setDisplayLayerStack(token, LAYER_STACK);
430             }
431         }
432         t.setLayerStack(control, LAYER_STACK);
433     }
434 
435     t.setLayer(control, 0x40000000)
436         .apply();
437 
438     sp<Surface> s = control->getSurface();
439 
440     // initialize opengl and egl
441     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
442     eglInitialize(display, nullptr, nullptr);
443     EGLConfig config = getEglConfig(display);
444     EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
445     EGLContext context = eglCreateContext(display, config, nullptr, nullptr);
446     EGLint w, h;
447     eglQuerySurface(display, surface, EGL_WIDTH, &w);
448     eglQuerySurface(display, surface, EGL_HEIGHT, &h);
449 
450     if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
451         return NO_INIT;
452 
453     mDisplay = display;
454     mContext = context;
455     mSurface = surface;
456     mWidth = w;
457     mHeight = h;
458     mFlingerSurfaceControl = control;
459     mFlingerSurface = s;
460     mTargetInset = -1;
461 
462     // Register a display event receiver
463     mDisplayEventReceiver = std::make_unique<DisplayEventReceiver>();
464     status_t status = mDisplayEventReceiver->initCheck();
465     SLOGE_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver failed with status: %d",
466             status);
467     mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT,
468             new DisplayEventCallback(this), nullptr);
469 
470     return NO_ERROR;
471 }
472 
resizeSurface(int newWidth,int newHeight)473 void BootAnimation::resizeSurface(int newWidth, int newHeight) {
474     // We assume this function is called on the animation thread.
475     if (newWidth == mWidth && newHeight == mHeight) {
476         return;
477     }
478     SLOGV("Resizing the boot animation surface to %d %d", newWidth, newHeight);
479 
480     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
481     eglDestroySurface(mDisplay, mSurface);
482 
483     const auto limitedSize = limitSurfaceSize(newWidth, newHeight);
484     mWidth = limitedSize.width;
485     mHeight = limitedSize.height;
486 
487     SurfaceComposerClient::Transaction t;
488     t.setSize(mFlingerSurfaceControl, mWidth, mHeight);
489     t.apply();
490 
491     EGLConfig config = getEglConfig(mDisplay);
492     EGLSurface surface = eglCreateWindowSurface(mDisplay, config, mFlingerSurface.get(), nullptr);
493     if (eglMakeCurrent(mDisplay, surface, surface, mContext) == EGL_FALSE) {
494         SLOGE("Can't make the new surface current. Error %d", eglGetError());
495         return;
496     }
497     glViewport(0, 0, mWidth, mHeight);
498     glScissor(0, 0, mWidth, mHeight);
499 
500     mSurface = surface;
501 }
502 
preloadAnimation()503 bool BootAnimation::preloadAnimation() {
504     findBootAnimationFile();
505     if (!mZipFileName.isEmpty()) {
506         mAnimation = loadAnimation(mZipFileName);
507         return (mAnimation != nullptr);
508     }
509 
510     return false;
511 }
512 
findBootAnimationFileInternal(const std::vector<std::string> & files)513 bool BootAnimation::findBootAnimationFileInternal(const std::vector<std::string> &files) {
514     for (const std::string& f : files) {
515         if (access(f.c_str(), R_OK) == 0) {
516             mZipFileName = f.c_str();
517             return true;
518         }
519     }
520     return false;
521 }
522 
findBootAnimationFile()523 void BootAnimation::findBootAnimationFile() {
524     // If the device has encryption turned on or is in process
525     // of being encrypted we show the encrypted boot animation.
526     char decrypt[PROPERTY_VALUE_MAX];
527     property_get("vold.decrypt", decrypt, "");
528 
529     bool encryptedAnimation = atoi(decrypt) != 0 ||
530         !strcmp("trigger_restart_min_framework", decrypt);
531 
532     if (!mShuttingDown && encryptedAnimation) {
533         static const std::vector<std::string> encryptedBootFiles = {
534             PRODUCT_ENCRYPTED_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE,
535         };
536         if (findBootAnimationFileInternal(encryptedBootFiles)) {
537             return;
538         }
539     }
540 
541     const bool playDarkAnim = android::base::GetIntProperty("ro.boot.theme", 0) == 1;
542     static const std::vector<std::string> bootFiles = {
543         APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE,
544         OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE
545     };
546     static const std::vector<std::string> shutdownFiles = {
547         PRODUCT_SHUTDOWNANIMATION_FILE, OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE, ""
548     };
549     static const std::vector<std::string> userspaceRebootFiles = {
550         PRODUCT_USERSPACE_REBOOT_ANIMATION_FILE, OEM_USERSPACE_REBOOT_ANIMATION_FILE,
551         SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE,
552     };
553 
554     if (android::base::GetBoolProperty("sys.init.userspace_reboot.in_progress", false)) {
555         findBootAnimationFileInternal(userspaceRebootFiles);
556     } else if (mShuttingDown) {
557         findBootAnimationFileInternal(shutdownFiles);
558     } else {
559         findBootAnimationFileInternal(bootFiles);
560     }
561 }
562 
threadLoop()563 bool BootAnimation::threadLoop() {
564     bool result;
565     // We have no bootanimation file, so we use the stock android logo
566     // animation.
567     if (mZipFileName.isEmpty()) {
568         result = android();
569     } else {
570         result = movie();
571     }
572 
573     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
574     eglDestroyContext(mDisplay, mContext);
575     eglDestroySurface(mDisplay, mSurface);
576     mFlingerSurface.clear();
577     mFlingerSurfaceControl.clear();
578     eglTerminate(mDisplay);
579     eglReleaseThread();
580     IPCThreadState::self()->stopProcess();
581     return result;
582 }
583 
android()584 bool BootAnimation::android() {
585     SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
586             elapsedRealtime());
587     initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
588     initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
589 
590     mCallbacks->init({});
591 
592     // clear screen
593     glShadeModel(GL_FLAT);
594     glDisable(GL_DITHER);
595     glDisable(GL_SCISSOR_TEST);
596     glClearColor(0,0,0,1);
597     glClear(GL_COLOR_BUFFER_BIT);
598     eglSwapBuffers(mDisplay, mSurface);
599 
600     glEnable(GL_TEXTURE_2D);
601     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
602 
603     // Blend state
604     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
605     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
606 
607     const nsecs_t startTime = systemTime();
608     do {
609         processDisplayEvents();
610         const GLint xc = (mWidth  - mAndroid[0].w) / 2;
611         const GLint yc = (mHeight - mAndroid[0].h) / 2;
612         const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
613         glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
614                 updateRect.height());
615 
616         nsecs_t now = systemTime();
617         double time = now - startTime;
618         float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
619         GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
620         GLint x = xc - offset;
621 
622         glDisable(GL_SCISSOR_TEST);
623         glClear(GL_COLOR_BUFFER_BIT);
624 
625         glEnable(GL_SCISSOR_TEST);
626         glDisable(GL_BLEND);
627         glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
628         glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
629         glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
630 
631         glEnable(GL_BLEND);
632         glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
633         glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
634 
635         EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
636         if (res == EGL_FALSE)
637             break;
638 
639         // 12fps: don't animate too fast to preserve CPU
640         const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
641         if (sleepTime > 0)
642             usleep(sleepTime);
643 
644         checkExit();
645     } while (!exitPending());
646 
647     glDeleteTextures(1, &mAndroid[0].name);
648     glDeleteTextures(1, &mAndroid[1].name);
649     return false;
650 }
651 
checkExit()652 void BootAnimation::checkExit() {
653     // Allow surface flinger to gracefully request shutdown
654     char value[PROPERTY_VALUE_MAX];
655     property_get(EXIT_PROP_NAME, value, "0");
656     int exitnow = atoi(value);
657     if (exitnow) {
658         requestExit();
659         mCallbacks->shutdown();
660     }
661 }
662 
validClock(const Animation::Part & part)663 bool BootAnimation::validClock(const Animation::Part& part) {
664     return part.clockPosX != TEXT_MISSING_VALUE && part.clockPosY != TEXT_MISSING_VALUE;
665 }
666 
parseTextCoord(const char * str,int * dest)667 bool parseTextCoord(const char* str, int* dest) {
668     if (strcmp("c", str) == 0) {
669         *dest = TEXT_CENTER_VALUE;
670         return true;
671     }
672 
673     char* end;
674     int val = (int) strtol(str, &end, 0);
675     if (end == str || *end != '\0' || val == INT_MAX || val == INT_MIN) {
676         return false;
677     }
678     *dest = val;
679     return true;
680 }
681 
682 // Parse two position coordinates. If only string is non-empty, treat it as the y value.
parsePosition(const char * str1,const char * str2,int * x,int * y)683 void parsePosition(const char* str1, const char* str2, int* x, int* y) {
684     bool success = false;
685     if (strlen(str1) == 0) {  // No values were specified
686         // success = false
687     } else if (strlen(str2) == 0) {  // we have only one value
688         if (parseTextCoord(str1, y)) {
689             *x = TEXT_CENTER_VALUE;
690             success = true;
691         }
692     } else {
693         if (parseTextCoord(str1, x) && parseTextCoord(str2, y)) {
694             success = true;
695         }
696     }
697 
698     if (!success) {
699         *x = TEXT_MISSING_VALUE;
700         *y = TEXT_MISSING_VALUE;
701     }
702 }
703 
704 // Parse a color represented as an HTML-style 'RRGGBB' string: each pair of
705 // characters in str is a hex number in [0, 255], which are converted to
706 // floating point values in the range [0.0, 1.0] and placed in the
707 // corresponding elements of color.
708 //
709 // If the input string isn't valid, parseColor returns false and color is
710 // left unchanged.
parseColor(const char str[7],float color[3])711 static bool parseColor(const char str[7], float color[3]) {
712     float tmpColor[3];
713     for (int i = 0; i < 3; i++) {
714         int val = 0;
715         for (int j = 0; j < 2; j++) {
716             val *= 16;
717             char c = str[2*i + j];
718             if      (c >= '0' && c <= '9') val += c - '0';
719             else if (c >= 'A' && c <= 'F') val += (c - 'A') + 10;
720             else if (c >= 'a' && c <= 'f') val += (c - 'a') + 10;
721             else                           return false;
722         }
723         tmpColor[i] = static_cast<float>(val) / 255.0f;
724     }
725     memcpy(color, tmpColor, sizeof(tmpColor));
726     return true;
727 }
728 
729 
readFile(ZipFileRO * zip,const char * name,String8 & outString)730 static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
731     ZipEntryRO entry = zip->findEntryByName(name);
732     SLOGE_IF(!entry, "couldn't find %s", name);
733     if (!entry) {
734         return false;
735     }
736 
737     FileMap* entryMap = zip->createEntryFileMap(entry);
738     zip->releaseEntry(entry);
739     SLOGE_IF(!entryMap, "entryMap is null");
740     if (!entryMap) {
741         return false;
742     }
743 
744     outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
745     delete entryMap;
746     return true;
747 }
748 
749 // The font image should be a 96x2 array of character images.  The
750 // columns are the printable ASCII characters 0x20 - 0x7f.  The
751 // top row is regular text; the bottom row is bold.
initFont(Font * font,const char * fallback)752 status_t BootAnimation::initFont(Font* font, const char* fallback) {
753     status_t status = NO_ERROR;
754 
755     if (font->map != nullptr) {
756         glGenTextures(1, &font->texture.name);
757         glBindTexture(GL_TEXTURE_2D, font->texture.name);
758 
759         status = initTexture(font->map, &font->texture.w, &font->texture.h);
760 
761         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
762         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
763         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
764         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
765     } else if (fallback != nullptr) {
766         status = initTexture(&font->texture, mAssets, fallback);
767     } else {
768         return NO_INIT;
769     }
770 
771     if (status == NO_ERROR) {
772         font->char_width = font->texture.w / FONT_NUM_COLS;
773         font->char_height = font->texture.h / FONT_NUM_ROWS / 2;  // There are bold and regular rows
774     }
775 
776     return status;
777 }
778 
drawText(const char * str,const Font & font,bool bold,int * x,int * y)779 void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
780     glEnable(GL_BLEND);  // Allow us to draw on top of the animation
781     glBindTexture(GL_TEXTURE_2D, font.texture.name);
782 
783     const int len = strlen(str);
784     const int strWidth = font.char_width * len;
785 
786     if (*x == TEXT_CENTER_VALUE) {
787         *x = (mWidth - strWidth) / 2;
788     } else if (*x < 0) {
789         *x = mWidth + *x - strWidth;
790     }
791     if (*y == TEXT_CENTER_VALUE) {
792         *y = (mHeight - font.char_height) / 2;
793     } else if (*y < 0) {
794         *y = mHeight + *y - font.char_height;
795     }
796 
797     int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
798 
799     for (int i = 0; i < len; i++) {
800         char c = str[i];
801 
802         if (c < FONT_BEGIN_CHAR || c > FONT_END_CHAR) {
803             c = '?';
804         }
805 
806         // Crop the texture to only the pixels in the current glyph
807         const int charPos = (c - FONT_BEGIN_CHAR);  // Position in the list of valid characters
808         const int row = charPos / FONT_NUM_COLS;
809         const int col = charPos % FONT_NUM_COLS;
810         cropRect[0] = col * font.char_width;  // Left of column
811         cropRect[1] = row * font.char_height * 2; // Top of row
812         // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line
813         cropRect[1] += bold ? 2 * font.char_height : font.char_height;
814         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
815 
816         glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);
817 
818         *x += font.char_width;
819     }
820 
821     glDisable(GL_BLEND);  // Return to the animation's default behaviour
822     glBindTexture(GL_TEXTURE_2D, 0);
823 }
824 
825 // We render 12 or 24 hour time.
drawClock(const Font & font,const int xPos,const int yPos)826 void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) {
827     static constexpr char TIME_FORMAT_12[] = "%l:%M";
828     static constexpr char TIME_FORMAT_24[] = "%H:%M";
829     static constexpr int TIME_LENGTH = 6;
830 
831     time_t rawtime;
832     time(&rawtime);
833     struct tm* timeInfo = localtime(&rawtime);
834 
835     char timeBuff[TIME_LENGTH];
836     const char* timeFormat = mTimeFormat12Hour ? TIME_FORMAT_12 : TIME_FORMAT_24;
837     size_t length = strftime(timeBuff, TIME_LENGTH, timeFormat, timeInfo);
838 
839     if (length != TIME_LENGTH - 1) {
840         SLOGE("Couldn't format time; abandoning boot animation clock");
841         mClockEnabled = false;
842         return;
843     }
844 
845     char* out = timeBuff[0] == ' ' ? &timeBuff[1] : &timeBuff[0];
846     int x = xPos;
847     int y = yPos;
848     drawText(out, font, false, &x, &y);
849 }
850 
parseAnimationDesc(Animation & animation)851 bool BootAnimation::parseAnimationDesc(Animation& animation)  {
852     String8 desString;
853 
854     if (!readFile(animation.zip, "desc.txt", desString)) {
855         return false;
856     }
857     char const* s = desString.string();
858 
859     // Parse the description file
860     for (;;) {
861         const char* endl = strstr(s, "\n");
862         if (endl == nullptr) break;
863         String8 line(s, endl - s);
864         const char* l = line.string();
865         int fps = 0;
866         int width = 0;
867         int height = 0;
868         int count = 0;
869         int pause = 0;
870         char path[ANIM_ENTRY_NAME_MAX];
871         char color[7] = "000000"; // default to black if unspecified
872         char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
873         char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
874 
875         char pathType;
876         if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
877             // SLOGD("> w=%d, h=%d, fps=%d", width, height, fps);
878             animation.width = width;
879             animation.height = height;
880             animation.fps = fps;
881         } else if (sscanf(l, " %c %d %d %" STRTO(ANIM_PATH_MAX) "s #%6s %16s %16s",
882                           &pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) {
883             //SLOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s",
884             //    pathType, count, pause, path, color, clockPos1, clockPos2);
885             Animation::Part part;
886             part.playUntilComplete = pathType == 'c';
887             part.count = count;
888             part.pause = pause;
889             part.path = path;
890             part.audioData = nullptr;
891             part.animation = nullptr;
892             if (!parseColor(color, part.backgroundColor)) {
893                 SLOGE("> invalid color '#%s'", color);
894                 part.backgroundColor[0] = 0.0f;
895                 part.backgroundColor[1] = 0.0f;
896                 part.backgroundColor[2] = 0.0f;
897             }
898             parsePosition(clockPos1, clockPos2, &part.clockPosX, &part.clockPosY);
899             animation.parts.add(part);
900         }
901         else if (strcmp(l, "$SYSTEM") == 0) {
902             // SLOGD("> SYSTEM");
903             Animation::Part part;
904             part.playUntilComplete = false;
905             part.count = 1;
906             part.pause = 0;
907             part.audioData = nullptr;
908             part.animation = loadAnimation(String8(SYSTEM_BOOTANIMATION_FILE));
909             if (part.animation != nullptr)
910                 animation.parts.add(part);
911         }
912         s = ++endl;
913     }
914 
915     return true;
916 }
917 
preloadZip(Animation & animation)918 bool BootAnimation::preloadZip(Animation& animation) {
919     // read all the data structures
920     const size_t pcount = animation.parts.size();
921     void *cookie = nullptr;
922     ZipFileRO* zip = animation.zip;
923     if (!zip->startIteration(&cookie)) {
924         return false;
925     }
926 
927     ZipEntryRO entry;
928     char name[ANIM_ENTRY_NAME_MAX];
929     while ((entry = zip->nextEntry(cookie)) != nullptr) {
930         const int foundEntryName = zip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
931         if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
932             SLOGE("Error fetching entry file name");
933             continue;
934         }
935 
936         const String8 entryName(name);
937         const String8 path(entryName.getPathDir());
938         const String8 leaf(entryName.getPathLeaf());
939         if (leaf.size() > 0) {
940             if (entryName == CLOCK_FONT_ZIP_NAME) {
941                 FileMap* map = zip->createEntryFileMap(entry);
942                 if (map) {
943                     animation.clockFont.map = map;
944                 }
945                 continue;
946             }
947 
948             for (size_t j = 0; j < pcount; j++) {
949                 if (path == animation.parts[j].path) {
950                     uint16_t method;
951                     // supports only stored png files
952                     if (zip->getEntryInfo(entry, &method, nullptr, nullptr, nullptr, nullptr, nullptr)) {
953                         if (method == ZipFileRO::kCompressStored) {
954                             FileMap* map = zip->createEntryFileMap(entry);
955                             if (map) {
956                                 Animation::Part& part(animation.parts.editItemAt(j));
957                                 if (leaf == "audio.wav") {
958                                     // a part may have at most one audio file
959                                     part.audioData = (uint8_t *)map->getDataPtr();
960                                     part.audioLength = map->getDataLength();
961                                 } else if (leaf == "trim.txt") {
962                                     part.trimData.setTo((char const*)map->getDataPtr(),
963                                                         map->getDataLength());
964                                 } else {
965                                     Animation::Frame frame;
966                                     frame.name = leaf;
967                                     frame.map = map;
968                                     frame.trimWidth = animation.width;
969                                     frame.trimHeight = animation.height;
970                                     frame.trimX = 0;
971                                     frame.trimY = 0;
972                                     part.frames.add(frame);
973                                 }
974                             }
975                         } else {
976                             SLOGE("bootanimation.zip is compressed; must be only stored");
977                         }
978                     }
979                 }
980             }
981         }
982     }
983 
984     // If there is trimData present, override the positioning defaults.
985     for (Animation::Part& part : animation.parts) {
986         const char* trimDataStr = part.trimData.string();
987         for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
988             const char* endl = strstr(trimDataStr, "\n");
989             // No more trimData for this part.
990             if (endl == nullptr) {
991                 break;
992             }
993             String8 line(trimDataStr, endl - trimDataStr);
994             const char* lineStr = line.string();
995             trimDataStr = ++endl;
996             int width = 0, height = 0, x = 0, y = 0;
997             if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
998                 Animation::Frame& frame(part.frames.editItemAt(frameIdx));
999                 frame.trimWidth = width;
1000                 frame.trimHeight = height;
1001                 frame.trimX = x;
1002                 frame.trimY = y;
1003             } else {
1004                 SLOGE("Error parsing trim.txt, line: %s", lineStr);
1005                 break;
1006             }
1007         }
1008     }
1009 
1010     zip->endIteration(cookie);
1011 
1012     return true;
1013 }
1014 
movie()1015 bool BootAnimation::movie() {
1016     if (mAnimation == nullptr) {
1017         mAnimation = loadAnimation(mZipFileName);
1018     }
1019 
1020     if (mAnimation == nullptr)
1021         return false;
1022 
1023     // mCallbacks->init() may get called recursively,
1024     // this loop is needed to get the same results
1025     for (const Animation::Part& part : mAnimation->parts) {
1026         if (part.animation != nullptr) {
1027             mCallbacks->init(part.animation->parts);
1028         }
1029     }
1030     mCallbacks->init(mAnimation->parts);
1031 
1032     bool anyPartHasClock = false;
1033     for (size_t i=0; i < mAnimation->parts.size(); i++) {
1034         if(validClock(mAnimation->parts[i])) {
1035             anyPartHasClock = true;
1036             break;
1037         }
1038     }
1039     if (!anyPartHasClock) {
1040         mClockEnabled = false;
1041     }
1042 
1043     // Check if npot textures are supported
1044     mUseNpotTextures = false;
1045     String8 gl_extensions;
1046     const char* exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
1047     if (!exts) {
1048         glGetError();
1049     } else {
1050         gl_extensions.setTo(exts);
1051         if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||
1052             (gl_extensions.find("GL_OES_texture_npot") != -1)) {
1053             mUseNpotTextures = true;
1054         }
1055     }
1056 
1057     // Blend required to draw time on top of animation frames.
1058     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1059     glShadeModel(GL_FLAT);
1060     glDisable(GL_DITHER);
1061     glDisable(GL_SCISSOR_TEST);
1062     glDisable(GL_BLEND);
1063 
1064     glBindTexture(GL_TEXTURE_2D, 0);
1065     glEnable(GL_TEXTURE_2D);
1066     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1067     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1068     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1069     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1070     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1071 
1072     bool clockFontInitialized = false;
1073     if (mClockEnabled) {
1074         clockFontInitialized =
1075             (initFont(&mAnimation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR);
1076         mClockEnabled = clockFontInitialized;
1077     }
1078 
1079     if (mClockEnabled && !updateIsTimeAccurate()) {
1080         mTimeCheckThread = new TimeCheckThread(this);
1081         mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
1082     }
1083 
1084     playAnimation(*mAnimation);
1085 
1086     if (mTimeCheckThread != nullptr) {
1087         mTimeCheckThread->requestExit();
1088         mTimeCheckThread = nullptr;
1089     }
1090 
1091     if (clockFontInitialized) {
1092         glDeleteTextures(1, &mAnimation->clockFont.texture.name);
1093     }
1094 
1095     releaseAnimation(mAnimation);
1096     mAnimation = nullptr;
1097 
1098     return false;
1099 }
1100 
playAnimation(const Animation & animation)1101 bool BootAnimation::playAnimation(const Animation& animation) {
1102     const size_t pcount = animation.parts.size();
1103     nsecs_t frameDuration = s2ns(1) / animation.fps;
1104 
1105     SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
1106             elapsedRealtime());
1107     for (size_t i=0 ; i<pcount ; i++) {
1108         const Animation::Part& part(animation.parts[i]);
1109         const size_t fcount = part.frames.size();
1110         glBindTexture(GL_TEXTURE_2D, 0);
1111 
1112         // Handle animation package
1113         if (part.animation != nullptr) {
1114             playAnimation(*part.animation);
1115             if (exitPending())
1116                 break;
1117             continue; //to next part
1118         }
1119 
1120         for (int r=0 ; !part.count || r<part.count ; r++) {
1121             // Exit any non playuntil complete parts immediately
1122             if(exitPending() && !part.playUntilComplete)
1123                 break;
1124 
1125             mCallbacks->playPart(i, part, r);
1126 
1127             glClearColor(
1128                     part.backgroundColor[0],
1129                     part.backgroundColor[1],
1130                     part.backgroundColor[2],
1131                     1.0f);
1132 
1133             for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
1134                 processDisplayEvents();
1135 
1136                 const int animationX = (mWidth - animation.width) / 2;
1137                 const int animationY = (mHeight - animation.height) / 2;
1138 
1139                 const Animation::Frame& frame(part.frames[j]);
1140                 nsecs_t lastFrame = systemTime();
1141 
1142                 if (r > 0) {
1143                     glBindTexture(GL_TEXTURE_2D, frame.tid);
1144                 } else {
1145                     if (part.count != 1) {
1146                         glGenTextures(1, &frame.tid);
1147                         glBindTexture(GL_TEXTURE_2D, frame.tid);
1148                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1149                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1150                     }
1151                     int w, h;
1152                     initTexture(frame.map, &w, &h);
1153                 }
1154 
1155                 const int xc = animationX + frame.trimX;
1156                 const int yc = animationY + frame.trimY;
1157                 Region clearReg(Rect(mWidth, mHeight));
1158                 clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
1159                 if (!clearReg.isEmpty()) {
1160                     Region::const_iterator head(clearReg.begin());
1161                     Region::const_iterator tail(clearReg.end());
1162                     glEnable(GL_SCISSOR_TEST);
1163                     while (head != tail) {
1164                         const Rect& r2(*head++);
1165                         glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
1166                         glClear(GL_COLOR_BUFFER_BIT);
1167                     }
1168                     glDisable(GL_SCISSOR_TEST);
1169                 }
1170                 // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
1171                 // which is equivalent to mHeight - (yc + frame.trimHeight)
1172                 glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight),
1173                               0, frame.trimWidth, frame.trimHeight);
1174                 if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
1175                     drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
1176                 }
1177                 handleViewport(frameDuration);
1178 
1179                 eglSwapBuffers(mDisplay, mSurface);
1180 
1181                 nsecs_t now = systemTime();
1182                 nsecs_t delay = frameDuration - (now - lastFrame);
1183                 //SLOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));
1184                 lastFrame = now;
1185 
1186                 if (delay > 0) {
1187                     struct timespec spec;
1188                     spec.tv_sec  = (now + delay) / 1000000000;
1189                     spec.tv_nsec = (now + delay) % 1000000000;
1190                     int err;
1191                     do {
1192                         err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, nullptr);
1193                     } while (err<0 && errno == EINTR);
1194                 }
1195 
1196                 checkExit();
1197             }
1198 
1199             usleep(part.pause * ns2us(frameDuration));
1200 
1201             // For infinite parts, we've now played them at least once, so perhaps exit
1202             if(exitPending() && !part.count && mCurrentInset >= mTargetInset)
1203                 break;
1204         }
1205 
1206     }
1207 
1208     // Free textures created for looping parts now that the animation is done.
1209     for (const Animation::Part& part : animation.parts) {
1210         if (part.count != 1) {
1211             const size_t fcount = part.frames.size();
1212             for (size_t j = 0; j < fcount; j++) {
1213                 const Animation::Frame& frame(part.frames[j]);
1214                 glDeleteTextures(1, &frame.tid);
1215             }
1216         }
1217     }
1218 
1219     return true;
1220 }
1221 
processDisplayEvents()1222 void BootAnimation::processDisplayEvents() {
1223     // This will poll mDisplayEventReceiver and if there are new events it'll call
1224     // displayEventCallback synchronously.
1225     mLooper->pollOnce(0);
1226 }
1227 
handleViewport(nsecs_t timestep)1228 void BootAnimation::handleViewport(nsecs_t timestep) {
1229     if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) {
1230         return;
1231     }
1232     if (mTargetInset < 0) {
1233         // Poll the amount for the top display inset. This will return -1 until persistent properties
1234         // have been loaded.
1235         mTargetInset = android::base::GetIntProperty("persist.sys.displayinset.top",
1236                 -1 /* default */, -1 /* min */, mHeight / 2 /* max */);
1237     }
1238     if (mTargetInset <= 0) {
1239         return;
1240     }
1241 
1242     if (mCurrentInset < mTargetInset) {
1243         // After the device boots, the inset will effectively be cropped away. We animate this here.
1244         float fraction = static_cast<float>(mCurrentInset) / mTargetInset;
1245         int interpolatedInset = (cosf((fraction + 1) * M_PI) / 2.0f + 0.5f) * mTargetInset;
1246 
1247         SurfaceComposerClient::Transaction()
1248                 .setCrop(mFlingerSurfaceControl, Rect(0, interpolatedInset, mWidth, mHeight))
1249                 .apply();
1250     } else {
1251         // At the end of the animation, we switch to the viewport that DisplayManager will apply
1252         // later. This changes the coordinate system, and means we must move the surface up by
1253         // the inset amount.
1254         Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset);
1255         Rect displayRect(0, mTargetInset, mWidth, mHeight);
1256 
1257         SurfaceComposerClient::Transaction t;
1258         t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset)
1259                 .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight));
1260         t.setDisplayProjection(mDisplayToken, ui::ROTATION_0, layerStackRect, displayRect);
1261         t.apply();
1262 
1263         mTargetInset = mCurrentInset = 0;
1264     }
1265 
1266     int delta = timestep * mTargetInset / ms2ns(200);
1267     mCurrentInset += delta;
1268 }
1269 
releaseAnimation(Animation * animation) const1270 void BootAnimation::releaseAnimation(Animation* animation) const {
1271     for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
1272          e = animation->parts.end(); it != e; ++it) {
1273         if (it->animation)
1274             releaseAnimation(it->animation);
1275     }
1276     if (animation->zip)
1277         delete animation->zip;
1278     delete animation;
1279 }
1280 
loadAnimation(const String8 & fn)1281 BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) {
1282     if (mLoadedFiles.indexOf(fn) >= 0) {
1283         SLOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
1284             fn.string());
1285         return nullptr;
1286     }
1287     ZipFileRO *zip = ZipFileRO::open(fn);
1288     if (zip == nullptr) {
1289         SLOGE("Failed to open animation zip \"%s\": %s",
1290             fn.string(), strerror(errno));
1291         return nullptr;
1292     }
1293 
1294     Animation *animation =  new Animation;
1295     animation->fileName = fn;
1296     animation->zip = zip;
1297     animation->clockFont.map = nullptr;
1298     mLoadedFiles.add(animation->fileName);
1299 
1300     parseAnimationDesc(*animation);
1301     if (!preloadZip(*animation)) {
1302         releaseAnimation(animation);
1303         return nullptr;
1304     }
1305 
1306     mLoadedFiles.remove(fn);
1307     return animation;
1308 }
1309 
updateIsTimeAccurate()1310 bool BootAnimation::updateIsTimeAccurate() {
1311     static constexpr long long MAX_TIME_IN_PAST =   60000LL * 60LL * 24LL * 30LL;  // 30 days
1312     static constexpr long long MAX_TIME_IN_FUTURE = 60000LL * 90LL;  // 90 minutes
1313 
1314     if (mTimeIsAccurate) {
1315         return true;
1316     }
1317     if (mShuttingDown) return true;
1318     struct stat statResult;
1319 
1320     if(stat(TIME_FORMAT_12_HOUR_FLAG_FILE_PATH, &statResult) == 0) {
1321         mTimeFormat12Hour = true;
1322     }
1323 
1324     if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) {
1325         mTimeIsAccurate = true;
1326         return true;
1327     }
1328 
1329     FILE* file = fopen(LAST_TIME_CHANGED_FILE_PATH, "r");
1330     if (file != nullptr) {
1331       long long lastChangedTime = 0;
1332       fscanf(file, "%lld", &lastChangedTime);
1333       fclose(file);
1334       if (lastChangedTime > 0) {
1335         struct timespec now;
1336         clock_gettime(CLOCK_REALTIME, &now);
1337         // Match the Java timestamp format
1338         long long rtcNow = (now.tv_sec * 1000LL) + (now.tv_nsec / 1000000LL);
1339         if (ACCURATE_TIME_EPOCH < rtcNow
1340             && lastChangedTime > (rtcNow - MAX_TIME_IN_PAST)
1341             && lastChangedTime < (rtcNow + MAX_TIME_IN_FUTURE)) {
1342             mTimeIsAccurate = true;
1343         }
1344       }
1345     }
1346 
1347     return mTimeIsAccurate;
1348 }
1349 
TimeCheckThread(BootAnimation * bootAnimation)1350 BootAnimation::TimeCheckThread::TimeCheckThread(BootAnimation* bootAnimation) : Thread(false),
1351     mInotifyFd(-1), mSystemWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
1352 
~TimeCheckThread()1353 BootAnimation::TimeCheckThread::~TimeCheckThread() {
1354     // mInotifyFd may be -1 but that's ok since we're not at risk of attempting to close a valid FD.
1355     close(mInotifyFd);
1356 }
1357 
threadLoop()1358 bool BootAnimation::TimeCheckThread::threadLoop() {
1359     bool shouldLoop = doThreadLoop() && !mBootAnimation->mTimeIsAccurate
1360         && mBootAnimation->mClockEnabled;
1361     if (!shouldLoop) {
1362         close(mInotifyFd);
1363         mInotifyFd = -1;
1364     }
1365     return shouldLoop;
1366 }
1367 
doThreadLoop()1368 bool BootAnimation::TimeCheckThread::doThreadLoop() {
1369     static constexpr int BUFF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1));
1370 
1371     // Poll instead of doing a blocking read so the Thread can exit if requested.
1372     struct pollfd pfd = { mInotifyFd, POLLIN, 0 };
1373     ssize_t pollResult = poll(&pfd, 1, 1000);
1374 
1375     if (pollResult == 0) {
1376         return true;
1377     } else if (pollResult < 0) {
1378         SLOGE("Could not poll inotify events");
1379         return false;
1380     }
1381 
1382     char buff[BUFF_LEN] __attribute__ ((aligned(__alignof__(struct inotify_event))));;
1383     ssize_t length = read(mInotifyFd, buff, BUFF_LEN);
1384     if (length == 0) {
1385         return true;
1386     } else if (length < 0) {
1387         SLOGE("Could not read inotify events");
1388         return false;
1389     }
1390 
1391     const struct inotify_event *event;
1392     for (char* ptr = buff; ptr < buff + length; ptr += sizeof(struct inotify_event) + event->len) {
1393         event = (const struct inotify_event *) ptr;
1394         if (event->wd == mSystemWd && strcmp(SYSTEM_TIME_DIR_NAME, event->name) == 0) {
1395             addTimeDirWatch();
1396         } else if (event->wd == mTimeWd && (strcmp(LAST_TIME_CHANGED_FILE_NAME, event->name) == 0
1397                 || strcmp(ACCURATE_TIME_FLAG_FILE_NAME, event->name) == 0)) {
1398             return !mBootAnimation->updateIsTimeAccurate();
1399         }
1400     }
1401 
1402     return true;
1403 }
1404 
addTimeDirWatch()1405 void BootAnimation::TimeCheckThread::addTimeDirWatch() {
1406         mTimeWd = inotify_add_watch(mInotifyFd, SYSTEM_TIME_DIR_PATH,
1407                 IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB);
1408         if (mTimeWd > 0) {
1409             // No need to watch for the time directory to be created if it already exists
1410             inotify_rm_watch(mInotifyFd, mSystemWd);
1411             mSystemWd = -1;
1412         }
1413 }
1414 
readyToRun()1415 status_t BootAnimation::TimeCheckThread::readyToRun() {
1416     mInotifyFd = inotify_init();
1417     if (mInotifyFd < 0) {
1418         SLOGE("Could not initialize inotify fd");
1419         return NO_INIT;
1420     }
1421 
1422     mSystemWd = inotify_add_watch(mInotifyFd, SYSTEM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
1423     if (mSystemWd < 0) {
1424         close(mInotifyFd);
1425         mInotifyFd = -1;
1426         SLOGE("Could not add watch for %s: %s", SYSTEM_DATA_DIR_PATH, strerror(errno));
1427         return NO_INIT;
1428     }
1429 
1430     addTimeDirWatch();
1431 
1432     if (mBootAnimation->updateIsTimeAccurate()) {
1433         close(mInotifyFd);
1434         mInotifyFd = -1;
1435         return ALREADY_EXISTS;
1436     }
1437 
1438     return NO_ERROR;
1439 }
1440 
1441 // ---------------------------------------------------------------------------
1442 
1443 } // namespace android
1444