diff options
Diffstat (limited to 'chromium/content')
150 files changed, 1663 insertions, 331 deletions
diff --git a/chromium/content/app/strings/translations/content_strings_am.xtb b/chromium/content/app/strings/translations/content_strings_am.xtb index 9ea13ab9040..4000a06bde5 100644 --- a/chromium/content/app/strings/translations/content_strings_am.xtb +++ b/chromium/content/app/strings/translations/content_strings_am.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">የምናሌ አዝራር</translation> <translation id="4446524499724042288">የሙዳየ ቃላት ዋቢ</translation> <translation id="4522570452068850558">ዝርዝሮች</translation> +<translation id="4542388879936266156">ቀሪ ጊዜ፦ <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">ቅጽ</translation> <translation id="4661075872484491155">ዛፍ</translation> <translation id="4664250907885839816">ከ«<ph name="ATSIGN" />» በኋላ የሚመጣ ክፍል የ«<ph name="INVALIDCHARACTER" />» ምልክት መያዝ የለበትም።</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">ዓዓዓዓ</translation> <translation id="8284326494547611709">መግለጫ ጽሑፎች</translation> <translation id="835897206747267392">ልክ ያልሆነ እሴት።</translation> +<translation id="8403857369060869934">ያለፈው ጊዜ፦ <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">ክፍለ አካል</translation> <translation id="8433900881053900389">የመሣሪያ አሞሌ</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> ፋይሎች</translation> diff --git a/chromium/content/app/strings/translations/content_strings_ar.xtb b/chromium/content/app/strings/translations/content_strings_ar.xtb index ab4f8eade1b..d4aa6aff188 100644 --- a/chromium/content/app/strings/translations/content_strings_ar.xtb +++ b/chromium/content/app/strings/translations/content_strings_ar.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">زر القائمة</translation> <translation id="4446524499724042288">مرجع مسرد مصطلحات</translation> <translation id="4522570452068850558">التفاصيل</translation> +<translation id="4542388879936266156">الوقت المتبقي: <ph name="REMAINING_TIME" />ّ</translation> <translation id="4597532268155981612">نموذج</translation> <translation id="4661075872484491155">متفرع</translation> <translation id="4664250907885839816">يجب ألا يشتمل الجزء الذي يلي العلامة "<ph name="ATSIGN" />" على الرمز "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">سنة</translation> <translation id="8284326494547611709">الترجمة والشرح</translation> <translation id="835897206747267392">قيمة غير صحيحة</translation> +<translation id="8403857369060869934">الوقت المنقضي: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">جزء</translation> <translation id="8433900881053900389">شريط الأدوات</translation> <translation id="8444882422881193423">عدد الملفات: <ph name="NUMBER_OF_FILES" /></translation> diff --git a/chromium/content/app/strings/translations/content_strings_bg.xtb b/chromium/content/app/strings/translations/content_strings_bg.xtb index af5c981a911..30de99754f1 100644 --- a/chromium/content/app/strings/translations/content_strings_bg.xtb +++ b/chromium/content/app/strings/translations/content_strings_bg.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">бутон за меню</translation> <translation id="4446524499724042288">препратка към определение в терминологичния речник</translation> <translation id="4522570452068850558">Подробности</translation> +<translation id="4542388879936266156">оставащо време: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">формуляр</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Текстът след „<ph name="ATSIGN" />“ не бива да съдържа символа „<ph name="INVALIDCHARACTER" />“.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">гггг</translation> <translation id="8284326494547611709">Надписи</translation> <translation id="835897206747267392">Невалидна стойност.</translation> +<translation id="8403857369060869934">изминало време: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">част</translation> <translation id="8433900881053900389">лента с инструменти</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> файла</translation> diff --git a/chromium/content/app/strings/translations/content_strings_bn.xtb b/chromium/content/app/strings/translations/content_strings_bn.xtb index 1687769f998..86895e57762 100644 --- a/chromium/content/app/strings/translations/content_strings_bn.xtb +++ b/chromium/content/app/strings/translations/content_strings_bn.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">মেনু বোতাম</translation> <translation id="4446524499724042288">শব্দকোষের রেফারেন্স</translation> <translation id="4522570452068850558">বিশদ বিবরণ</translation> +<translation id="4542388879936266156">বাকি সময়: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">ফর্ম</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">'<ph name="ATSIGN" />' অনুসরণ করে এমন একটি অংশে '<ph name="INVALIDCHARACTER" />' চিহ্ন থাকা উচিত নয়৷</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">পরিচয়লিপিগুলি</translation> <translation id="835897206747267392">অকার্যকর মান৷</translation> +<translation id="8403857369060869934">অতিবাহিত সময়: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">অংশ</translation> <translation id="8433900881053900389">টুল দণ্ড</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> টি ফাইল</translation> diff --git a/chromium/content/app/strings/translations/content_strings_ca.xtb b/chromium/content/app/strings/translations/content_strings_ca.xtb index b87d799eee0..92f873ba250 100644 --- a/chromium/content/app/strings/translations/content_strings_ca.xtb +++ b/chromium/content/app/strings/translations/content_strings_ca.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">botó de menú</translation> <translation id="4446524499724042288">referència del glossari</translation> <translation id="4522570452068850558">Detalls</translation> +<translation id="4542388879936266156">temps restant: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulari</translation> <translation id="4661075872484491155">arbre</translation> <translation id="4664250907885839816">Un domini precedit per "<ph name="ATSIGN" />" no pot contenir el símbol "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">aaaa</translation> <translation id="8284326494547611709">Subtítols</translation> <translation id="835897206747267392">Valor no vàlid.</translation> +<translation id="8403857369060869934">temps transcorregut: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">part</translation> <translation id="8433900881053900389">barra d'eines</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> fitxers</translation> diff --git a/chromium/content/app/strings/translations/content_strings_cs.xtb b/chromium/content/app/strings/translations/content_strings_cs.xtb index fa16a1c0f6b..542a503a1bc 100644 --- a/chromium/content/app/strings/translations/content_strings_cs.xtb +++ b/chromium/content/app/strings/translations/content_strings_cs.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">tlačítko nabídky</translation> <translation id="4446524499724042288">odkaz na glosář</translation> <translation id="4522570452068850558">Podrobnosti</translation> +<translation id="4542388879936266156">zbývající čas: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulář</translation> <translation id="4661075872484491155">strom</translation> <translation id="4664250907885839816">Část za znakem <ph name="ATSIGN" /> nesmí obsahovat znak <ph name="INVALIDCHARACTER" />.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">rrrr</translation> <translation id="8284326494547611709">Titulky</translation> <translation id="835897206747267392">Neplatná hodnota.</translation> +<translation id="8403857369060869934">uplynulý čas: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">část</translation> <translation id="8433900881053900389">lišta</translation> <translation id="8444882422881193423">Počet souborů: <ph name="NUMBER_OF_FILES" /></translation> diff --git a/chromium/content/app/strings/translations/content_strings_da.xtb b/chromium/content/app/strings/translations/content_strings_da.xtb index eb2a102da33..c735c9027fd 100644 --- a/chromium/content/app/strings/translations/content_strings_da.xtb +++ b/chromium/content/app/strings/translations/content_strings_da.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">menuknap</translation> <translation id="4446524499724042288">reference på ordliste</translation> <translation id="4522570452068850558">Detaljer</translation> +<translation id="4542388879936266156">resterende tid: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formular</translation> <translation id="4661075872484491155">træ</translation> <translation id="4664250907885839816">Den del, der kommer efter "<ph name="ATSIGN" />", må ikke indeholde symbolet "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">åååå</translation> <translation id="8284326494547611709">Undertekster</translation> <translation id="835897206747267392">Ugyldig værdi.</translation> +<translation id="8403857369060869934">forløbet tid: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">del</translation> <translation id="8433900881053900389">værktøjslinje</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> filer</translation> @@ -228,7 +230,7 @@ <translation id="9093215626363556771">afslut integreret billede</translation> <translation id="9108370397979208512">matematik</translation> <translation id="9132465097189459683">Andet...</translation> -<translation id="9138385573473225930">notifikation</translation> +<translation id="9138385573473225930">underretning</translation> <translation id="9155987714137265666"><ph name="WEEK" />, med start <ph name="WEEK_START_DATE" /></translation> <translation id="916607977885256133">Integreret billede</translation> <translation id="9168329111483466115">fodnote</translation> diff --git a/chromium/content/app/strings/translations/content_strings_de.xtb b/chromium/content/app/strings/translations/content_strings_de.xtb index 69a5d5d16bd..93e92a107bc 100644 --- a/chromium/content/app/strings/translations/content_strings_de.xtb +++ b/chromium/content/app/strings/translations/content_strings_de.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">Menüschaltfläche</translation> <translation id="4446524499724042288">Glossarreferenz</translation> <translation id="4522570452068850558">Details</translation> +<translation id="4542388879936266156">verbleibende Zeit: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">Formular</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Nach dem <ph name="ATSIGN" />-Zeichen darf das Zeichen "<ph name="INVALIDCHARACTER" />" nicht verwendet werden.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">jjjj</translation> <translation id="8284326494547611709">Untertitel</translation> <translation id="835897206747267392">Ungültiger Wert.</translation> +<translation id="8403857369060869934">verstrichene Zeit: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">Teil</translation> <translation id="8433900881053900389">Symbolleiste</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> Dateien</translation> diff --git a/chromium/content/app/strings/translations/content_strings_el.xtb b/chromium/content/app/strings/translations/content_strings_el.xtb index 4793b07f2cf..33061048c2a 100644 --- a/chromium/content/app/strings/translations/content_strings_el.xtb +++ b/chromium/content/app/strings/translations/content_strings_el.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">κουμπί μενού</translation> <translation id="4446524499724042288">αναφορά στο γλωσσάρι</translation> <translation id="4522570452068850558">Λεπτομέρειες</translation> +<translation id="4542388879936266156">χρόνος που απομένει: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">φόρμα</translation> <translation id="4661075872484491155">δέντρο</translation> <translation id="4664250907885839816">Το τμήμα της διεύθυνσης μετά το σύμβολο "<ph name="ATSIGN" />" δεν πρέπει να περιέχει το σύμβολο "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">εεεε</translation> <translation id="8284326494547611709">Υπότιτλοι</translation> <translation id="835897206747267392">Μη έγκυρη τιμή.</translation> +<translation id="8403857369060869934">χρόνος που παρήλθε: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">τμήμα</translation> <translation id="8433900881053900389">γραμμή εργαλείων</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> αρχεία</translation> diff --git a/chromium/content/app/strings/translations/content_strings_en-GB.xtb b/chromium/content/app/strings/translations/content_strings_en-GB.xtb index f8251cd02fc..c1ce0d6f28f 100644 --- a/chromium/content/app/strings/translations/content_strings_en-GB.xtb +++ b/chromium/content/app/strings/translations/content_strings_en-GB.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">menu button</translation> <translation id="4446524499724042288">glossary reference</translation> <translation id="4522570452068850558">Details</translation> +<translation id="4542388879936266156">remaining time: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">form</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">A part following '<ph name="ATSIGN" />' should not contain the symbol '<ph name="INVALIDCHARACTER" />'.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">Captions</translation> <translation id="835897206747267392">Invalid value.</translation> +<translation id="8403857369060869934">elapsed time: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">part</translation> <translation id="8433900881053900389">toolbar</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> files</translation> diff --git a/chromium/content/app/strings/translations/content_strings_es-419.xtb b/chromium/content/app/strings/translations/content_strings_es-419.xtb index ac519857f9d..781b4382137 100644 --- a/chromium/content/app/strings/translations/content_strings_es-419.xtb +++ b/chromium/content/app/strings/translations/content_strings_es-419.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">botón de menú</translation> <translation id="4446524499724042288">referencia de glosario</translation> <translation id="4522570452068850558">Detalles</translation> +<translation id="4542388879936266156">tiempo restante: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulario</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">El texto después del signo "<ph name="ATSIGN" />" no debe incluir el símbolo "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">aaaa</translation> <translation id="8284326494547611709">Subtítulos</translation> <translation id="835897206747267392">Valor no válido.</translation> +<translation id="8403857369060869934">tiempo transcurrido: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">parte</translation> <translation id="8433900881053900389">barra de herramientas</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> archivos</translation> diff --git a/chromium/content/app/strings/translations/content_strings_es.xtb b/chromium/content/app/strings/translations/content_strings_es.xtb index fe448681d7c..9bf9370b387 100644 --- a/chromium/content/app/strings/translations/content_strings_es.xtb +++ b/chromium/content/app/strings/translations/content_strings_es.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">botón de menú</translation> <translation id="4446524499724042288">referencia de glosario</translation> <translation id="4522570452068850558">Detalles</translation> +<translation id="4542388879936266156">tiempo restante: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulario</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">El texto detrás del signo "<ph name="ATSIGN" />" no debe incluir el símbolo "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">aaaa</translation> <translation id="8284326494547611709">Subtítulos</translation> <translation id="835897206747267392">Valor no válido</translation> +<translation id="8403857369060869934">tiempo transcurrido: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">parte</translation> <translation id="8433900881053900389">barra de herramientas</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> archivos</translation> diff --git a/chromium/content/app/strings/translations/content_strings_et.xtb b/chromium/content/app/strings/translations/content_strings_et.xtb index 70aa8ad210e..101bee26ab3 100644 --- a/chromium/content/app/strings/translations/content_strings_et.xtb +++ b/chromium/content/app/strings/translations/content_strings_et.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">menüünupp</translation> <translation id="4446524499724042288">sõnastiku viide</translation> <translation id="4522570452068850558">Üksikasjad</translation> +<translation id="4542388879936266156">järelejäänud aeg: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">vorm</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Märgile „<ph name="ATSIGN" />” järgnev osa ei tohi sisaldada sümbolit „<ph name="INVALIDCHARACTER" />”.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">aaaa</translation> <translation id="8284326494547611709">Subtiitrid</translation> <translation id="835897206747267392">Kehtetu väärtus.</translation> +<translation id="8403857369060869934">möödunud aeg: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">osa</translation> <translation id="8433900881053900389">tööriistariba</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> faili</translation> diff --git a/chromium/content/app/strings/translations/content_strings_fa.xtb b/chromium/content/app/strings/translations/content_strings_fa.xtb index 53b474df401..75bd1385b31 100644 --- a/chromium/content/app/strings/translations/content_strings_fa.xtb +++ b/chromium/content/app/strings/translations/content_strings_fa.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">دکمه منو</translation> <translation id="4446524499724042288">مرجع واژهنامه</translation> <translation id="4522570452068850558">جزئیات</translation> +<translation id="4542388879936266156">زمان باقیمانده: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">فرم</translation> <translation id="4661075872484491155">درخت</translation> <translation id="4664250907885839816">قسمت بعد از «<ph name="ATSIGN" />» نباید حاوی نماد «<ph name="INVALIDCHARACTER" />» باشد.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">زیرنویسها</translation> <translation id="835897206747267392">مقدار نامعتبر.</translation> +<translation id="8403857369060869934">زمان سپریشده: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">بخش</translation> <translation id="8433900881053900389">نوار ابزار</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> فایل</translation> diff --git a/chromium/content/app/strings/translations/content_strings_fi.xtb b/chromium/content/app/strings/translations/content_strings_fi.xtb index 6cdaa8c7f85..11cd70a5c54 100644 --- a/chromium/content/app/strings/translations/content_strings_fi.xtb +++ b/chromium/content/app/strings/translations/content_strings_fi.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">valikkopainike</translation> <translation id="4446524499724042288">sanastoviittaus</translation> <translation id="4522570452068850558">Tiedot</translation> +<translation id="4542388879936266156">jäljellä oleva aika: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">lomake</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816"><ph name="ATSIGN" />-osan jälkeen tulevassa osassa ei pitäisi olla merkkiä <ph name="INVALIDCHARACTER" />.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">vvvv</translation> <translation id="8284326494547611709">Tekstitykset</translation> <translation id="835897206747267392">Virheellinen arvo.</translation> +<translation id="8403857369060869934">kulunut aika: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">osa</translation> <translation id="8433900881053900389">työkalupalkki</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> tiedostoa</translation> diff --git a/chromium/content/app/strings/translations/content_strings_fil.xtb b/chromium/content/app/strings/translations/content_strings_fil.xtb index 1c21a25328e..efd20a92d3e 100644 --- a/chromium/content/app/strings/translations/content_strings_fil.xtb +++ b/chromium/content/app/strings/translations/content_strings_fil.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">button ng menu</translation> <translation id="4446524499724042288">sanggunian sa glosaryo</translation> <translation id="4522570452068850558">Mga Detalye</translation> +<translation id="4542388879936266156">natitirang oras: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">form</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Hindi dapat naglalaman ng simbolong '<ph name="INVALIDCHARACTER" />' ang bahagi pagkatapos ng '<ph name="ATSIGN" />.'</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">Mga Caption</translation> <translation id="835897206747267392">Di-wastong halaga.</translation> +<translation id="8403857369060869934">lumipas na oras: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">bahagi</translation> <translation id="8433900881053900389">toolbar</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> mga file</translation> diff --git a/chromium/content/app/strings/translations/content_strings_fr.xtb b/chromium/content/app/strings/translations/content_strings_fr.xtb index 4f04a9ecb40..7ec7829a373 100644 --- a/chromium/content/app/strings/translations/content_strings_fr.xtb +++ b/chromium/content/app/strings/translations/content_strings_fr.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">bouton de menu</translation> <translation id="4446524499724042288">référence de glossaire</translation> <translation id="4522570452068850558">Détails</translation> +<translation id="4542388879936266156">temps restant : <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulaire</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">La partie précédée du symbole "<ph name="ATSIGN" />" ne doit pas contenir le caractère "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">aaaa</translation> <translation id="8284326494547611709">Sous-titres</translation> <translation id="835897206747267392">Valeur incorrecte</translation> +<translation id="8403857369060869934">temps écoulé : <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">partie</translation> <translation id="8433900881053900389">barre d'outils</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> fichiers</translation> diff --git a/chromium/content/app/strings/translations/content_strings_gu.xtb b/chromium/content/app/strings/translations/content_strings_gu.xtb index dc4531c7421..bfe24a3853d 100644 --- a/chromium/content/app/strings/translations/content_strings_gu.xtb +++ b/chromium/content/app/strings/translations/content_strings_gu.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">મેનૂ બટન</translation> <translation id="4446524499724042288">શબ્દાવલીનો સંદર્ભ</translation> <translation id="4522570452068850558">વિગતો</translation> +<translation id="4542388879936266156">બાકીનો સમય: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">ફોર્મ</translation> <translation id="4661075872484491155">ટ્રી</translation> <translation id="4664250907885839816">'<ph name="ATSIGN" />' ને અનુસરી રહેલા ભાગમાં '<ph name="INVALIDCHARACTER" />' પ્રતીક શામેલ હોવું જોઈએ નહીં.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">કૅપ્શન્સ</translation> <translation id="835897206747267392">અમાન્ય મૂલ્ય.</translation> +<translation id="8403857369060869934">વીતેલો સમય: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">ભાગ</translation> <translation id="8433900881053900389">ટુલબાર</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> ફાઇલો</translation> diff --git a/chromium/content/app/strings/translations/content_strings_hi.xtb b/chromium/content/app/strings/translations/content_strings_hi.xtb index aad00a6c335..22e9a254ed4 100644 --- a/chromium/content/app/strings/translations/content_strings_hi.xtb +++ b/chromium/content/app/strings/translations/content_strings_hi.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">मेनू बटन</translation> <translation id="4446524499724042288">संदर्भ के लिए शब्दावली</translation> <translation id="4522570452068850558">विवरण</translation> +<translation id="4542388879936266156">बचा हुआ समय: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">फ़ॉर्म</translation> <translation id="4661075872484491155">ट्री</translation> <translation id="4664250907885839816">'<ph name="ATSIGN" />' के बाद आने वाले भाग में '<ph name="INVALIDCHARACTER" />' प्रतीक शामिल नहीं होना चाहिए.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">कैप्शन</translation> <translation id="835897206747267392">अमान्य मान.</translation> +<translation id="8403857369060869934">बीता हुआ समय: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">भाग</translation> <translation id="8433900881053900389">टूलबार</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> फ़ाइल</translation> diff --git a/chromium/content/app/strings/translations/content_strings_hr.xtb b/chromium/content/app/strings/translations/content_strings_hr.xtb index 3107c0c4479..21756243dcf 100644 --- a/chromium/content/app/strings/translations/content_strings_hr.xtb +++ b/chromium/content/app/strings/translations/content_strings_hr.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">gumb izbornika</translation> <translation id="4446524499724042288">referenca iz pojmovnika</translation> <translation id="4522570452068850558">Detalji</translation> +<translation id="4542388879936266156">preostalo vrijeme: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">obrazac</translation> <translation id="4661075872484491155">stablo</translation> <translation id="4664250907885839816">Dio adrese iza znaka "<ph name="ATSIGN" />" ne smije sadržavati simbol "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">gggg</translation> <translation id="8284326494547611709">Titlovi</translation> <translation id="835897206747267392">Nevažeća vrijednost.</translation> +<translation id="8403857369060869934">proteklo vrijeme: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">dio</translation> <translation id="8433900881053900389">alatna traka</translation> <translation id="8444882422881193423">Broj datoteka: <ph name="NUMBER_OF_FILES" /></translation> diff --git a/chromium/content/app/strings/translations/content_strings_hu.xtb b/chromium/content/app/strings/translations/content_strings_hu.xtb index c684f56d7b3..f2acce03ceb 100644 --- a/chromium/content/app/strings/translations/content_strings_hu.xtb +++ b/chromium/content/app/strings/translations/content_strings_hu.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">menügomb</translation> <translation id="4446524499724042288">szószedet-hivatkozás</translation> <translation id="4522570452068850558">Részletek</translation> +<translation id="4542388879936266156">hátralévő idő: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">űrlap</translation> <translation id="4661075872484491155">fa</translation> <translation id="4664250907885839816">A „<ph name="ATSIGN" />” utáni rész nem tartalmazhat „<ph name="INVALIDCHARACTER" />” karaktert.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">éééé</translation> <translation id="8284326494547611709">Feliratok</translation> <translation id="835897206747267392">Érvénytelen érték.</translation> +<translation id="8403857369060869934">eltelt idő: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">rész</translation> <translation id="8433900881053900389">eszköztár</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> fájl</translation> diff --git a/chromium/content/app/strings/translations/content_strings_id.xtb b/chromium/content/app/strings/translations/content_strings_id.xtb index 1ca7cdf0705..73428820683 100644 --- a/chromium/content/app/strings/translations/content_strings_id.xtb +++ b/chromium/content/app/strings/translations/content_strings_id.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">tombol menu</translation> <translation id="4446524499724042288">referensi glosarium</translation> <translation id="4522570452068850558">Detail</translation> +<translation id="4542388879936266156">sisa waktu: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulir</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Bagian setelah '<ph name="ATSIGN" />' tidak boleh berisi simbol '<ph name="INVALIDCHARACTER" />'.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">tttt</translation> <translation id="8284326494547611709">Teks</translation> <translation id="835897206747267392">Nilai tidak valid.</translation> +<translation id="8403857369060869934">waktu berlalu: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">bagian</translation> <translation id="8433900881053900389">bilah alat</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> file</translation> diff --git a/chromium/content/app/strings/translations/content_strings_it.xtb b/chromium/content/app/strings/translations/content_strings_it.xtb index 14f37b6c814..52129365de0 100644 --- a/chromium/content/app/strings/translations/content_strings_it.xtb +++ b/chromium/content/app/strings/translations/content_strings_it.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">pulsante di menu</translation> <translation id="4446524499724042288">riferimento glossario</translation> <translation id="4522570452068850558">Dettagli</translation> +<translation id="4542388879936266156">Tempo rimanente: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">modulo</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Una parte che segue "<ph name="ATSIGN" />" non deve contenere il simbolo "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">aaaa</translation> <translation id="8284326494547611709">Sottotitoli</translation> <translation id="835897206747267392">Valore non valido.</translation> +<translation id="8403857369060869934">Tempo trascorso: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">parte</translation> <translation id="8433900881053900389">barra degli strumenti</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> file</translation> diff --git a/chromium/content/app/strings/translations/content_strings_iw.xtb b/chromium/content/app/strings/translations/content_strings_iw.xtb index 19117ec8609..a35f142a085 100644 --- a/chromium/content/app/strings/translations/content_strings_iw.xtb +++ b/chromium/content/app/strings/translations/content_strings_iw.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">לחצן תפריט</translation> <translation id="4446524499724042288">הפניה למילון מונחים</translation> <translation id="4522570452068850558">פרטים</translation> +<translation id="4542388879936266156">הזמן שנותר: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">טופס</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">חלק ולאחריו '<ph name="ATSIGN" />' לא אמור לכלול את הסמל '<ph name="INVALIDCHARACTER" />'.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">כתוביות</translation> <translation id="835897206747267392">ערך לא חוקי.</translation> +<translation id="8403857369060869934">הזמן שחלף: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">חלק</translation> <translation id="8433900881053900389">סרגל כלים</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> קבצים</translation> diff --git a/chromium/content/app/strings/translations/content_strings_ja.xtb b/chromium/content/app/strings/translations/content_strings_ja.xtb index f3088626ed0..1996f553d5f 100644 --- a/chromium/content/app/strings/translations/content_strings_ja.xtb +++ b/chromium/content/app/strings/translations/content_strings_ja.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">メニューボタン</translation> <translation id="4446524499724042288">用語参照</translation> <translation id="4522570452068850558">詳細</translation> +<translation id="4542388879936266156">残り時間: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">フォーム</translation> <translation id="4661075872484491155">ツリー</translation> <translation id="4664250907885839816">「<ph name="ATSIGN" />」に続く文字列に記号「<ph name="INVALIDCHARACTER" />」を使用しないでください。</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405"> 年 </translation> <translation id="8284326494547611709">字幕</translation> <translation id="835897206747267392">値が無効です。</translation> +<translation id="8403857369060869934">経過時間: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">部</translation> <translation id="8433900881053900389">ツールバー</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> ファイル</translation> diff --git a/chromium/content/app/strings/translations/content_strings_kn.xtb b/chromium/content/app/strings/translations/content_strings_kn.xtb index 45a2c335671..9d29ffd1b94 100644 --- a/chromium/content/app/strings/translations/content_strings_kn.xtb +++ b/chromium/content/app/strings/translations/content_strings_kn.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">ಮೆನು ಬಟನ್</translation> <translation id="4446524499724042288">ಪದಕೋಶ ಉಲ್ಲೇಖ</translation> <translation id="4522570452068850558">ವಿವರಗಳು</translation> +<translation id="4542388879936266156">ಬಾಕಿ ಉಳಿದಿರುವ ಸಮಯ: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">ಫಾರ್ಮ್</translation> <translation id="4661075872484491155">ಮರ</translation> <translation id="4664250907885839816">'<ph name="ATSIGN" />' ನಂತರದ ಭಾಗವು '<ph name="INVALIDCHARACTER" />' ಚಿಹ್ನೆಯನ್ನು ಒಳಗೊಂಡಿರಬಾರದು.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">ವವವವ</translation> <translation id="8284326494547611709">ಶೀರ್ಷಿಕೆಗಳು</translation> <translation id="835897206747267392">ಅಮಾನ್ಯ ಮೌಲ್ಯ.</translation> +<translation id="8403857369060869934">ಕಳೆದುಹೋದ ಸಮಯ: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">ಭಾಗ</translation> <translation id="8433900881053900389">ಟೂಲ್ಬಾರ್</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> ಫೈಲ್ಗಳು</translation> diff --git a/chromium/content/app/strings/translations/content_strings_ko.xtb b/chromium/content/app/strings/translations/content_strings_ko.xtb index 289e7f4ff30..6133baf54eb 100644 --- a/chromium/content/app/strings/translations/content_strings_ko.xtb +++ b/chromium/content/app/strings/translations/content_strings_ko.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">메뉴 버튼</translation> <translation id="4446524499724042288">용어 참조</translation> <translation id="4522570452068850558">세부정보</translation> +<translation id="4542388879936266156">남은 시간: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">양식</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">'<ph name="ATSIGN" />' 다음 부분에 '<ph name="INVALIDCHARACTER" />' 기호가 포함되면 안됩니다.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">연도</translation> <translation id="8284326494547611709">자막</translation> <translation id="835897206747267392">값이 잘못되었습니다.</translation> +<translation id="8403857369060869934">경과 시간: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">부</translation> <translation id="8433900881053900389">툴바</translation> <translation id="8444882422881193423">파일 <ph name="NUMBER_OF_FILES" />개</translation> diff --git a/chromium/content/app/strings/translations/content_strings_lt.xtb b/chromium/content/app/strings/translations/content_strings_lt.xtb index fba7f297325..c354878208d 100644 --- a/chromium/content/app/strings/translations/content_strings_lt.xtb +++ b/chromium/content/app/strings/translations/content_strings_lt.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">meniu mygtukas</translation> <translation id="4446524499724042288">aiškinamojo terminų žodyno nuoroda</translation> <translation id="4522570452068850558">Išsami informacija</translation> +<translation id="4542388879936266156">likęs laikas: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">forma</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Po „<ph name="ATSIGN" />“ esančioje dalyje neturėtų būti simbolio „<ph name="INVALIDCHARACTER" />“.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">mmmm</translation> <translation id="8284326494547611709">Subtitrai</translation> <translation id="835897206747267392">Neteisinga vertė.</translation> +<translation id="8403857369060869934">praėjęs laikas: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">dalis</translation> <translation id="8433900881053900389">įrankių juosta</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> failai (-ų)</translation> diff --git a/chromium/content/app/strings/translations/content_strings_lv.xtb b/chromium/content/app/strings/translations/content_strings_lv.xtb index b4ebbac28d6..8902dff3cac 100644 --- a/chromium/content/app/strings/translations/content_strings_lv.xtb +++ b/chromium/content/app/strings/translations/content_strings_lv.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">izvēlnes poga</translation> <translation id="4446524499724042288">atsauce uz glosāriju</translation> <translation id="4522570452068850558">Informācija</translation> +<translation id="4542388879936266156">atlikušais laiks: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">veidlapa</translation> <translation id="4661075872484491155">koks</translation> <translation id="4664250907885839816">Daļā, kas atrodas aiz zīmes <ph name="ATSIGN" />, nedrīkst būt ietverts simbols <ph name="INVALIDCHARACTER" />.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">gggg</translation> <translation id="8284326494547611709">Paraksti</translation> <translation id="835897206747267392">Nederīga vērtība.</translation> +<translation id="8403857369060869934">pagājušais laiks: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">daļa</translation> <translation id="8433900881053900389">rīkjosla</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> faili</translation> diff --git a/chromium/content/app/strings/translations/content_strings_ml.xtb b/chromium/content/app/strings/translations/content_strings_ml.xtb index 66a7cf9e342..ce5fa4e2a5f 100644 --- a/chromium/content/app/strings/translations/content_strings_ml.xtb +++ b/chromium/content/app/strings/translations/content_strings_ml.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">മെനു ബട്ടൺ</translation> <translation id="4446524499724042288">പദസഞ്ചയ റെഫറൻസ്</translation> <translation id="4522570452068850558">വിശദാംശങ്ങൾ</translation> +<translation id="4542388879936266156">അവശേഷിക്കുന്ന സമയം: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">ഫോം</translation> <translation id="4661075872484491155">ട്രീ</translation> <translation id="4664250907885839816">'<ph name="ATSIGN" />' എന്നതിനുശേഷം വരുന്ന ഭാഗത്തിൽ '<ph name="INVALIDCHARACTER" />' ചിഹ്നം ഉണ്ടാകരുത്.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">വർഷം</translation> <translation id="8284326494547611709">അടിക്കുറിപ്പുകൾ</translation> <translation id="835897206747267392">അസാധുവായ മൂല്യം.</translation> +<translation id="8403857369060869934">കഴിഞ്ഞ സമയം: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">ഭാഗം</translation> <translation id="8433900881053900389">ടൂൾബാർ</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> ഫയലുകള്</translation> diff --git a/chromium/content/app/strings/translations/content_strings_mr.xtb b/chromium/content/app/strings/translations/content_strings_mr.xtb index 2e1d4935a66..c4ad1897491 100644 --- a/chromium/content/app/strings/translations/content_strings_mr.xtb +++ b/chromium/content/app/strings/translations/content_strings_mr.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">मेनू बटण</translation> <translation id="4446524499724042288">शब्दावली संदर्भ</translation> <translation id="4522570452068850558">तपशील</translation> +<translation id="4542388879936266156">शिल्लक वेळ: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">फॉर्म</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">'<ph name="ATSIGN" />' चे फॉलो करणार्या भागामध्ये '<ph name="INVALIDCHARACTER" />' चिन्ह नसावे.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">मथळे</translation> <translation id="835897206747267392">चुकीचे मूल्य.</translation> +<translation id="8403857369060869934">गेलेला वेळ: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">भाग</translation> <translation id="8433900881053900389">टूलबार</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> फायली</translation> diff --git a/chromium/content/app/strings/translations/content_strings_ms.xtb b/chromium/content/app/strings/translations/content_strings_ms.xtb index d9eafeebd85..cd9cc99fc62 100644 --- a/chromium/content/app/strings/translations/content_strings_ms.xtb +++ b/chromium/content/app/strings/translations/content_strings_ms.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">butang menu</translation> <translation id="4446524499724042288">rujukan glosari</translation> <translation id="4522570452068850558">Butiran</translation> +<translation id="4542388879936266156">masa yang tinggal: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">borang</translation> <translation id="4661075872484491155">pohon</translation> <translation id="4664250907885839816">Bahagian selepas '<ph name="ATSIGN" />' tidak boleh mengandungi simbol '<ph name="INVALIDCHARACTER" />'.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">Kapsyen</translation> <translation id="835897206747267392">Nilai tidak sah.</translation> +<translation id="8403857369060869934">masa berlalu: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">bahagian</translation> <translation id="8433900881053900389">bar alat</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> fail</translation> diff --git a/chromium/content/app/strings/translations/content_strings_nl.xtb b/chromium/content/app/strings/translations/content_strings_nl.xtb index c31f713ced7..e0af6ed8d47 100644 --- a/chromium/content/app/strings/translations/content_strings_nl.xtb +++ b/chromium/content/app/strings/translations/content_strings_nl.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">menuknop</translation> <translation id="4446524499724042288">woordenlijstreferentie</translation> <translation id="4522570452068850558">Details</translation> +<translation id="4542388879936266156">resterende tijd: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulier</translation> <translation id="4661075872484491155">structuur</translation> <translation id="4664250907885839816">Het adresgedeelte na '<ph name="ATSIGN" />' mag niet het teken '<ph name="INVALIDCHARACTER" />' bevatten.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">jjjj</translation> <translation id="8284326494547611709">Ondertiteling</translation> <translation id="835897206747267392">Ongeldige waarde.</translation> +<translation id="8403857369060869934">verstreken tijd: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">deel</translation> <translation id="8433900881053900389">werkbalk</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> bestanden</translation> diff --git a/chromium/content/app/strings/translations/content_strings_no.xtb b/chromium/content/app/strings/translations/content_strings_no.xtb index 3425a9ab99d..1466b040cd0 100644 --- a/chromium/content/app/strings/translations/content_strings_no.xtb +++ b/chromium/content/app/strings/translations/content_strings_no.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">menyknapp</translation> <translation id="4446524499724042288">ordlistereferanse</translation> <translation id="4522570452068850558">Detaljer</translation> +<translation id="4542388879936266156">tid som gjenstår: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">skjema</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">En del etterfulgt av «<ph name="ATSIGN" />» kan ikke inneholde symbolet «<ph name="INVALIDCHARACTER" />».</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">åååå</translation> <translation id="8284326494547611709">Teksting</translation> <translation id="835897206747267392">Ugyldig verdi</translation> +<translation id="8403857369060869934">medgått tid: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">del</translation> <translation id="8433900881053900389">verktøyrad</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> filer</translation> diff --git a/chromium/content/app/strings/translations/content_strings_pl.xtb b/chromium/content/app/strings/translations/content_strings_pl.xtb index 606c51e09a9..7dd99a81fd7 100644 --- a/chromium/content/app/strings/translations/content_strings_pl.xtb +++ b/chromium/content/app/strings/translations/content_strings_pl.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">przycisk menu</translation> <translation id="4446524499724042288">odniesienie do słownika</translation> <translation id="4522570452068850558">Szczegóły</translation> +<translation id="4542388879936266156">pozostało: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formularz</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Część po znaku „<ph name="ATSIGN" />” nie może zawierać symbolu „<ph name="INVALIDCHARACTER" />”.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">rrrr</translation> <translation id="8284326494547611709">Napisy</translation> <translation id="835897206747267392">Nieprawidłowa wartość.</translation> +<translation id="8403857369060869934">upłynęło: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">część</translation> <translation id="8433900881053900389">pasek narzędzi</translation> <translation id="8444882422881193423">Liczba plików: <ph name="NUMBER_OF_FILES" /></translation> diff --git a/chromium/content/app/strings/translations/content_strings_pt-BR.xtb b/chromium/content/app/strings/translations/content_strings_pt-BR.xtb index fe42f1147c5..d35546a4a62 100644 --- a/chromium/content/app/strings/translations/content_strings_pt-BR.xtb +++ b/chromium/content/app/strings/translations/content_strings_pt-BR.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">botão de menu</translation> <translation id="4446524499724042288">referência de glossário</translation> <translation id="4522570452068850558">Detalhes</translation> +<translation id="4542388879936266156">tempo restante: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulário</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">A parte depois de "<ph name="ATSIGN" />" não deve conter o símbolo "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">aaaa</translation> <translation id="8284326494547611709">Legendas</translation> <translation id="835897206747267392">Valor inválido.</translation> +<translation id="8403857369060869934">tempo decorrido: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">parte</translation> <translation id="8433900881053900389">barra de ferramentas</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> arquivos</translation> diff --git a/chromium/content/app/strings/translations/content_strings_pt-PT.xtb b/chromium/content/app/strings/translations/content_strings_pt-PT.xtb index c0f3275c561..491e03d0e20 100644 --- a/chromium/content/app/strings/translations/content_strings_pt-PT.xtb +++ b/chromium/content/app/strings/translations/content_strings_pt-PT.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">botão de menu</translation> <translation id="4446524499724042288">referência do glossário</translation> <translation id="4522570452068850558">Detalhes</translation> +<translation id="4542388879936266156">tempo restante: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulário</translation> <translation id="4661075872484491155">árvore</translation> <translation id="4664250907885839816">Uma parte a seguir a "<ph name="ATSIGN" />" não deve conter o símbolo "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">aaaa</translation> <translation id="8284326494547611709">Legendas</translation> <translation id="835897206747267392">Valor inválido.</translation> +<translation id="8403857369060869934">tempo decorrido: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">parte</translation> <translation id="8433900881053900389">barra de ferramentas</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> ficheiros</translation> diff --git a/chromium/content/app/strings/translations/content_strings_ro.xtb b/chromium/content/app/strings/translations/content_strings_ro.xtb index d4b11444778..ee95db287f5 100644 --- a/chromium/content/app/strings/translations/content_strings_ro.xtb +++ b/chromium/content/app/strings/translations/content_strings_ro.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">buton de meniu</translation> <translation id="4446524499724042288">trimitere la glosar</translation> <translation id="4522570452068850558">Detalii</translation> +<translation id="4542388879936266156">timp rămas: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formular</translation> <translation id="4661075872484491155">arbore</translation> <translation id="4664250907885839816">Valoarea care urmează după semnul „<ph name="ATSIGN" />” nu trebuie să conțină simbolul „<ph name="INVALIDCHARACTER" />”.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">aaaa</translation> <translation id="8284326494547611709">Subtitrări</translation> <translation id="835897206747267392">Valoare nevalidă.</translation> +<translation id="8403857369060869934">timp scurs: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">parte</translation> <translation id="8433900881053900389">bară de instrumente</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> fișiere</translation> diff --git a/chromium/content/app/strings/translations/content_strings_ru.xtb b/chromium/content/app/strings/translations/content_strings_ru.xtb index 9c03dc341e8..b3b0e4b80bf 100644 --- a/chromium/content/app/strings/translations/content_strings_ru.xtb +++ b/chromium/content/app/strings/translations/content_strings_ru.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">кнопка меню</translation> <translation id="4446524499724042288">ссылка на словарную статью</translation> <translation id="4522570452068850558">Подробнее</translation> +<translation id="4542388879936266156">осталось времени: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">форма</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Часть адреса после символа "<ph name="ATSIGN" />" не должна содержать символ "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">гггг</translation> <translation id="8284326494547611709">Титры</translation> <translation id="835897206747267392">Недопустимые данные.</translation> +<translation id="8403857369060869934">прошло времени: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">часть</translation> <translation id="8433900881053900389">панель инструментов</translation> <translation id="8444882422881193423">Число файлов: <ph name="NUMBER_OF_FILES" /></translation> diff --git a/chromium/content/app/strings/translations/content_strings_sk.xtb b/chromium/content/app/strings/translations/content_strings_sk.xtb index b7346f5caaa..b03211ff1dc 100644 --- a/chromium/content/app/strings/translations/content_strings_sk.xtb +++ b/chromium/content/app/strings/translations/content_strings_sk.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">tlačidlo ponuky</translation> <translation id="4446524499724042288">glosárový termín</translation> <translation id="4522570452068850558">Podrobnosti</translation> +<translation id="4542388879936266156">zostávajúci čas: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulár</translation> <translation id="4661075872484491155">strom</translation> <translation id="4664250907885839816">Časť za znakom <ph name="ATSIGN" /> by nemala obsahovať symbol <ph name="INVALIDCHARACTER" />.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">rrrr</translation> <translation id="8284326494547611709">Titulky</translation> <translation id="835897206747267392">Neplatná hodnota.</translation> +<translation id="8403857369060869934">uplynutý čas: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">časť</translation> <translation id="8433900881053900389">panel s nástrojmi</translation> <translation id="8444882422881193423">Počet súborov: <ph name="NUMBER_OF_FILES" /></translation> diff --git a/chromium/content/app/strings/translations/content_strings_sl.xtb b/chromium/content/app/strings/translations/content_strings_sl.xtb index ff44b9c97be..5d8dcba6f2d 100644 --- a/chromium/content/app/strings/translations/content_strings_sl.xtb +++ b/chromium/content/app/strings/translations/content_strings_sl.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">menijski gumb</translation> <translation id="4446524499724042288">vnos v glosarju</translation> <translation id="4522570452068850558">Podrobnosti</translation> +<translation id="4542388879936266156">preostali čas: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">obrazec</translation> <translation id="4661075872484491155">drevo</translation> <translation id="4664250907885839816">Del po »<ph name="ATSIGN" />« ne sme vsebovati znaka »<ph name="INVALIDCHARACTER" />«.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">llll</translation> <translation id="8284326494547611709">Napisi</translation> <translation id="835897206747267392">Neveljavna vrednost.</translation> +<translation id="8403857369060869934">pretečeni čas: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">del</translation> <translation id="8433900881053900389">orodna vrstica</translation> <translation id="8444882422881193423">Število datotek: <ph name="NUMBER_OF_FILES" /></translation> diff --git a/chromium/content/app/strings/translations/content_strings_sr.xtb b/chromium/content/app/strings/translations/content_strings_sr.xtb index 1545c8324a1..54d5d8328e8 100644 --- a/chromium/content/app/strings/translations/content_strings_sr.xtb +++ b/chromium/content/app/strings/translations/content_strings_sr.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">дугме менија</translation> <translation id="4446524499724042288">референца речника термина</translation> <translation id="4522570452068850558">Детаљи</translation> +<translation id="4542388879936266156">преостало време: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">образац</translation> <translation id="4661075872484491155">стабло</translation> <translation id="4664250907885839816">Део после „<ph name="ATSIGN" />“ не треба да садржи симбол „<ph name="INVALIDCHARACTER" />“.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">гггг</translation> <translation id="8284326494547611709">Титл</translation> <translation id="835897206747267392">Неважећа вредност.</translation> +<translation id="8403857369060869934">протекло време: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">део</translation> <translation id="8433900881053900389">трака с алаткама</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> датотеке(а)</translation> diff --git a/chromium/content/app/strings/translations/content_strings_sv.xtb b/chromium/content/app/strings/translations/content_strings_sv.xtb index 04d1828e3c3..c7215b55249 100644 --- a/chromium/content/app/strings/translations/content_strings_sv.xtb +++ b/chromium/content/app/strings/translations/content_strings_sv.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">menyknapp</translation> <translation id="4446524499724042288">hänvisning till ordlista</translation> <translation id="4522570452068850558">Info</translation> +<translation id="4542388879936266156">tid som återstår: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">formulär</translation> <translation id="4661075872484491155">träd</translation> <translation id="4664250907885839816">En del efter <ph name="ATSIGN" /> får inte innehålla symbolen <ph name="INVALIDCHARACTER" />.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">åååå</translation> <translation id="8284326494547611709">Textning</translation> <translation id="835897206747267392">Ogiltigt värde.</translation> +<translation id="8403857369060869934">tid som gått: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">del</translation> <translation id="8433900881053900389">verktygsfält</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> filer</translation> diff --git a/chromium/content/app/strings/translations/content_strings_sw.xtb b/chromium/content/app/strings/translations/content_strings_sw.xtb index 4ca647b930b..e7af6aff03f 100644 --- a/chromium/content/app/strings/translations/content_strings_sw.xtb +++ b/chromium/content/app/strings/translations/content_strings_sw.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">kitufe cha menyu</translation> <translation id="4446524499724042288">marejeleo ya farahasa</translation> <translation id="4522570452068850558">Maelezo</translation> +<translation id="4542388879936266156">muda uliosalia: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">fomu</translation> <translation id="4661075872484491155">mti</translation> <translation id="4664250907885839816">Sehemu inayofuata '<ph name="ATSIGN" />' haipaswi kuwa na alama ya '<ph name="INVALIDCHARACTER" />'.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">Manukuu</translation> <translation id="835897206747267392">Thamani batili.</translation> +<translation id="8403857369060869934">muda uliopita: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">sehemu</translation> <translation id="8433900881053900389">upau wa vidhibiti</translation> <translation id="8444882422881193423">faili <ph name="NUMBER_OF_FILES" /></translation> diff --git a/chromium/content/app/strings/translations/content_strings_ta.xtb b/chromium/content/app/strings/translations/content_strings_ta.xtb index 6701b515275..e7c94e110c9 100644 --- a/chromium/content/app/strings/translations/content_strings_ta.xtb +++ b/chromium/content/app/strings/translations/content_strings_ta.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">மெனு பொத்தான்</translation> <translation id="4446524499724042288">அருஞ்சொல் திரட்டு மேற்கோள்</translation> <translation id="4522570452068850558">விவரங்கள்</translation> +<translation id="4542388879936266156">மீதமுள்ள நேரம்: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">படிவம்</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">'<ph name="ATSIGN" />' ஐத் தொடரும் பகுதியில், '<ph name="INVALIDCHARACTER" />' சின்னம் இருக்கக்கூடாது.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">வசனங்கள்</translation> <translation id="835897206747267392">செல்லாத மதிப்பு.</translation> +<translation id="8403857369060869934">முடிவடைந்த நேரம்: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">பகுதி</translation> <translation id="8433900881053900389">கருவிப்பட்டி</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> கோப்புகள்</translation> diff --git a/chromium/content/app/strings/translations/content_strings_te.xtb b/chromium/content/app/strings/translations/content_strings_te.xtb index ca634b131ae..5e3f7b9de09 100644 --- a/chromium/content/app/strings/translations/content_strings_te.xtb +++ b/chromium/content/app/strings/translations/content_strings_te.xtb @@ -43,7 +43,7 @@ <translation id="2311842470354187719">పేజీ విభజన</translation> <translation id="2335594187091864976">తేదీ మరియు సమయం ఎంపిక</translation> <translation id="248395913932153421">రోజు</translation> -<translation id="2507943997699731163">దయచేసి ఈ ఫీల్డ్ని పూర్తి చెయ్యండి.</translation> +<translation id="2507943997699731163">దయచేసి ఈ ఫీల్డ్ను పూర్తి చేయండి.</translation> <translation id="2508569020611168319">ట్యాబ్ జాబితా</translation> <translation id="2561842179657104141">మరిన్ని మీడియా నియంత్రణలను చూపు</translation> <translation id="2572483411312390101">ప్లే చేయి</translation> @@ -63,7 +63,7 @@ <translation id="2942448076852699108">హైలైట్ చేయబడిన కంటెంట్</translation> <translation id="3040011195152428237">లింక్</translation> <translation id="3049748772180311791"><ph name="QUANTITY" /> MB</translation> -<translation id="3075154866155599887">దయచేసి చెల్లుబాటు అయ్యే విలువను నమోదు చేయండి. ఫీల్డ్ అసంపూర్ణంగా ఉంది లేదా అందులోని తేదీ చెల్లదు.</translation> +<translation id="3075154866155599887">దయచేసి చెల్లుబాటు అయ్యే విలువను నమోదు చేయండి. ఫీల్డ్ అసంపూర్ణంగా ఉంది లేదా ఇందులోని తేదీ చెల్లదు.</translation> <translation id="3078740164268491126">పట్టిక</translation> <translation id="3086746722712840547">note</translation> <translation id="310520048233152454">దయచేసి ఒక URLని ఎంటర్ చేయండి.</translation> @@ -84,7 +84,7 @@ <translation id="3920932319529768807">ముగింపు</translation> <translation id="3924558731517983934">అప్లికేషన్</translation> <translation id="3944740393230681990">ప్రారంభం</translation> -<translation id="3960700977367013758">స్క్రోల్ పట్టీ</translation> +<translation id="3960700977367013758">స్క్రోల్ బార్</translation> <translation id="4103419683916926126">మిల్లీసెకన్లు</translation> <translation id="4151657705144244502">గ్రాఫిక్</translation> <translation id="4193965531860883258">ముందుమాట</translation> @@ -97,6 +97,7 @@ <translation id="4413860115965805769">మెను బటన్</translation> <translation id="4446524499724042288">పదకోశ సూచన</translation> <translation id="4522570452068850558">వివరాలు</translation> +<translation id="4542388879936266156">మిగిలి ఉన్న సమయం: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">ఫారమ్</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">'<ph name="ATSIGN" />'కి తర్వాత ఉన్న భాగంలో '<ph name="INVALIDCHARACTER" />' చిహ్నం ఉండకూడదు.</translation> @@ -161,7 +162,7 @@ <translation id="6709570249143506788">ప్లేబ్యాక్ నాణ్యత బాగాలేదు</translation> <translation id="6755330956360078551">సాధన చిట్కా</translation> <translation id="6790428901817661496">ప్లే చేయి</translation> -<translation id="6820355525329141109">ప్లగిన్ను లోడ్ చేయడం సాధ్యపడలేదు.</translation> +<translation id="6820355525329141109">ప్లగ్ఇన్ను లోడ్ చేయడం సాధ్యపడలేదు.</translation> <translation id="6820615603175220800">వివరణపట్టి సూచన</translation> <translation id="6843725295806269523">మ్యూట్ చేయి</translation> <translation id="6885760532393684712">డైరెక్టరీ</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">ఉపశీర్షికలు</translation> <translation id="835897206747267392">చెల్లని విలువ.</translation> +<translation id="8403857369060869934">గడిచిన సమయం: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">భాగం</translation> <translation id="8433900881053900389">సాధన పట్టీ</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> ఫైళ్ళు</translation> diff --git a/chromium/content/app/strings/translations/content_strings_th.xtb b/chromium/content/app/strings/translations/content_strings_th.xtb index 5124b9820c6..d11b930ebea 100644 --- a/chromium/content/app/strings/translations/content_strings_th.xtb +++ b/chromium/content/app/strings/translations/content_strings_th.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">ปุ่มเมนู</translation> <translation id="4446524499724042288">ข้อมูลอ้างอิงอภิธานศัพท์</translation> <translation id="4522570452068850558">รายละเอียด</translation> +<translation id="4542388879936266156">เวลาที่เหลือ: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">ฟอร์ม</translation> <translation id="4661075872484491155">แผนผัง</translation> <translation id="4664250907885839816">ส่วนที่ต่อท้าย "<ph name="ATSIGN" />" ต้องไม่มีสัญลักษณ์ "<ph name="INVALIDCHARACTER" />"</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">ปปปป</translation> <translation id="8284326494547611709">คำบรรยาย</translation> <translation id="835897206747267392">ค่าไม่ถูกต้อง</translation> +<translation id="8403857369060869934">เวลาที่ผ่านไป: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">ภาค</translation> <translation id="8433900881053900389">แถบเครื่องมือ</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> ไฟล์</translation> diff --git a/chromium/content/app/strings/translations/content_strings_tr.xtb b/chromium/content/app/strings/translations/content_strings_tr.xtb index b2245f63d83..5fbb4fc8f29 100644 --- a/chromium/content/app/strings/translations/content_strings_tr.xtb +++ b/chromium/content/app/strings/translations/content_strings_tr.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">menü düğmesi</translation> <translation id="4446524499724042288">terimler sözlüğü referansı</translation> <translation id="4522570452068850558">Ayrıntılar</translation> +<translation id="4542388879936266156">kalan süre: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">form</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">Başında "<ph name="ATSIGN" />" bulunan kısımda "<ph name="INVALIDCHARACTER" />" simgesi bulunmamalıdır.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">Altyazılar</translation> <translation id="835897206747267392">Geçersiz değer.</translation> +<translation id="8403857369060869934">geçen süre: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">bölüm</translation> <translation id="8433900881053900389">araç çubuğu</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> dosya</translation> diff --git a/chromium/content/app/strings/translations/content_strings_uk.xtb b/chromium/content/app/strings/translations/content_strings_uk.xtb index fa50a669c62..702f177e433 100644 --- a/chromium/content/app/strings/translations/content_strings_uk.xtb +++ b/chromium/content/app/strings/translations/content_strings_uk.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">кнопка меню</translation> <translation id="4446524499724042288">посилання на глосарій</translation> <translation id="4522570452068850558">Деталі</translation> +<translation id="4542388879936266156">залишилося часу: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">форма</translation> <translation id="4661075872484491155">дерево</translation> <translation id="4664250907885839816">Частина після знака "<ph name="ATSIGN" />" не може містити символ "<ph name="INVALIDCHARACTER" />".</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">рррр</translation> <translation id="8284326494547611709">Субтитри</translation> <translation id="835897206747267392">Недійсне значення</translation> +<translation id="8403857369060869934">минуло часу: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">частина</translation> <translation id="8433900881053900389">панель інструментів</translation> <translation id="8444882422881193423">файлів: <ph name="NUMBER_OF_FILES" /></translation> diff --git a/chromium/content/app/strings/translations/content_strings_vi.xtb b/chromium/content/app/strings/translations/content_strings_vi.xtb index 48a3a977133..8f99cda416c 100644 --- a/chromium/content/app/strings/translations/content_strings_vi.xtb +++ b/chromium/content/app/strings/translations/content_strings_vi.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">nút menu</translation> <translation id="4446524499724042288">tham chiếu bảng thuật ngữ</translation> <translation id="4522570452068850558">Chi tiết</translation> +<translation id="4542388879936266156">thời gian còn lại: <ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">biểu mẫu</translation> <translation id="4661075872484491155">cây</translation> <translation id="4664250907885839816">Phần đứng sau '<ph name="ATSIGN" />' không được chứa biểu tượng '<ph name="INVALIDCHARACTER" />'.</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405">yyyy</translation> <translation id="8284326494547611709">Phụ đề</translation> <translation id="835897206747267392">Giá trị không hợp lệ.</translation> +<translation id="8403857369060869934">thời gian trôi qua: <ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">phần</translation> <translation id="8433900881053900389">thanh công cụ</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> tệp</translation> diff --git a/chromium/content/app/strings/translations/content_strings_zh-CN.xtb b/chromium/content/app/strings/translations/content_strings_zh-CN.xtb index 6afd44e47ef..96ef950574f 100644 --- a/chromium/content/app/strings/translations/content_strings_zh-CN.xtb +++ b/chromium/content/app/strings/translations/content_strings_zh-CN.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">菜单按钮</translation> <translation id="4446524499724042288">词汇表参考资料</translation> <translation id="4522570452068850558">详细信息</translation> +<translation id="4542388879936266156">剩余时间:<ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">表单</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">“<ph name="ATSIGN" />”后面的内容不应包含符号“<ph name="INVALIDCHARACTER" />”。</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405"> 年 </translation> <translation id="8284326494547611709">字幕</translation> <translation id="835897206747267392">值无效。</translation> +<translation id="8403857369060869934">已播放时间:<ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">部分</translation> <translation id="8433900881053900389">工具栏</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> 个文件</translation> diff --git a/chromium/content/app/strings/translations/content_strings_zh-TW.xtb b/chromium/content/app/strings/translations/content_strings_zh-TW.xtb index 905aecf9818..3debe6d97d2 100644 --- a/chromium/content/app/strings/translations/content_strings_zh-TW.xtb +++ b/chromium/content/app/strings/translations/content_strings_zh-TW.xtb @@ -97,6 +97,7 @@ <translation id="4413860115965805769">選單按鈕</translation> <translation id="4446524499724042288">詞彙解釋參考資料</translation> <translation id="4522570452068850558">詳細資訊</translation> +<translation id="4542388879936266156">剩餘時間:<ph name="REMAINING_TIME" /></translation> <translation id="4597532268155981612">表單</translation> <translation id="4661075872484491155">tree</translation> <translation id="4664250907885839816">「<ph name="ATSIGN" />」後面的部分不應包含「<ph name="INVALIDCHARACTER" />」符號。</translation> @@ -200,6 +201,7 @@ <translation id="8199524924445686405"> 年 </translation> <translation id="8284326494547611709">字幕</translation> <translation id="835897206747267392">無效的值。</translation> +<translation id="8403857369060869934">經過時間:<ph name="ELAPSED_TIME" /></translation> <translation id="8415319359811155763">分輯</translation> <translation id="8433900881053900389">工具列</translation> <translation id="8444882422881193423"><ph name="NUMBER_OF_FILES" /> 個檔案</translation> diff --git a/chromium/content/browser/android/content_feature_list.cc b/chromium/content/browser/android/content_feature_list.cc index 538ef50a446..4d1b275060e 100644 --- a/chromium/content/browser/android/content_feature_list.cc +++ b/chromium/content/browser/android/content_feature_list.cc @@ -24,6 +24,7 @@ namespace { const base::Feature* kFeaturesExposedToJava[] = { &features::kBackgroundMediaRendererHasModerateBinding, &kEnhancedSelectionInsertionHandle, + &features::kServiceWorkerForegroundPriority, }; const base::Feature* FindFeatureExposedToJava(const std::string& feature_name) { diff --git a/chromium/content/browser/browser_main_loop.cc b/chromium/content/browser/browser_main_loop.cc index 81d99cb7f9e..5fd14e79ead 100644 --- a/chromium/content/browser/browser_main_loop.cc +++ b/chromium/content/browser/browser_main_loop.cc @@ -178,7 +178,6 @@ #if defined(OS_MACOSX) #include "base/memory/memory_pressure_monitor_mac.h" -#include "content/browser/cocoa/system_hotkey_helper_mac.h" #include "content/browser/mach_broker_mac.h" #include "content/browser/renderer_host/browser_compositor_view_mac.h" #include "content/browser/theme_helper_mac.h" @@ -1461,7 +1460,6 @@ int BrowserMainLoop::BrowserThreadsStarted() { #if defined(OS_MACOSX) ThemeHelperMac::GetInstance(); - SystemHotkeyHelperMac::GetInstance()->DeferredLoadSystemHotkeys(); #endif // defined(OS_MACOSX) responsiveness_watcher_ = new responsiveness::Watcher; diff --git a/chromium/content/browser/child_process_launcher.cc b/chromium/content/browser/child_process_launcher.cc index fa1fb766fe3..19b747d2f1c 100644 --- a/chromium/content/browser/child_process_launcher.cc +++ b/chromium/content/browser/child_process_launcher.cc @@ -15,6 +15,7 @@ #include "base/process/launch.h" #include "build/build_config.h" #include "content/public/browser/child_process_launcher_utils.h" +#include "content/public/common/content_features.h" #include "content/public/common/sandboxed_process_launcher_delegate.h" #include "services/service_manager/embedder/result_codes.h" @@ -167,6 +168,14 @@ ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( return ret; } +bool ChildProcessLauncherPriority::is_background() const { + return !visible && !has_media_stream && + !(should_boost_for_pending_views && boost_for_pending_views) && + !(has_foreground_service_worker && + base::FeatureList::IsEnabled( + features::kServiceWorkerForegroundPriority)); +} + bool ChildProcessLauncherPriority::operator==( const ChildProcessLauncherPriority& other) const { // |should_boost_for_pending_views| is temporary and constant for all @@ -175,6 +184,7 @@ bool ChildProcessLauncherPriority::operator==( other.should_boost_for_pending_views); return visible == other.visible && has_media_stream == other.has_media_stream && + has_foreground_service_worker == other.has_foreground_service_worker && frame_depth == other.frame_depth && intersects_viewport == other.intersects_viewport && boost_for_pending_views == other.boost_for_pending_views diff --git a/chromium/content/browser/child_process_launcher.h b/chromium/content/browser/child_process_launcher.h index 415d916da31..f5fff8ff48c 100644 --- a/chromium/content/browser/child_process_launcher.h +++ b/chromium/content/browser/child_process_launcher.h @@ -58,6 +58,7 @@ static_assert(static_cast<int>(LAUNCH_RESULT_START) > struct ChildProcessLauncherPriority { ChildProcessLauncherPriority(bool visible, bool has_media_stream, + bool has_foreground_service_worker, unsigned int frame_depth, bool intersects_viewport, bool boost_for_pending_views, @@ -69,6 +70,7 @@ struct ChildProcessLauncherPriority { ) : visible(visible), has_media_stream(has_media_stream), + has_foreground_service_worker(has_foreground_service_worker), frame_depth(frame_depth), intersects_viewport(intersects_viewport), boost_for_pending_views(boost_for_pending_views), @@ -81,10 +83,7 @@ struct ChildProcessLauncherPriority { } // Returns true if the child process is backgrounded. - bool is_background() const { - return !visible && !has_media_stream && - !(should_boost_for_pending_views && boost_for_pending_views); - } + bool is_background() const; bool operator==(const ChildProcessLauncherPriority& other) const; bool operator!=(const ChildProcessLauncherPriority& other) const { @@ -104,6 +103,11 @@ struct ChildProcessLauncherPriority { // content. bool has_media_stream; + // |has_foreground_service_worker| is true when the process has a service + // worker that may need to service timely events from other, possibly visible, + // processes. + bool has_foreground_service_worker; + // |frame_depth| is the depth of the shallowest frame this process is // responsible for which has |visible| visibility. It only makes sense to // compare this property for two ChildProcessLauncherPriority instances with diff --git a/chromium/content/browser/child_process_launcher_helper_android.cc b/chromium/content/browser/child_process_launcher_helper_android.cc index 04bfd4acf36..4aa0301d1a6 100644 --- a/chromium/content/browser/child_process_launcher_helper_android.cc +++ b/chromium/content/browser/child_process_launcher_helper_android.cc @@ -226,9 +226,9 @@ void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread( DCHECK(env); return Java_ChildProcessLauncherHelperImpl_setPriority( env, java_peer_, process.Handle(), priority.visible, - priority.has_media_stream, priority.frame_depth, - priority.intersects_viewport, priority.boost_for_pending_views, - static_cast<jint>(priority.importance)); + priority.has_media_stream, priority.has_foreground_service_worker, + priority.frame_depth, priority.intersects_viewport, + priority.boost_for_pending_views, static_cast<jint>(priority.importance)); } // static diff --git a/chromium/content/browser/child_process_security_policy_impl.cc b/chromium/content/browser/child_process_security_policy_impl.cc index 0e69ac487ca..79b62092482 100644 --- a/chromium/content/browser/child_process_security_policy_impl.cc +++ b/chromium/content/browser/child_process_security_policy_impl.cc @@ -1170,6 +1170,17 @@ bool ChildProcessSecurityPolicyImpl::CanDeleteFileSystemFile( DELETE_FILE_GRANT); } +bool ChildProcessSecurityPolicyImpl::CanAccessDataForWebSocket( + int child_id, + const GURL& url) { + DCHECK(url.SchemeIsWSOrWSS()); + GURL::Replacements replace_scheme; + replace_scheme.SetSchemeStr(url.SchemeIs(url::kWssScheme) ? url::kHttpsScheme + : url::kHttpScheme); + GURL url_to_check = url.ReplaceComponents(replace_scheme); + return CanAccessDataForOrigin(child_id, url_to_check); +} + bool ChildProcessSecurityPolicyImpl::HasWebUIBindings(int child_id) { base::AutoLock lock(lock_); diff --git a/chromium/content/browser/child_process_security_policy_impl.h b/chromium/content/browser/child_process_security_policy_impl.h index 93af81e6818..811557a3ec2 100644 --- a/chromium/content/browser/child_process_security_policy_impl.h +++ b/chromium/content/browser/child_process_security_policy_impl.h @@ -236,6 +236,10 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl bool CanDeleteFileSystemFile(int child_id, const storage::FileSystemURL& filesystem_url); + // True if cookie headers may be exposed to renderer |child_id| for |url| for + // display in DevTools. |url| should be a WebSocket URL. + bool CanAccessDataForWebSocket(int child_id, const GURL& url); + // Returns true if the specified child_id has been granted ReadRawCookies. bool CanReadRawCookies(int child_id); diff --git a/chromium/content/browser/cocoa/system_hotkey_helper_mac.h b/chromium/content/browser/cocoa/system_hotkey_helper_mac.h index 19ecb8889b9..b523430114d 100644 --- a/chromium/content/browser/cocoa/system_hotkey_helper_mac.h +++ b/chromium/content/browser/cocoa/system_hotkey_helper_mac.h @@ -5,54 +5,12 @@ #ifndef CONTENT_BROWSER_COCOA_SYSTEM_HOTKEY_HELPER_MAC_H_ #define CONTENT_BROWSER_COCOA_SYSTEM_HOTKEY_HELPER_MAC_H_ -#include <memory> - -#include "base/macros.h" -#include "base/memory/singleton.h" -#include "base/memory/weak_ptr.h" - -#ifdef __OBJC__ -@class NSDictionary; -#else -class NSDictionary; -#endif - namespace content { class SystemHotkeyMap; -// This singleton holds a global mapping of hotkeys reserved by OSX. -class SystemHotkeyHelperMac { - public: - // Return pointer to the singleton instance for the current process. - static SystemHotkeyHelperMac* GetInstance(); - - // Loads the system hot keys after a brief delay, to reduce file system access - // immediately after launch. - void DeferredLoadSystemHotkeys(); - - // Guaranteed to not be NULL. - SystemHotkeyMap* map() { return map_.get(); } - - private: - friend struct base::DefaultSingletonTraits<SystemHotkeyHelperMac>; - - SystemHotkeyHelperMac(); - ~SystemHotkeyHelperMac(); - - // Must be called from the FILE thread. Loads the file containing the system - // hotkeys into a NSDictionary* object, and passes the result to FileDidLoad - // on the UI thread. - void LoadSystemHotkeys(); - - // Must be called from the UI thread. This takes ownership of |dictionary|. - // Parses the system hotkeys from the plist stored in |dictionary|. - void FileDidLoad(NSDictionary* dictionary); - - std::unique_ptr<SystemHotkeyMap> map_; - - DISALLOW_COPY_AND_ASSIGN(SystemHotkeyHelperMac); -}; +// Guaranteed to not be NULL. +SystemHotkeyMap* GetSystemHotkeyMap(); } // namespace content diff --git a/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm b/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm index 27b8fae73bc..99a4d4d29ac 100644 --- a/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm +++ b/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm @@ -4,76 +4,37 @@ #include "content/browser/cocoa/system_hotkey_helper_mac.h" -#include "base/bind.h" #include "base/files/file_path.h" #include "base/mac/foundation_util.h" #include "base/metrics/histogram_macros.h" -#include "base/task/post_task.h" -#include "base/task/task_traits.h" -#include "base/threading/scoped_blocking_call.h" +#include "base/no_destructor.h" #include "content/browser/cocoa/system_hotkey_map.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" namespace { -NSString* kSystemHotkeyPlistExtension = - @"/Preferences/com.apple.symbolichotkeys.plist"; +constexpr auto* kSystemHotkeyPlistPath = + "Preferences/com.apple.symbolichotkeys.plist"; -// Amount of time to delay loading the hotkeys in seconds. -const int kLoadHotkeysDelaySeconds = 10; +content::SystemHotkeyMap LoadSystemHotkeyMap() { + auto* hotkey_plist_url = base::mac::FilePathToNSURL( + base::mac::GetUserLibraryPath().Append(kSystemHotkeyPlistPath)); + NSDictionary* dictionary = + [NSDictionary dictionaryWithContentsOfURL:hotkey_plist_url]; + + content::SystemHotkeyMap map; + bool success = map.ParseDictionary(dictionary); + UMA_HISTOGRAM_BOOLEAN("OSX.SystemHotkeyMap.LoadSuccess", success); + return map; +} } // namespace namespace content { // static -SystemHotkeyHelperMac* SystemHotkeyHelperMac::GetInstance() { - return base::Singleton<SystemHotkeyHelperMac>::get(); -} - -void SystemHotkeyHelperMac::DeferredLoadSystemHotkeys() { - base::PostDelayedTaskWithTraits( - FROM_HERE, - {base::TaskPriority::USER_VISIBLE, - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()}, - base::Bind(&SystemHotkeyHelperMac::LoadSystemHotkeys, - base::Unretained(this)), - base::TimeDelta::FromSeconds(kLoadHotkeysDelaySeconds)); -} - -SystemHotkeyHelperMac::SystemHotkeyHelperMac() : map_(new SystemHotkeyMap) { -} - -SystemHotkeyHelperMac::~SystemHotkeyHelperMac() { -} - -void SystemHotkeyHelperMac::LoadSystemHotkeys() { - base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); - - std::string library_path(base::mac::GetUserLibraryPath().value()); - NSString* expanded_file_path = - [NSString stringWithFormat:@"%s%@", - library_path.c_str(), - kSystemHotkeyPlistExtension]; - - // Loads the file into memory. - NSData* data = [NSData dataWithContentsOfFile:expanded_file_path]; - // Intentionally create the object with +1 retain count, as FileDidLoad - // will destroy the object. - NSDictionary* dictionary = [SystemHotkeyMap::DictionaryFromData(data) retain]; - - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, - base::Bind(&SystemHotkeyHelperMac::FileDidLoad, - base::Unretained(this), dictionary)); -} - -void SystemHotkeyHelperMac::FileDidLoad(NSDictionary* dictionary) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - bool success = map()->ParseDictionary(dictionary); - UMA_HISTOGRAM_BOOLEAN("OSX.SystemHotkeyMap.LoadSuccess", success); - [dictionary release]; +SystemHotkeyMap* GetSystemHotkeyMap() { + static base::NoDestructor<SystemHotkeyMap> instance(LoadSystemHotkeyMap()); + return instance.get(); } } // namespace content diff --git a/chromium/content/browser/cocoa/system_hotkey_map.h b/chromium/content/browser/cocoa/system_hotkey_map.h index 1909aa53b88..e40c60edc83 100644 --- a/chromium/content/browser/cocoa/system_hotkey_map.h +++ b/chromium/content/browser/cocoa/system_hotkey_map.h @@ -22,12 +22,9 @@ struct SystemHotkey; class CONTENT_EXPORT SystemHotkeyMap { public: SystemHotkeyMap(); + SystemHotkeyMap(SystemHotkeyMap&&); ~SystemHotkeyMap(); - // Converts the plist stored in |data| into an NSDictionary. Returns nil on - // error. - static NSDictionary* DictionaryFromData(NSData* data); - // Parses the property list data commonly stored at // ~/Library/Preferences/com.apple.symbolichotkeys.plist // Returns false on encountering an irrecoverable error. diff --git a/chromium/content/browser/cocoa/system_hotkey_map.mm b/chromium/content/browser/cocoa/system_hotkey_map.mm index 6ee40574420..bf3484da4f3 100644 --- a/chromium/content/browser/cocoa/system_hotkey_map.mm +++ b/chromium/content/browser/cocoa/system_hotkey_map.mm @@ -50,28 +50,9 @@ struct SystemHotkey { #pragma mark - SystemHotkeyMap -SystemHotkeyMap::SystemHotkeyMap() { -} -SystemHotkeyMap::~SystemHotkeyMap() { -} - -NSDictionary* SystemHotkeyMap::DictionaryFromData(NSData* data) { - if (!data) - return nil; - - NSError* error = nil; - NSPropertyListFormat format; - NSDictionary* dictionary = - [NSPropertyListSerialization propertyListWithData:data - options:0 - format:&format - error:&error]; - - if (![dictionary isKindOfClass:[NSDictionary class]]) - return nil; - - return dictionary; -} +SystemHotkeyMap::SystemHotkeyMap() = default; +SystemHotkeyMap::SystemHotkeyMap(SystemHotkeyMap&&) = default; +SystemHotkeyMap::~SystemHotkeyMap() = default; bool SystemHotkeyMap::ParseDictionary(NSDictionary* dictionary) { system_hotkeys_.clear(); diff --git a/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm b/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm index d4b2a798c0c..cbae4c39866 100644 --- a/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm +++ b/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm @@ -8,6 +8,7 @@ #import <Cocoa/Cocoa.h> #include "base/files/file_path.h" +#import "base/mac/foundation_util.h" #include "base/mac/scoped_nsobject.h" #include "base/path_service.h" #import "content/browser/cocoa/system_hotkey_map.h" @@ -19,17 +20,15 @@ class SystemHotkeyMapTest : public ::testing::Test { protected: SystemHotkeyMapTest() {} - NSData* DataFromTestFile(const char* file) { + NSDictionary* DictionaryFromTestFile(const char* file) { base::FilePath test_data_dir; bool result = base::PathService::Get(DIR_TEST_DATA, &test_data_dir); if (!result) return nil; base::FilePath test_path = test_data_dir.AppendASCII(file); - std::string test_path_string = test_path.AsUTF8Unsafe(); - NSString* file_path = - [NSString stringWithUTF8String:test_path_string.c_str()]; - return [NSData dataWithContentsOfFile:file_path]; + return [NSDictionary + dictionaryWithContentsOfURL:base::mac::FilePathToNSURL(test_path)]; } void AddEntryToDictionary(BOOL enabled, @@ -84,10 +83,8 @@ class SystemHotkeyMapTest : public ::testing::Test { TEST_F(SystemHotkeyMapTest, Parse) { // This plist was pulled from a real machine. It is extensively populated, // and has no missing or incomplete entries. - NSData* data = DataFromTestFile("mac/mac_system_hotkeys.plist"); - ASSERT_TRUE(data); - - NSDictionary* dictionary = SystemHotkeyMap::DictionaryFromData(data); + NSDictionary* dictionary = + DictionaryFromTestFile("mac/mac_system_hotkeys.plist"); ASSERT_TRUE(dictionary); SystemHotkeyMap map; @@ -124,10 +121,8 @@ TEST_F(SystemHotkeyMapTest, ParseNil) { TEST_F(SystemHotkeyMapTest, ParseMouse) { // This plist was pulled from a real machine. It has missing entries, // incomplete entries, and mouse hotkeys. - NSData* data = DataFromTestFile("mac/mac_system_hotkeys_sparse.plist"); - ASSERT_TRUE(data); - - NSDictionary* dictionary = SystemHotkeyMap::DictionaryFromData(data); + NSDictionary* dictionary = + DictionaryFromTestFile("mac/mac_system_hotkeys_sparse.plist"); ASSERT_TRUE(dictionary); SystemHotkeyMap map; diff --git a/chromium/content/browser/contacts/contacts_manager_impl.cc b/chromium/content/browser/contacts/contacts_manager_impl.cc index 7170bb338f0..f830af86e4a 100644 --- a/chromium/content/browser/contacts/contacts_manager_impl.cc +++ b/chromium/content/browser/contacts/contacts_manager_impl.cc @@ -10,6 +10,7 @@ #include "base/callback.h" #include "build/build_config.h" +#include "content/browser/frame_host/render_frame_host_impl.h" #include "mojo/public/cpp/bindings/strong_binding.h" #if defined(OS_ANDROID) @@ -22,6 +23,8 @@ namespace { std::unique_ptr<ContactsProvider> CreateProvider( RenderFrameHostImpl* render_frame_host) { + if (render_frame_host->GetParent()) + return nullptr; // This API is only supported on the main frame. #if defined(OS_ANDROID) return std::make_unique<ContactsProviderAndroid>(render_frame_host); #else diff --git a/chromium/content/browser/contacts/contacts_provider_android.cc b/chromium/content/browser/contacts/contacts_provider_android.cc index f698edab1fd..4fc2199def5 100644 --- a/chromium/content/browser/contacts/contacts_provider_android.cc +++ b/chromium/content/browser/contacts/contacts_provider_android.cc @@ -9,12 +9,15 @@ #include <utility> #include <vector> +#include "base/android/jni_string.h" #include "base/callback.h" +#include "components/url_formatter/elide_url.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/public/browser/web_contents.h" #include "jni/ContactsDialogHost_jni.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "ui/android/window_android.h" +#include "url/origin.h" namespace content { @@ -29,6 +32,10 @@ ContactsProviderAndroid::ContactsProviderAndroid( if (!web_contents->GetTopLevelNativeWindow()) return; + formatted_origin_ = url_formatter::FormatUrlForSecurityDisplay( + render_frame_host->GetLastCommittedOrigin().GetURL(), + url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC); + dialog_.Reset(Java_ContactsDialogHost_create( env, web_contents->GetTopLevelNativeWindow()->GetJavaObject(), reinterpret_cast<intptr_t>(this))); @@ -54,8 +61,9 @@ void ContactsProviderAndroid::Select( callback_ = std::move(callback); JNIEnv* env = base::android::AttachCurrentThread(); - Java_ContactsDialogHost_showDialog(env, dialog_, multiple, include_names, - include_emails, include_tel); + Java_ContactsDialogHost_showDialog( + env, dialog_, multiple, include_names, include_emails, include_tel, + base::android::ConvertUTF16ToJavaString(env, formatted_origin_)); } void ContactsProviderAndroid::AddContact( diff --git a/chromium/content/browser/contacts/contacts_provider_android.h b/chromium/content/browser/contacts/contacts_provider_android.h index 9276052ba4f..60ed7854c88 100644 --- a/chromium/content/browser/contacts/contacts_provider_android.h +++ b/chromium/content/browser/contacts/contacts_provider_android.h @@ -7,6 +7,7 @@ #include "base/android/jni_array.h" #include "base/android/scoped_java_ref.h" +#include "base/strings/string16.h" #include "content/browser/contacts/contacts_provider.h" #include "content/common/content_export.h" #include "third_party/blink/public/mojom/contacts/contacts_manager.mojom.h" @@ -56,6 +57,10 @@ class ContactsProviderAndroid : public ContactsProvider { // The list of contacts to return. std::vector<blink::mojom::ContactInfoPtr> contacts_; + // The origin that the contacts data will be shared with. Formatted for + // display with the scheme omitted. + base::string16 formatted_origin_; + DISALLOW_COPY_AND_ASSIGN(ContactsProviderAndroid); }; diff --git a/chromium/content/browser/devtools/devtools_session.cc b/chromium/content/browser/devtools/devtools_session.cc index f498b0db1ec..debd425dc04 100644 --- a/chromium/content/browser/devtools/devtools_session.cc +++ b/chromium/content/browser/devtools/devtools_session.cc @@ -143,6 +143,12 @@ void DevToolsSession::MojoConnectionDestroyed() { } bool DevToolsSession::DispatchProtocolMessage(const std::string& message) { + if (proxy_delegate_) { + // Note: we assume that child sessions are not forwarding. + proxy_delegate_->SendMessageToBackend(this, message); + return true; + } + std::unique_ptr<base::DictionaryValue> parsed_message = base::DictionaryValue::From(base::JSONReader::Read(message)); @@ -154,6 +160,7 @@ bool DevToolsSession::DispatchProtocolMessage(const std::string& message) { if (it == child_sessions_.end()) return false; DevToolsSession* session = it->second; + DCHECK(!session->proxy_delegate_); return session->DispatchProtocolMessageInternal(message, std::move(parsed_message)); } @@ -166,11 +173,6 @@ bool DevToolsSession::DispatchProtocolMessageInternal( std::move(runtime_resume_).Run(); } - if (proxy_delegate_) { - proxy_delegate_->SendMessageToBackend(this, message); - return true; - } - DevToolsManagerDelegate* delegate = DevToolsManager::GetInstance()->delegate(); if (delegate && parsed_message) { diff --git a/chromium/content/browser/file_url_loader_factory.cc b/chromium/content/browser/file_url_loader_factory.cc index 61494efeae4..5cc14df0b4a 100644 --- a/chromium/content/browser/file_url_loader_factory.cc +++ b/chromium/content/browser/file_url_loader_factory.cc @@ -850,6 +850,7 @@ void CreateFileURLLoader( network::mojom::URLLoaderRequest loader, network::mojom::URLLoaderClientPtr client, std::unique_ptr<FileURLLoaderObserver> observer, + bool allow_directory_listing, scoped_refptr<net::HttpResponseHeaders> extra_response_headers) { // TODO(crbug.com/924416): Re-evaluate how TaskPriority is set here and in // other file URL-loading-related code. Some callers require USER_VISIBLE @@ -859,12 +860,13 @@ void CreateFileURLLoader( base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); task_runner->PostTask( FROM_HERE, - base::BindOnce(&FileURLLoader::CreateAndStart, base::FilePath(), request, - std::move(loader), client.PassInterface(), - DirectoryLoadingPolicy::kFail, - FileAccessPolicy::kUnrestricted, - LinkFollowingPolicy::kDoNotFollow, std::move(observer), - std::move(extra_response_headers))); + base::BindOnce( + &FileURLLoader::CreateAndStart, base::FilePath(), request, + std::move(loader), client.PassInterface(), + allow_directory_listing ? DirectoryLoadingPolicy::kRespondWithListing + : DirectoryLoadingPolicy::kFail, + FileAccessPolicy::kUnrestricted, LinkFollowingPolicy::kDoNotFollow, + std::move(observer), std::move(extra_response_headers))); } std::unique_ptr<network::mojom::URLLoaderFactory> CreateFileURLLoaderFactory( diff --git a/chromium/content/browser/frame_host/interstitial_page_impl.cc b/chromium/content/browser/frame_host/interstitial_page_impl.cc index a97648ef717..de100cad56f 100644 --- a/chromium/content/browser/frame_host/interstitial_page_impl.cc +++ b/chromium/content/browser/frame_host/interstitial_page_impl.cc @@ -782,6 +782,7 @@ void InterstitialPageImpl::CreateNewWindow( int32_t main_frame_route_id, int32_t main_frame_widget_route_id, const mojom::CreateNewWindowParams& params, + bool has_user_gesture, SessionStorageNamespace* session_storage_namespace) { NOTREACHED() << "InterstitialPage does not support showing popups."; } diff --git a/chromium/content/browser/frame_host/interstitial_page_impl.h b/chromium/content/browser/frame_host/interstitial_page_impl.h index c3c81b842d3..783112ed2d0 100644 --- a/chromium/content/browser/frame_host/interstitial_page_impl.h +++ b/chromium/content/browser/frame_host/interstitial_page_impl.h @@ -130,6 +130,7 @@ class CONTENT_EXPORT InterstitialPageImpl : public InterstitialPage, int32_t main_frame_route_id, int32_t main_frame_widget_route_id, const mojom::CreateNewWindowParams& params, + bool has_user_gesture, SessionStorageNamespace* session_storage_namespace) override; void ShowCreatedWindow(int process_id, int main_frame_widget_route_id, diff --git a/chromium/content/browser/frame_host/navigation_controller_impl.cc b/chromium/content/browser/frame_host/navigation_controller_impl.cc index 744a1d2343f..a28b7c8a394 100644 --- a/chromium/content/browser/frame_host/navigation_controller_impl.cc +++ b/chromium/content/browser/frame_host/navigation_controller_impl.cc @@ -2522,6 +2522,12 @@ void NavigationControllerImpl::FindFramesToNavigate( ReloadType reload_type, std::vector<std::unique_ptr<NavigationRequest>>* same_document_loads, std::vector<std::unique_ptr<NavigationRequest>>* different_document_loads) { + // A frame pending deletion is not allowed to navigate anymore. It has been + // deleted and the browser already committed to destroying this + // RenderFrameHost. See https://crbug.com/930278. + if (!frame->current_frame_host()->is_active()) + return; + DCHECK(pending_entry_); DCHECK_GE(last_committed_entry_index_, 0); FrameNavigationEntry* new_item = pending_entry_->GetFrameEntry(frame); diff --git a/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc index 877c18094e2..177d6106913 100644 --- a/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc +++ b/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc @@ -7631,6 +7631,26 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, controller.GetLastCommittedEntry()->GetVirtualURL()); } +// Verifies that unsafe redirects to javascript: or other URLs create an error +// page and don't make a spoof possible. See https://crbug.com/935175. +IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, + UnsafeRedirectCreatesErrorPage) { + NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>( + shell()->web_contents()->GetController()); + + GURL start_url(embedded_test_server()->GetURL("/title1.html")); + EXPECT_TRUE(NavigateToURL(shell(), start_url)); + EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); + + // Navigating to URLs with unsafe redirects should create an error page so + // that the pending URL is not left in the address bar. + GURL redirect_to_unsafe_url( + embedded_test_server()->GetURL("/server-redirect?javascript:Hello!")); + EXPECT_FALSE(NavigateToURL(shell(), redirect_to_unsafe_url)); + EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); + EXPECT_EQ(PAGE_TYPE_ERROR, controller.GetLastCommittedEntry()->GetPageType()); +} + // Verifies that redirecting to a blocked URL and going back does not allow a // URL spoof. See https://crbug.com/777419. IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, diff --git a/chromium/content/browser/frame_host/navigation_handle_impl.cc b/chromium/content/browser/frame_host/navigation_handle_impl.cc index 244992176f0..9381de48eaf 100644 --- a/chromium/content/browser/frame_host/navigation_handle_impl.cc +++ b/chromium/content/browser/frame_host/navigation_handle_impl.cc @@ -1149,10 +1149,12 @@ void NavigationHandleImpl::RestartCommitTimeout() { RenderProcessHost* renderer_host = GetRenderFrameHost()->GetRenderWidgetHost()->GetProcess(); - render_process_blocked_state_changed_subscription_ = - renderer_host->RegisterBlockStateChangedCallback(base::BindRepeating( - &NavigationHandleImpl::RenderProcessBlockedStateChanged, - base::Unretained(this))); + if (!render_process_blocked_state_changed_subscription_) { + render_process_blocked_state_changed_subscription_ = + renderer_host->RegisterBlockStateChangedCallback(base::BindRepeating( + &NavigationHandleImpl::RenderProcessBlockedStateChanged, + base::Unretained(this))); + } if (!renderer_host->IsBlocked()) commit_timeout_timer_.Start( FROM_HERE, g_commit_timeout, diff --git a/chromium/content/browser/frame_host/navigation_request.cc b/chromium/content/browser/frame_host/navigation_request.cc index 559d0959cbf..bbb2ba40eca 100644 --- a/chromium/content/browser/frame_host/navigation_request.cc +++ b/chromium/content/browser/frame_host/navigation_request.cc @@ -897,8 +897,13 @@ void NavigationRequest::OnRequestRedirected( redirect_info.new_url)) { DVLOG(1) << "Denied redirect for " << redirect_info.new_url.possibly_invalid_spec(); - navigation_handle_->set_net_error_code(net::ERR_UNSAFE_REDIRECT); - frame_tree_node_->ResetNavigationRequest(false, true); + // Show an error page rather than leaving the previous page in place. + OnRequestFailedInternal( + network::URLLoaderCompletionStatus(net::ERR_UNSAFE_REDIRECT), + false /* skip_throttles */, base::nullopt /* error_page_content */, + false /* collapse_frame */); + // DO NOT ADD CODE after this. The previous call to OnRequestFailedInternal + // has destroyed the NavigationRequest. return; } @@ -911,8 +916,13 @@ void NavigationRequest::OnRequestRedirected( redirect_info.new_url)) { DVLOG(1) << "Denied unauthorized redirect for " << redirect_info.new_url.possibly_invalid_spec(); - navigation_handle_->set_net_error_code(net::ERR_UNSAFE_REDIRECT); - frame_tree_node_->ResetNavigationRequest(false, true); + // Show an error page rather than leaving the previous page in place. + OnRequestFailedInternal( + network::URLLoaderCompletionStatus(net::ERR_UNSAFE_REDIRECT), + false /* skip_throttles */, base::nullopt /* error_page_content */, + false /* collapse_frame */); + // DO NOT ADD CODE after this. The previous call to OnRequestFailedInternal + // has destroyed the NavigationRequest. return; } diff --git a/chromium/content/browser/frame_host/render_frame_host_delegate.h b/chromium/content/browser/frame_host/render_frame_host_delegate.h index b8e79580256..73ea2f77469 100644 --- a/chromium/content/browser/frame_host/render_frame_host_delegate.h +++ b/chromium/content/browser/frame_host/render_frame_host_delegate.h @@ -351,6 +351,7 @@ class CONTENT_EXPORT RenderFrameHostDelegate { int32_t main_frame_route_id, int32_t main_frame_widget_route_id, const mojom::CreateNewWindowParams& params, + bool has_user_gesture, SessionStorageNamespace* session_storage_namespace) {} // Show a previously created page with the specified disposition and bounds. diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.cc b/chromium/content/browser/frame_host/render_frame_host_impl.cc index b4a3b637fa6..fcda9392b8a 100644 --- a/chromium/content/browser/frame_host/render_frame_host_impl.cc +++ b/chromium/content/browser/frame_host/render_frame_host_impl.cc @@ -1974,6 +1974,24 @@ void RenderFrameHostImpl::SetLastCommittedOriginForTesting( SetLastCommittedOrigin(origin); } +void RenderFrameHostImpl::SetOriginOfNewFrame( + const url::Origin& new_frame_creator) { + // This method should only be called for *new* frames, that haven't committed + // a navigation yet. + DCHECK(!has_committed_any_navigation_); + DCHECK(GetLastCommittedOrigin().opaque()); + + // Calculate and set |new_frame_origin|. + bool new_frame_should_be_sandboxed = + blink::WebSandboxFlags::kOrigin == + (frame_tree_node()->active_sandbox_flags() & + blink::WebSandboxFlags::kOrigin); + url::Origin new_frame_origin = new_frame_should_be_sandboxed + ? new_frame_creator.DeriveNewOpaqueOrigin() + : new_frame_creator; + SetLastCommittedOrigin(new_frame_origin); +} + FrameTreeNode* RenderFrameHostImpl::AddChild( std::unique_ptr<FrameTreeNode> child, int process_id, @@ -1994,8 +2012,12 @@ FrameTreeNode* RenderFrameHostImpl::AddChild( // in a frame tree should have the same set of proxies. frame_tree_node_->render_manager()->CreateProxiesForChildFrame(child.get()); - children_.push_back(std::move(child)); + // When the child is added, it hasn't committed any navigation yet - its + // initial empty document should inherit the origin of its parent (the origin + // may change after the first commit). See also https://crbug.com/932067. + child->current_frame_host()->SetOriginOfNewFrame(GetLastCommittedOrigin()); + children_.push_back(std::move(child)); return children_.back().get(); } @@ -2303,16 +2325,15 @@ void RenderFrameHostImpl::DidCommitSameDocumentNavigation( frame_tree_node()->frame_tree()->root()->current_origin()); ScopedCommitStateResetter commit_state_resetter(this); - // If we're waiting for an unload ack from this frame and we receive a commit - // message, then the frame was navigating before it received the unload - // request. It will either respond to the unload request soon or our timer - // will expire. Either way, we should ignore this message, because we have - // already committed to destroying this RenderFrameHost. Note that we - // intentionally do not ignore commits that happen while the current tab is - // being closed - see https://crbug.com/805705. + // When the frame is pending deletion, the browser is waiting for it to unload + // properly. In the meantime, because of race conditions, it might tries to + // commit a same-document navigation before unloading. Similarly to what is + // done with cross-document navigations, such navigation are ignored. The + // browser already committed to destroying this RenderFrameHost. + // See https://crbug.com/805705 and https://crbug.com/930132. // TODO(ahemery): Investigate to see if this can be removed when the // NavigationClient interface is implemented. - if (is_waiting_for_swapout_ack_) + if (!is_active()) return; TRACE_EVENT2("navigation", @@ -3728,10 +3749,11 @@ void RenderFrameHostImpl::CreateNewWindow( effective_transient_activation_state, params->opener_suppressed, &no_javascript_access); + bool was_consumed = false; if (can_create_window) { // Consume activation even w/o User Activation v2, to sync other renderers // with calling renderer. - frame_tree_node_->UpdateUserActivationState( + was_consumed = frame_tree_node_->UpdateUserActivationState( blink::UserActivationUpdateType::kConsumeTransientActivation); } @@ -3800,9 +3822,13 @@ void RenderFrameHostImpl::CreateNewWindow( DCHECK(IsRenderFrameLive()); + bool opened_by_user_activation = params->mimic_user_gesture; + if (base::FeatureList::IsEnabled(features::kUserActivationV2)) + opened_by_user_activation = was_consumed; + delegate_->CreateNewWindow(this, render_view_route_id, main_frame_route_id, main_frame_widget_route_id, *params, - cloned_namespace.get()); + opened_by_user_activation, cloned_namespace.get()); if (main_frame_route_id == MSG_ROUTING_NONE) { // Opener suppressed or Javascript access disabled. Never tell the renderer @@ -3830,6 +3856,16 @@ void RenderFrameHostImpl::CreateNewWindow( RenderFrameHostImpl::FromID(GetProcess()->GetID(), main_frame_route_id); DCHECK(rfh); + // When the popup is created, it hasn't committed any navigation yet - its + // initial empty document should inherit the origin of its opener (the origin + // may change after the first commit). See also https://crbug.com/932067. + // + // Note that that origin of the new frame might depend on sandbox flags. + // Checking sandbox flags of the new frame should be safe at this point, + // because the flags should be already inherited by the CreateNewWindow call + // above. + rfh->SetOriginOfNewFrame(GetLastCommittedOrigin()); + if (base::FeatureList::IsEnabled(network::features::kNetworkService) && rfh->waiting_for_init_) { // Need to check |waiting_for_init_| as some paths inside CreateNewWindow diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.h b/chromium/content/browser/frame_host/render_frame_host_impl.h index b7e5b4e09dc..62887439c36 100644 --- a/chromium/content/browser/frame_host/render_frame_host_impl.h +++ b/chromium/content/browser/frame_host/render_frame_host_impl.h @@ -1350,6 +1350,11 @@ class CONTENT_EXPORT RenderFrameHostImpl // Update this frame's last committed origin. void SetLastCommittedOrigin(const url::Origin& origin); + // Set the |last_committed_origin_| of |this| frame, inheriting the origin + // from |new_frame_creator| as appropriate (e.g. depending on whether |this| + // frame should be sandboxed / should have an opaque origin instead). + void SetOriginOfNewFrame(const url::Origin& new_frame_creator); + // Called when a navigation commits succesfully to |url|. This will update // |last_committed_site_url_| with the site URL corresponding to |url|. // Note that this will recompute the site URL from |url| rather than using diff --git a/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc index c108626dd91..d435492c4a1 100644 --- a/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc +++ b/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc @@ -2016,4 +2016,226 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, EXPECT_EQ(0, process->get_media_stream_count_for_testing()); } +IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, + OriginOfFreshFrame_Subframe_NavCancelledByDocWrite) { + WebContents* web_contents = shell()->web_contents(); + NavigationController& controller = web_contents->GetController(); + GURL main_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); + ASSERT_TRUE(NavigateToURL(shell(), main_url)); + EXPECT_EQ(1, controller.GetEntryCount()); + url::Origin main_origin = url::Origin::Create(main_url); + + // document.open should cancel the cross-origin navigation to '/hung' and the + // subframe should remain on the parent/initiator origin. + const char kScriptTemplate[] = R"( + const frame = document.createElement('iframe'); + frame.src = $1; + document.body.appendChild(frame); + + const html = '<!DOCTYPE html><html><body>Hello world!</body></html>'; + const doc = frame.contentDocument; + doc.open(); + doc.write(html); + doc.close(); + + frame.contentWindow.origin; + )"; + GURL cross_site_url(embedded_test_server()->GetURL("bar.com", "/hung")); + std::string script = JsReplace(kScriptTemplate, cross_site_url); + EXPECT_EQ(main_origin.Serialize(), EvalJs(web_contents, script)); + + // The subframe navigation should be cancelled and therefore shouldn't + // contribute an extra history entry. + EXPECT_EQ(1, controller.GetEntryCount()); + + // Browser-side origin should match the renderer-side origin. + // See also https://crbug.com/932067. + ASSERT_EQ(2u, web_contents->GetAllFrames().size()); + RenderFrameHost* subframe = web_contents->GetAllFrames()[1]; + EXPECT_EQ(main_origin, subframe->GetLastCommittedOrigin()); +} + +class RenderFrameHostCreatedObserver : public WebContentsObserver { + public: + explicit RenderFrameHostCreatedObserver(WebContents* web_contents) + : WebContentsObserver(web_contents) {} + + RenderFrameHost* Wait() { + if (!new_frame_) + run_loop_.Run(); + + return new_frame_; + } + + private: + void RenderFrameCreated(RenderFrameHost* render_frame_host) override { + new_frame_ = render_frame_host; + run_loop_.Quit(); + } + + base::RunLoop run_loop_; + RenderFrameHost* new_frame_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver); +}; + +IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, + OriginOfFreshFrame_SandboxedSubframe) { + WebContents* web_contents = shell()->web_contents(); + NavigationController& controller = web_contents->GetController(); + GURL main_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); + ASSERT_TRUE(NavigateToURL(shell(), main_url)); + EXPECT_EQ(1, controller.GetEntryCount()); + url::Origin main_origin = url::Origin::Create(main_url); + + // Navigate a sandboxed frame to a cross-origin '/hung'. + RenderFrameHostCreatedObserver subframe_observer(web_contents); + const char kScriptTemplate[] = R"( + const frame = document.createElement('iframe'); + frame.sandbox = 'allow-scripts'; + frame.src = $1; + document.body.appendChild(frame); + )"; + GURL cross_site_url(embedded_test_server()->GetURL("bar.com", "/hung")); + std::string script = JsReplace(kScriptTemplate, cross_site_url); + EXPECT_TRUE(ExecJs(web_contents, script)); + + // Wait for a new subframe, but ignore the frame returned by + // |subframe_observer| (it might be the speculative one, not the current one). + subframe_observer.Wait(); + ASSERT_EQ(2u, web_contents->GetAllFrames().size()); + RenderFrameHost* subframe = web_contents->GetAllFrames()[1]; + + // The browser-side origin of the *sandboxed* subframe should be set to an + // *opaque* origin (with the parent's origin as the precursor origin). + EXPECT_TRUE(subframe->GetLastCommittedOrigin().opaque()); + EXPECT_EQ( + main_origin.GetTupleOrPrecursorTupleIfOpaque(), + subframe->GetLastCommittedOrigin().GetTupleOrPrecursorTupleIfOpaque()); + + // Note that the test cannot check the renderer-side origin of the frame: + // - Scripts cannot be executed before the frame commits, + // - The parent cannot document.write into the *sandboxed* frame. +} + +IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, + OriginOfFreshFrame_Subframe_AboutBlankAndThenDocWrite) { + WebContents* web_contents = shell()->web_contents(); + NavigationController& controller = web_contents->GetController(); + GURL main_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); + ASSERT_TRUE(NavigateToURL(shell(), main_url)); + EXPECT_EQ(1, controller.GetEntryCount()); + url::Origin main_origin = url::Origin::Create(main_url); + + // Create a new about:blank subframe and document.write into it. + TestNavigationObserver load_observer(web_contents); + RenderFrameHostCreatedObserver subframe_observer(web_contents); + const char kScript[] = R"( + const frame = document.createElement('iframe'); + // Don't set |frame.src| - have the frame commit an initial about:blank. + document.body.appendChild(frame); + + const html = '<!DOCTYPE html><html><body>Hello world!</body></html>'; + const doc = frame.contentDocument; + doc.open(); + doc.write(html); + doc.close(); + )"; + ExecuteScriptAsync(web_contents, kScript); + + // Wait for the new subframe to be created - this will be still before the + // commit of about:blank. + RenderFrameHost* subframe = subframe_observer.Wait(); + EXPECT_EQ(main_origin, subframe->GetLastCommittedOrigin()); + + // Wait for the about:blank navigation to finish. + load_observer.Wait(); + + // The subframe commit to about:blank should not contribute an extra history + // entry. + EXPECT_EQ(1, controller.GetEntryCount()); + + // Browser-side origin should match the renderer-side origin. + // See also https://crbug.com/932067. + ASSERT_EQ(2u, web_contents->GetAllFrames().size()); + RenderFrameHost* subframe2 = web_contents->GetAllFrames()[1]; + EXPECT_EQ(subframe, subframe2); // No swaps are expected. + EXPECT_EQ(main_origin, subframe2->GetLastCommittedOrigin()); + EXPECT_EQ(main_origin.Serialize(), EvalJs(subframe2, "window.origin")); +} + +IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, + OriginOfFreshFrame_Popup_NavCancelledByDocWrite) { + WebContents* web_contents = shell()->web_contents(); + GURL main_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); + ASSERT_TRUE(NavigateToURL(shell(), main_url)); + url::Origin main_origin = url::Origin::Create(main_url); + + // document.open should cancel the cross-origin navigation to '/hung' and the + // popup should remain on the initiator origin. + WebContentsAddedObserver popup_observer; + const char kScriptTemplate[] = R"( + var popup = window.open($1, 'popup'); + + const html = '<!DOCTYPE html><html><body>Hello world!</body></html>'; + const doc = popup.document; + doc.open(); + doc.write(html); + doc.close(); + + popup.origin; + )"; + GURL cross_site_url(embedded_test_server()->GetURL("bar.com", "/hung")); + std::string script = JsReplace(kScriptTemplate, cross_site_url); + EXPECT_EQ(main_origin.Serialize(), EvalJs(web_contents, script)); + + // Browser-side origin should match the renderer-side origin. + // See also https://crbug.com/932067. + WebContents* popup = popup_observer.GetWebContents(); + EXPECT_EQ(main_origin, popup->GetMainFrame()->GetLastCommittedOrigin()); + + // The popup navigation should be cancelled and therefore shouldn't + // contribute an extra history entry. + EXPECT_EQ(0, popup->GetController().GetEntryCount()); +} + +IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, + OriginOfFreshFrame_Popup_AboutBlankAndThenDocWrite) { + WebContents* web_contents = shell()->web_contents(); + GURL main_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); + ASSERT_TRUE(NavigateToURL(shell(), main_url)); + url::Origin main_origin = url::Origin::Create(main_url); + + // Create a new about:blank popup and document.write into it. + WebContentsAddedObserver popup_observer; + TestNavigationObserver load_observer(web_contents); + const char kScript[] = R"( + // Empty |url| argument means that the popup will commit an initial + // about:blank. + var popup = window.open('', 'popup'); + + const html = '<!DOCTYPE html><html><body>Hello world!</body></html>'; + const doc = popup.document; + doc.open(); + doc.write(html); + doc.close(); + )"; + ExecuteScriptAsync(web_contents, kScript); + + // Wait for the new popup to be created (this will be before the popup commits + // the initial about:blank page). + WebContents* popup = popup_observer.GetWebContents(); + EXPECT_EQ(main_origin, popup->GetMainFrame()->GetLastCommittedOrigin()); + + // A round-trip to the renderer process is an indirect way to wait for + // DidCommitProvisionalLoad IPC for the initial about:blank page. + // WaitForLoadStop cannot be used, because this commit won't raise + // NOTIFICATION_LOAD_STOP. + EXPECT_EQ(123, EvalJs(popup, "123")); + EXPECT_EQ(main_origin, popup->GetMainFrame()->GetLastCommittedOrigin()); + + // The about:blank navigation shouldn't contribute an extra history entry. + EXPECT_EQ(0, popup->GetController().GetEntryCount()); +} + } // namespace content diff --git a/chromium/content/browser/frame_host/render_frame_host_manager.cc b/chromium/content/browser/frame_host/render_frame_host_manager.cc index dce34d55315..f9f8e5204d1 100644 --- a/chromium/content/browser/frame_host/render_frame_host_manager.cc +++ b/chromium/content/browser/frame_host/render_frame_host_manager.cc @@ -515,9 +515,7 @@ RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation( // See https://crbug.com/926820 and https://crbug.com/927705. if (!current_frame_host()->is_active()) { NOTREACHED() << "Navigation in an inactive frame"; - NavigationHandle* handle = request.navigation_handle(); - DEBUG_ALIAS_FOR_GURL(url_from, handle->GetPreviousURL()) - DEBUG_ALIAS_FOR_GURL(url_to, handle->GetURL()) + DEBUG_ALIAS_FOR_GURL(url, request.common_params().url); base::debug::DumpWithoutCrashing(); } diff --git a/chromium/content/browser/frame_host/render_frame_message_filter.cc b/chromium/content/browser/frame_host/render_frame_message_filter.cc index 789c4061262..ec1c286b421 100644 --- a/chromium/content/browser/frame_host/render_frame_message_filter.cc +++ b/chromium/content/browser/frame_host/render_frame_message_filter.cc @@ -620,10 +620,14 @@ void RenderFrameMessageFilter::SetCookie(int32_t render_frame_id, return; } + // |callback| needs to be fired even if network process crashes as it's for + // sync IPC. net::CookieStore::SetCookiesCallback net_callback = - base::BindOnce([](SetCookieCallback callback, - bool success) { std::move(callback).Run(); }, - std::move(callback)); + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce([](SetCookieCallback callback, + bool success) { std::move(callback).Run(); }, + std::move(callback)), + false); (*GetCookieManager()) ->SetCanonicalCookie(*cookie, url.SchemeIsCryptographic(), !options.exclude_httponly(), @@ -689,9 +693,11 @@ void RenderFrameMessageFilter::GetCookies(int render_frame_id, (*GetCookieManager()) ->GetCookieList( url, options, - base::BindOnce(&RenderFrameMessageFilter::CheckPolicyForCookies, this, - render_frame_id, url, site_for_cookies, - std::move(callback))); + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce(&RenderFrameMessageFilter::CheckPolicyForCookies, + this, render_frame_id, url, site_for_cookies, + std::move(callback)), + net::CookieList())); } #if BUILDFLAG(ENABLE_PLUGINS) diff --git a/chromium/content/browser/frame_host/render_frame_proxy_host.cc b/chromium/content/browser/frame_host/render_frame_proxy_host.cc index f075640df52..a5e18f465f7 100644 --- a/chromium/content/browser/frame_host/render_frame_proxy_host.cc +++ b/chromium/content/browser/frame_host/render_frame_proxy_host.cc @@ -302,9 +302,15 @@ void RenderFrameProxyHost::OnOpenURL( GetSiteInstance()->GetBrowserContext(), std::move(blob_url_token)); } + RenderFrameHostImpl* current_rfh = frame_tree_node_->current_frame_host(); + + // The current_rfh may be pending deletion. In this case, ignore the + // navigation, because the frame is going to disappear soon anyway. + if (!current_rfh->is_active()) + return; + // Verify that we are in the same BrowsingInstance as the current // RenderFrameHost. - RenderFrameHostImpl* current_rfh = frame_tree_node_->current_frame_host(); if (!site_instance_->IsRelatedSiteInstance(current_rfh->GetSiteInstance())) return; diff --git a/chromium/content/browser/gpu/gpu_process_host.cc b/chromium/content/browser/gpu/gpu_process_host.cc index caf9e5fe26d..1c93dfbc345 100644 --- a/chromium/content/browser/gpu/gpu_process_host.cc +++ b/chromium/content/browser/gpu/gpu_process_host.cc @@ -242,7 +242,7 @@ static const char* const kSwitchNames[] = { #endif #if defined(USE_OZONE) switches::kOzonePlatform, - switches::kDisableExplicitDmaFences, + switches::kEnableExplicitDmaFences, switches::kOzoneDumpFile, #endif #if defined(USE_X11) diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc index 43c5c265a6c..7951ea25d94 100644 --- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc +++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc @@ -8,10 +8,12 @@ #include <limits> #include <utility> +#include "base/big_endian.h" #include "base/logging.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "base/sys_byteorder.h" +#include "build/build_config.h" // See leveldb_coding_scheme.md for detailed documentation of the coding // scheme implemented here. @@ -23,6 +25,14 @@ using blink::IndexedDBKeyPath; namespace content { namespace { +inline uint64_t ByteSwapToBE64(uint64_t x) { +#if defined(ARCH_CPU_LITTLE_ENDIAN) + return base::ByteSwap(x); +#else + return x; +#endif +} + // As most of the IndexedDBKeys and encoded values are short, we // initialize some std::vectors with a default inline buffer size to reduce // the memory re-allocations when the std::vectors are appended. @@ -1005,22 +1015,25 @@ int CompareIndexKeys(const StringPiece& a, const StringPiece& b) { } ScopeLockRange GetDatabaseLockRange(int64_t database_id) { - uint64_t first[1] = { - base::ByteSwapToLE64(static_cast<uint64_t>(database_id))}; - uint64_t next[1] = { - base::ByteSwapToLE64(static_cast<uint64_t>(database_id + 1))}; + // The numbers are transformed into big-endian to make them + // bytewise-comparable. Eventually, these lock ranges should just match the + // leveldb keys when they are bytewise-comparable. + uint64_t first[1] = {ByteSwapToBE64(static_cast<uint64_t>(database_id))}; + uint64_t next[1] = {ByteSwapToBE64(static_cast<uint64_t>(database_id + 1))}; return {std::string(reinterpret_cast<char*>(&first), sizeof(first)), std::string(reinterpret_cast<char*>(&next), sizeof(next))}; } ScopeLockRange GetObjectStoreLockRange(int64_t database_id, int64_t object_store_id) { - uint64_t first[2] = { - base::ByteSwapToLE64(static_cast<uint64_t>(database_id)), - base::ByteSwapToLE64(static_cast<uint64_t>(object_store_id))}; + // The numbers are transformed into big-endian to make them + // bytewise-comparable. Eventually, these lock ranges should just match the + // leveldb keys when they are bytewise-comparable. + uint64_t first[2] = {ByteSwapToBE64(static_cast<uint64_t>(database_id)), + ByteSwapToBE64(static_cast<uint64_t>(object_store_id))}; uint64_t next[2] = { - base::ByteSwapToLE64(static_cast<uint64_t>(database_id)), - base::ByteSwapToLE64(static_cast<uint64_t>(object_store_id + 1))}; + ByteSwapToBE64(static_cast<uint64_t>(database_id)), + ByteSwapToBE64(static_cast<uint64_t>(object_store_id + 1))}; return {std::string(reinterpret_cast<char*>(&first), sizeof(first)), std::string(reinterpret_cast<char*>(&next), sizeof(next))}; } diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h index afa5ce76dd6..539d31f59c1 100644 --- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h +++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h @@ -112,9 +112,9 @@ const constexpr int kDatabaseRangeLockLevel = 0; const constexpr int kObjectStoreRangeLockLevel = 1; const constexpr int kIndexedDBLockLevelCount = 2; -ScopeLockRange GetDatabaseLockRange(int64_t database_id); -ScopeLockRange GetObjectStoreLockRange(int64_t database_id, - int64_t object_store_id); +CONTENT_EXPORT ScopeLockRange GetDatabaseLockRange(int64_t database_id); +CONTENT_EXPORT ScopeLockRange GetObjectStoreLockRange(int64_t database_id, + int64_t object_store_id); // TODO(dmurph): Modify all decoding methods to return something more sensible, // as it is not obvious that they modify the input slice to remove the decoded diff --git a/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc b/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc index 17eea2e156e..8bebd1591b2 100644 --- a/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc +++ b/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc @@ -113,7 +113,7 @@ bool DisjointRangeLockManager::AcquireLock( if (it == level_locks.end()) { it = level_locks .emplace(std::piecewise_construct, - std::forward_as_tuple(request.range), + std::forward_as_tuple(std::move(request.range)), std::forward_as_tuple()) .first; } @@ -127,7 +127,7 @@ bool DisjointRangeLockManager::AcquireLock( lock.lock_mode = request.type; auto released_callback = base::BindOnce( &DisjointRangeLockManager::LockReleased, weak_factory_.GetWeakPtr(), - request.level, request.range); + request.level, std::move(request.range)); std::move(acquired_callback) .Run(ScopeLock(std::move(request.range), request.level, std::move(released_callback))); diff --git a/chromium/content/browser/indexed_db/scopes/scope_lock_range.h b/chromium/content/browser/indexed_db/scopes/scope_lock_range.h index 1e68794aef5..bf276eae02f 100644 --- a/chromium/content/browser/indexed_db/scopes/scope_lock_range.h +++ b/chromium/content/browser/indexed_db/scopes/scope_lock_range.h @@ -4,8 +4,9 @@ #ifndef CONTENT_BROWSER_INDEXED_DB_SCOPES_SCOPE_LOCK_RANGE_H_ #define CONTENT_BROWSER_INDEXED_DB_SCOPES_SCOPE_LOCK_RANGE_H_ +#include <stdint.h> #include <iosfwd> -#include <string> +#include <vector> #include "base/logging.h" #include "content/common/content_export.h" @@ -21,6 +22,8 @@ struct CONTENT_EXPORT ScopeLockRange { ~ScopeLockRange() = default; std::string begin; std::string end; + + bool IsValid() const { return begin < end; } }; // Logging support. diff --git a/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.h b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.h index 7093b68dbf3..6b336b954e7 100644 --- a/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.h +++ b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.h @@ -37,11 +37,10 @@ class CONTENT_EXPORT ScopesLockManager { // Acquires locks for the given requests. Lock levels are treated as // completely independent domains. The lock levels start at zero. - // Returns false if any of the lock ranges were invalid or an invarient was + // Returns false if any of the lock ranges were invalid or an invariant was // broken. struct CONTENT_EXPORT ScopeLockRequest { ScopeLockRequest(int level, ScopeLockRange range, LockType type); - ~ScopeLockRequest() = default; int level; ScopeLockRange range; LockType type; diff --git a/chromium/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc index b4d9e42594e..c00ac488ea4 100644 --- a/chromium/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc +++ b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc @@ -8,15 +8,45 @@ #include "base/bind.h" #include "base/test/bind_test_util.h" +#include "content/browser/indexed_db/indexed_db_leveldb_coding.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { namespace { TEST(ScopesLockManager, TestRangePopulation) { - ScopeLockRange range{"a", "b"}; - EXPECT_EQ("a", range.begin); - EXPECT_EQ("b", range.end); + ScopeLockRange range = {"1", "2"}; + EXPECT_EQ("1", range.begin); + EXPECT_EQ("2", range.end); + EXPECT_TRUE(range.IsValid()); +} + +TEST(ScopesLockManager, TestInvalidRange) { + ScopeLockRange range = {"2", "1"}; + EXPECT_FALSE(range.IsValid()); + range = {"2", "2"}; + EXPECT_FALSE(range.IsValid()); +} + +TEST(ScopesLockManager, TestRangeDifferences) { + ScopeLockRange range_db1; + ScopeLockRange range_db2; + ScopeLockRange range_db1_os1; + ScopeLockRange range_db1_os2; + for (int64_t i = 0; i < 512; ++i) { + range_db1 = GetDatabaseLockRange(i); + range_db2 = GetDatabaseLockRange(i + 1); + range_db1_os1 = GetObjectStoreLockRange(i, i); + range_db1_os2 = GetObjectStoreLockRange(i, i + 1); + EXPECT_TRUE(range_db1.IsValid() && range_db2.IsValid() && + range_db1_os1.IsValid() && range_db1_os2.IsValid()); + EXPECT_LT(range_db1, range_db2); + EXPECT_LT(range_db1, range_db1_os1); + EXPECT_LT(range_db1, range_db1_os2); + EXPECT_LT(range_db1_os1, range_db1_os2); + EXPECT_LT(range_db1_os1, range_db2); + EXPECT_LT(range_db1_os2, range_db2); + } } } // namespace diff --git a/chromium/content/browser/loader/loader_browsertest.cc b/chromium/content/browser/loader/loader_browsertest.cc index cfe0b988b5a..f249009f172 100644 --- a/chromium/content/browser/loader/loader_browsertest.cc +++ b/chromium/content/browser/loader/loader_browsertest.cc @@ -152,6 +152,7 @@ IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, SniffHTMLWithNoContentType) { CheckTitleTest( net::URLRequestMockHTTPJob::GetMockUrl("content-sniffer-test0.html"), "Content Sniffer Test 0"); + EXPECT_EQ("text/html", shell()->web_contents()->GetContentsMimeType()); } IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, RespectNoSniffDirective) { @@ -161,16 +162,18 @@ IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, RespectNoSniffDirective) { CheckTitleTest(net::URLRequestMockHTTPJob::GetMockUrl("nosniff-test.html"), "mock.http/nosniff-test.html"); + EXPECT_EQ("text/plain", shell()->web_contents()->GetContentsMimeType()); } IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, DoNotSniffHTMLFromTextPlain) { - // Covered by URLLoaderTest.DoNotSniffHTMLFromTextPlain. + // Covered by URLLoaderTest.SniffTextPlainDoesNotResultInHTML. if (base::FeatureList::IsEnabled(network::features::kNetworkService)) return; CheckTitleTest( net::URLRequestMockHTTPJob::GetMockUrl("content-sniffer-test1.html"), "mock.http/content-sniffer-test1.html"); + EXPECT_EQ("text/plain", shell()->web_contents()->GetContentsMimeType()); } IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, DoNotSniffHTMLFromImageGIF) { @@ -181,6 +184,7 @@ IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, DoNotSniffHTMLFromImageGIF) { CheckTitleTest( net::URLRequestMockHTTPJob::GetMockUrl("content-sniffer-test2.html"), "mock.http/content-sniffer-test2.html"); + EXPECT_EQ("image/gif", shell()->web_contents()->GetContentsMimeType()); } IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, SniffNoContentTypeNoData) { diff --git a/chromium/content/browser/loader/navigation_url_loader_impl_unittest.cc b/chromium/content/browser/loader/navigation_url_loader_impl_unittest.cc index 638d4f646f8..9b49c3f5d7c 100644 --- a/chromium/content/browser/loader/navigation_url_loader_impl_unittest.cc +++ b/chromium/content/browser/loader/navigation_url_loader_impl_unittest.cc @@ -32,6 +32,7 @@ #include "content/public/test/test_browser_thread_bundle.h" #include "content/test/test_navigation_url_loader_delegate.h" #include "net/base/load_flags.h" +#include "net/base/mock_network_change_notifier.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/url_request_context.h" @@ -294,6 +295,7 @@ class NavigationURLLoaderImplTest : public testing::Test { base::test::ScopedFeatureList feature_list_; TestBrowserThreadBundle thread_bundle_; std::unique_ptr<TestBrowserContext> browser_context_; + net::test::MockNetworkChangeNotifier network_change_notifier_; net::EmbeddedTestServer http_test_server_; base::Optional<network::ResourceRequest> most_recent_resource_request_; }; diff --git a/chromium/content/browser/loader/source_stream_to_data_pipe.cc b/chromium/content/browser/loader/source_stream_to_data_pipe.cc index 569344921a8..c3923e59262 100644 --- a/chromium/content/browser/loader/source_stream_to_data_pipe.cc +++ b/chromium/content/browser/loader/source_stream_to_data_pipe.cc @@ -65,16 +65,12 @@ void SourceStreamToDataPipe::ReadMore() { void SourceStreamToDataPipe::DidRead(int result) { DCHECK(pending_write_); - if (result < 0) { - // An error case. + if (result <= 0) { + // An error, or end of the stream. + pending_write_->Complete(0); // Closes the data pipe. OnComplete(result); return; } - if (result == 0) { - pending_write_->Complete(0); - OnComplete(net::OK); - return; - } dest_ = pending_write_->Complete(result); pending_write_ = nullptr; @@ -97,7 +93,7 @@ void SourceStreamToDataPipe::OnComplete(int result) { // Resets the watchers, pipes and the exchange handler, so that // we will never be called back. writable_handle_watcher_.Cancel(); - pending_write_ = nullptr; // Closes the data pipe if this was holding it. + pending_write_ = nullptr; dest_.reset(); std::move(completion_callback_).Run(result); diff --git a/chromium/content/browser/media/session/media_session_impl.cc b/chromium/content/browser/media/session/media_session_impl.cc index a83f7a50ea8..25867580366 100644 --- a/chromium/content/browser/media/session/media_session_impl.cc +++ b/chromium/content/browser/media/session/media_session_impl.cc @@ -214,6 +214,22 @@ void MediaSessionImpl::NotifyMediaSessionMetadataChange() { }); } +void MediaSessionImpl::OnWebContentsFocused(RenderWidgetHost*) { + focused_ = true; + +#if !defined(OS_ANDROID) && !defined(OS_MACOSX) + // If we have just gained focus and we have audio focus we should re-request + // system audio focus. This will ensure this media session is towards the top + // of the stack if we have multiple sessions active at the same time. + if (audio_focus_state_ == State::ACTIVE) + RequestSystemAudioFocus(desired_audio_focus_type_); +#endif +} + +void MediaSessionImpl::OnWebContentsLostFocus(RenderWidgetHost*) { + focused_ = false; +} + bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer, int player_id, media::MediaContentType media_content_type) { @@ -396,7 +412,7 @@ void MediaSessionImpl::Resume(SuspendType suspend_type) { } MediaSessionUmaHelper::RecordMediaSessionUserAction( - MediaSessionUmaHelper::MediaSessionUserAction::PlayDefault); + MediaSessionUmaHelper::MediaSessionUserAction::PlayDefault, focused_); } // When the resume requests comes from another source than system, audio focus @@ -432,7 +448,7 @@ void MediaSessionImpl::Suspend(SuspendType suspend_type) { } MediaSessionUmaHelper::RecordMediaSessionUserAction( - MediaSessionUserAction::PauseDefault); + MediaSessionUserAction::PauseDefault, focused_); } OnSuspendInternal(suspend_type, State::SUSPENDED); @@ -445,7 +461,7 @@ void MediaSessionImpl::Stop(SuspendType suspend_type) { if (suspend_type == SuspendType::kUI) { MediaSessionUmaHelper::RecordMediaSessionUserAction( - MediaSessionUmaHelper::MediaSessionUserAction::StopDefault); + MediaSessionUmaHelper::MediaSessionUserAction::StopDefault, focused_); } // TODO(mlamouri): merge the logic between UI and SYSTEM. @@ -677,6 +693,11 @@ MediaSessionImpl::MediaSessionImpl(WebContents* web_contents) #if defined(OS_ANDROID) session_android_.reset(new MediaSessionAndroid(this)); #endif // defined(OS_ANDROID) + + if (web_contents && web_contents->GetMainFrame() && + web_contents->GetMainFrame()->GetView()) { + focused_ = web_contents->GetMainFrame()->GetView()->HasFocus(); + } } void MediaSessionImpl::Initialize() { @@ -978,7 +999,7 @@ void MediaSessionImpl::OnMediaSessionActionsChanged( void MediaSessionImpl::DidReceiveAction( media_session::mojom::MediaSessionAction action) { MediaSessionUmaHelper::RecordMediaSessionUserAction( - MediaSessionActionToUserAction(action)); + MediaSessionActionToUserAction(action), focused_); // Pause all players in non-routed frames if the action is PAUSE. // diff --git a/chromium/content/browser/media/session/media_session_impl.h b/chromium/content/browser/media/session/media_session_impl.h index af003f6e23f..84c26918664 100644 --- a/chromium/content/browser/media/session/media_session_impl.h +++ b/chromium/content/browser/media/session/media_session_impl.h @@ -136,6 +136,8 @@ class MediaSessionImpl : public MediaSession, void WebContentsDestroyed() override; void RenderFrameDeleted(RenderFrameHost* rfh) override; void DidFinishNavigation(NavigationHandle* navigation_handle) override; + void OnWebContentsFocused(RenderWidgetHost*) override; + void OnWebContentsLostFocus(RenderWidgetHost*) override; // MediaSessionService-related methods @@ -390,6 +392,9 @@ class MediaSessionImpl : public MediaSession, base::ObserverList<MediaSessionObserver>::Unchecked observers_; + // True if the WebContents associated with this MediaSessionImpl is focused. + bool focused_ = false; + #if defined(OS_ANDROID) std::unique_ptr<MediaSessionAndroid> session_android_; #endif // defined(OS_ANDROID) diff --git a/chromium/content/browser/media/session/media_session_impl_unittest.cc b/chromium/content/browser/media/session/media_session_impl_unittest.cc index 97596a161ad..87971f07945 100644 --- a/chromium/content/browser/media/session/media_session_impl_unittest.cc +++ b/chromium/content/browser/media/session/media_session_impl_unittest.cc @@ -575,6 +575,8 @@ TEST_F(MediaSessionImplTest, WebContentsDestroyed_StopsDucking) { } } +#if defined(OS_MACOSX) + TEST_F(MediaSessionImplTest, TabFocusDoesNotCauseAudioFocus) { MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate(); SetDelegateForTests(GetMediaSession(), delegate); @@ -591,6 +593,59 @@ TEST_F(MediaSessionImplTest, TabFocusDoesNotCauseAudioFocus) { EXPECT_EQ(1, delegate->request_audio_focus_count()); } +#else // defined(OS_MACOSX) + +TEST_F(MediaSessionImplTest, RequestAudioFocus_OnFocus_Active) { + MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate(); + SetDelegateForTests(GetMediaSession(), delegate); + + { + MockMediaSessionMojoObserver observer(*GetMediaSession()); + RequestAudioFocus(GetMediaSession(), AudioFocusType::kGain); + FlushForTesting(GetMediaSession()); + observer.WaitForState(MediaSessionInfo::SessionState::kActive); + } + + EXPECT_EQ(1, delegate->request_audio_focus_count()); + GetMediaSession()->OnWebContentsFocused(nullptr); + EXPECT_EQ(2, delegate->request_audio_focus_count()); +} + +TEST_F(MediaSessionImplTest, RequestAudioFocus_OnFocus_Inactive) { + MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate(); + SetDelegateForTests(GetMediaSession(), delegate); + EXPECT_EQ(MediaSessionInfo::SessionState::kInactive, + GetState(GetMediaSession())); + + EXPECT_EQ(0, delegate->request_audio_focus_count()); + GetMediaSession()->OnWebContentsFocused(nullptr); + EXPECT_EQ(0, delegate->request_audio_focus_count()); +} + +TEST_F(MediaSessionImplTest, RequestAudioFocus_OnFocus_Suspended) { + MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate(); + SetDelegateForTests(GetMediaSession(), delegate); + + { + MockMediaSessionMojoObserver observer(*GetMediaSession()); + RequestAudioFocus(GetMediaSession(), AudioFocusType::kGain); + FlushForTesting(GetMediaSession()); + observer.WaitForState(MediaSessionInfo::SessionState::kActive); + } + + { + MockMediaSessionMojoObserver observer(*GetMediaSession()); + GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem); + observer.WaitForState(MediaSessionInfo::SessionState::kSuspended); + } + + EXPECT_EQ(1, delegate->request_audio_focus_count()); + GetMediaSession()->OnWebContentsFocused(nullptr); + EXPECT_EQ(1, delegate->request_audio_focus_count()); +} + +#endif // defined(OS_MACOSX) + #endif // !defined(OS_ANDROID) } // namespace content diff --git a/chromium/content/browser/media/session/media_session_uma_helper.cc b/chromium/content/browser/media/session/media_session_uma_helper.cc index d9619173791..2b5359572b9 100644 --- a/chromium/content/browser/media/session/media_session_uma_helper.cc +++ b/chromium/content/browser/media/session/media_session_uma_helper.cc @@ -22,8 +22,10 @@ MediaSessionUmaHelper::~MediaSessionUmaHelper() // static void MediaSessionUmaHelper::RecordMediaSessionUserAction( - MediaSessionUserAction action) { + MediaSessionUserAction action, + bool focused) { UMA_HISTOGRAM_ENUMERATION("Media.Session.UserAction", action); + UMA_HISTOGRAM_BOOLEAN("Media.Session.UserAction.Focus", focused); } void MediaSessionUmaHelper::RecordSessionSuspended( diff --git a/chromium/content/browser/media/session/media_session_uma_helper.h b/chromium/content/browser/media/session/media_session_uma_helper.h index 4745e78ce45..1b8511ebfd8 100644 --- a/chromium/content/browser/media/session/media_session_uma_helper.h +++ b/chromium/content/browser/media/session/media_session_uma_helper.h @@ -48,7 +48,8 @@ class CONTENT_EXPORT MediaSessionUmaHelper { MediaSessionUmaHelper(); ~MediaSessionUmaHelper(); - static void RecordMediaSessionUserAction(MediaSessionUserAction action); + static void RecordMediaSessionUserAction(MediaSessionUserAction action, + bool focused); void RecordSessionSuspended(MediaSessionSuspendedSource source) const; diff --git a/chromium/content/browser/network_service_browsertest.cc b/chromium/content/browser/network_service_browsertest.cc index 5b23582e8a5..7f32646708f 100644 --- a/chromium/content/browser/network_service_browsertest.cc +++ b/chromium/content/browser/network_service_browsertest.cc @@ -28,6 +28,7 @@ #include "net/http/http_response_headers.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/network/public/cpp/features.h" +#include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/simple_url_loader.h" #include "services/network/public/mojom/network_service_test.mojom.h" @@ -300,6 +301,60 @@ IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest, EXPECT_GT(base::ComputeDirectorySize(GetCacheIndexDirectory()), directory_size); } + +class NetworkConnectionObserver + : public network::NetworkConnectionTracker::NetworkConnectionObserver { + public: + NetworkConnectionObserver() { + content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this); + content::GetNetworkConnectionTracker()->GetConnectionType( + &last_connection_type_, + base::BindOnce(&NetworkConnectionObserver::OnConnectionChanged, + base::Unretained(this))); + } + + ~NetworkConnectionObserver() override { + content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver( + this); + } + + void WaitForConnectionType(network::mojom::ConnectionType type) { + type_to_wait_for_ = type; + if (last_connection_type_ == type_to_wait_for_) + return; + + run_loop_ = std::make_unique<base::RunLoop>(); + run_loop_->Run(); + } + + // network::NetworkConnectionTracker::NetworkConnectionObserver: + void OnConnectionChanged(network::mojom::ConnectionType type) override { + last_connection_type_ = type; + if (run_loop_ && type_to_wait_for_ == type) + run_loop_->Quit(); + } + + private: + network::mojom::ConnectionType type_to_wait_for_ = + network::mojom::ConnectionType::CONNECTION_UNKNOWN; + network::mojom::ConnectionType last_connection_type_ = + network::mojom::ConnectionType::CONNECTION_UNKNOWN; + std::unique_ptr<base::RunLoop> run_loop_; +}; + +IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest, + ConnectionTypeChangeSyncedToNetworkProcess) { + NetworkConnectionObserver observer; + net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests( + net::NetworkChangeNotifier::CONNECTION_WIFI); + observer.WaitForConnectionType( + network::mojom::ConnectionType::CONNECTION_WIFI); + + net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests( + net::NetworkChangeNotifier::CONNECTION_ETHERNET); + observer.WaitForConnectionType( + network::mojom::ConnectionType::CONNECTION_ETHERNET); +} #endif IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest, @@ -363,6 +418,39 @@ IN_PROC_BROWSER_TEST_F(NetworkServiceInProcessBrowserTest, Basic) { LoadBasicRequest(partition->GetNetworkContext(), test_url)); } +class NetworkServiceInvalidLogBrowserTest : public ContentBrowserTest { + public: + NetworkServiceInvalidLogBrowserTest() { + scoped_feature_list_.InitAndEnableFeature( + network::features::kNetworkService); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII(network::switches::kLogNetLog, "/abc/def"); + } + + void SetUpOnMainThread() override { + host_resolver()->AddRule("*", "127.0.0.1"); + EXPECT_TRUE(embedded_test_server()->Start()); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; + + DISALLOW_COPY_AND_ASSIGN(NetworkServiceInvalidLogBrowserTest); +}; + +// Verifies that an invalid --log-net-log flag won't crash the browser. +IN_PROC_BROWSER_TEST_F(NetworkServiceInvalidLogBrowserTest, Basic) { + GURL test_url = embedded_test_server()->GetURL("foo.com", "/echo"); + StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( + BrowserContext::GetDefaultStoragePartition( + shell()->web_contents()->GetBrowserContext())); + NavigateToURL(shell(), test_url); + ASSERT_EQ(net::OK, + LoadBasicRequest(partition->GetNetworkContext(), test_url)); +} + } // namespace } // namespace content diff --git a/chromium/content/browser/network_service_client.cc b/chromium/content/browser/network_service_client.cc index 6fd435a3b14..207ebdd1551 100644 --- a/chromium/content/browser/network_service_client.cc +++ b/chromium/content/browser/network_service_client.cc @@ -442,12 +442,29 @@ NetworkServiceClient::NetworkServiceClient( memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(base::BindRepeating( &NetworkServiceClient::OnMemoryPressure, base::Unretained(this))); + +#if defined(OS_ANDROID) + DCHECK(net::NetworkChangeNotifier::HasNetworkChangeNotifier()); + GetNetworkService()->GetNetworkChangeManager( + mojo::MakeRequest(&network_change_manager_)); + net::NetworkChangeNotifier::AddConnectionTypeObserver(this); + net::NetworkChangeNotifier::AddMaxBandwidthObserver(this); + net::NetworkChangeNotifier::AddIPAddressObserver(this); + net::NetworkChangeNotifier::AddDNSObserver(this); +#endif } } NetworkServiceClient::~NetworkServiceClient() { - if (IsOutOfProcessNetworkService()) + if (IsOutOfProcessNetworkService()) { net::CertDatabase::GetInstance()->RemoveObserver(this); +#if defined(OS_ANDROID) + net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); + net::NetworkChangeNotifier::RemoveMaxBandwidthObserver(this); + net::NetworkChangeNotifier::RemoveIPAddressObserver(this); + net::NetworkChangeNotifier::RemoveDNSObserver(this); +#endif + } } void NetworkServiceClient::OnAuthRequired( @@ -618,6 +635,62 @@ void NetworkServiceClient::OnApplicationStateChange( base::android::ApplicationState state) { GetNetworkService()->OnApplicationStateChange(state); } + +void NetworkServiceClient::OnConnectionTypeChanged( + net::NetworkChangeNotifier::ConnectionType type) { + network_change_manager_->OnNetworkChanged( + false /* dns_changed */, false /* ip_address_changed */, + true /* connection_type_changed */, network::mojom::ConnectionType(type), + false /* connection_subtype_changed */, + network::mojom::ConnectionSubtype( + net::NetworkChangeNotifier::GetConnectionSubtype())); +} + +void NetworkServiceClient::OnMaxBandwidthChanged( + double max_bandwidth_mbps, + net::NetworkChangeNotifier::ConnectionType type) { + // The connection subtype change will trigger a max bandwidth change in the + // network service notifier. + network_change_manager_->OnNetworkChanged( + false /* dns_changed */, false /* ip_address_changed */, + false /* connection_type_changed */, network::mojom::ConnectionType(type), + true /* connection_subtype_changed */, + network::mojom::ConnectionSubtype( + net::NetworkChangeNotifier::GetConnectionSubtype())); +} + +void NetworkServiceClient::OnIPAddressChanged() { + network_change_manager_->OnNetworkChanged( + false /* dns_changed */, true /* ip_address_changed */, + false /* connection_type_changed */, + network::mojom::ConnectionType( + net::NetworkChangeNotifier::GetConnectionType()), + false /* connection_subtype_changed */, + network::mojom::ConnectionSubtype( + net::NetworkChangeNotifier::GetConnectionSubtype())); +} + +void NetworkServiceClient::OnDNSChanged() { + network_change_manager_->OnNetworkChanged( + true /* dns_changed */, false /* ip_address_changed */, + false /* connection_type_changed */, + network::mojom::ConnectionType( + net::NetworkChangeNotifier::GetConnectionType()), + false /* connection_subtype_changed */, + network::mojom::ConnectionSubtype( + net::NetworkChangeNotifier::GetConnectionSubtype())); +} + +void NetworkServiceClient::OnInitialDNSConfigRead() { + network_change_manager_->OnNetworkChanged( + true /* dns_changed */, false /* ip_address_changed */, + false /* connection_type_changed */, + network::mojom::ConnectionType( + net::NetworkChangeNotifier::GetConnectionType()), + false /* connection_subtype_changed */, + network::mojom::ConnectionSubtype( + net::NetworkChangeNotifier::GetConnectionSubtype())); +} #endif void NetworkServiceClient::OnDataUseUpdate( diff --git a/chromium/content/browser/network_service_client.h b/chromium/content/browser/network_service_client.h index 2962736dd4c..6714aefc46d 100644 --- a/chromium/content/browser/network_service_client.h +++ b/chromium/content/browser/network_service_client.h @@ -22,6 +22,12 @@ namespace content { class CONTENT_EXPORT NetworkServiceClient : public network::mojom::NetworkServiceClient, +#if defined(OS_ANDROID) + public net::NetworkChangeNotifier::ConnectionTypeObserver, + public net::NetworkChangeNotifier::MaxBandwidthObserver, + public net::NetworkChangeNotifier::IPAddressObserver, + public net::NetworkChangeNotifier::DNSObserver, +#endif public net::CertDatabase::Observer { public: explicit NetworkServiceClient(network::mojom::NetworkServiceClientRequest @@ -103,6 +109,22 @@ class CONTENT_EXPORT NetworkServiceClient #if defined(OS_ANDROID) void OnApplicationStateChange(base::android::ApplicationState state); + + // net::NetworkChangeNotifier::ConnectionTypeObserver implementation: + void OnConnectionTypeChanged( + net::NetworkChangeNotifier::ConnectionType type) override; + + // net::NetworkChangeNotifier::MaxBandwidthObserver implementation: + void OnMaxBandwidthChanged( + double max_bandwidth_mbps, + net::NetworkChangeNotifier::ConnectionType type) override; + + // net::NetworkChangeNotifier::IPAddressObserver implementation: + void OnIPAddressChanged() override; + + // net::NetworkChangeNotifier::DNSObserver implementation: + void OnDNSChanged() override; + void OnInitialDNSConfigRead() override; #endif private: @@ -113,6 +135,7 @@ class CONTENT_EXPORT NetworkServiceClient #if defined(OS_ANDROID) std::unique_ptr<base::android::ApplicationStatusListener> app_status_listener_; + network::mojom::NetworkChangeManagerPtr network_change_manager_; #endif DISALLOW_COPY_AND_ASSIGN(NetworkServiceClient); diff --git a/chromium/content/browser/network_service_instance.cc b/chromium/content/browser/network_service_instance.cc index bf703662552..f45d1d89974 100644 --- a/chromium/content/browser/network_service_instance.cc +++ b/chromium/content/browser/network_service_instance.cc @@ -41,6 +41,18 @@ network::mojom::NetworkServicePtr* g_network_service_ptr = nullptr; network::NetworkConnectionTracker* g_network_connection_tracker; network::NetworkService* g_network_service; +network::mojom::NetworkServiceParamsPtr CreateNetworkServiceParams() { + network::mojom::NetworkServiceParamsPtr network_service_params = + network::mojom::NetworkServiceParams::New(); + network_service_params->initial_connection_type = + network::mojom::ConnectionType( + net::NetworkChangeNotifier::GetConnectionType()); + network_service_params->initial_connection_subtype = + network::mojom::ConnectionSubtype( + net::NetworkChangeNotifier::GetConnectionSubtype()); + return network_service_params; +} + void CreateNetworkServiceOnIO(network::mojom::NetworkServiceRequest request) { if (g_network_service) { // GetNetworkServiceImpl() was already called and created the object, so @@ -112,9 +124,14 @@ CONTENT_EXPORT network::mojom::NetworkService* GetNetworkServiceFromConnector( } network::mojom::NetworkServiceClientPtr client_ptr; + auto client_request = mojo::MakeRequest(&client_ptr); + // Call SetClient before creating NetworkServiceClient, as the latter might + // make requests to NetworkService that depend on initialization. + (*g_network_service_ptr) + ->SetClient(std::move(client_ptr), CreateNetworkServiceParams()); + delete g_client; // In case we're recreating the network service. - g_client = new NetworkServiceClient(mojo::MakeRequest(&client_ptr)); - (*g_network_service_ptr)->SetClient(std::move(client_ptr)); + g_client = new NetworkServiceClient(std::move(client_request)); const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); @@ -128,14 +145,15 @@ CONTENT_EXPORT network::mojom::NetworkService* GetNetworkServiceFromConnector( base::File file(log_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - LOG_IF(ERROR, !file.IsValid()) - << "Failed opening: " << log_path.value(); - - // TODO(mmenke): Get capture mode from the command line. - (*g_network_service_ptr) - ->StartNetLog(std::move(file), - network::mojom::NetLogCaptureMode::DEFAULT, - std::move(client_constants)); + if (!file.IsValid()) { + LOG(ERROR) << "Failed opening: " << log_path.value(); + } else { + // TODO(mmenke): Get capture mode from the command line. + (*g_network_service_ptr) + ->StartNetLog(std::move(file), + network::mojom::NetLogCaptureMode::DEFAULT, + std::move(client_constants)); + } } } diff --git a/chromium/content/browser/renderer_host/render_process_host_impl.cc b/chromium/content/browser/renderer_host/render_process_host_impl.cc index 2841e44002e..04f816a43b8 100644 --- a/chromium/content/browser/renderer_host/render_process_host_impl.cc +++ b/chromium/content/browser/renderer_host/render_process_host_impl.cc @@ -1572,6 +1572,7 @@ RenderProcessHostImpl::RenderProcessHostImpl( visible_clients_(0), priority_(!blink::kLaunchingProcessIsBackgrounded, false /* has_media_stream */, + false /* has_foreground_service_worker */, frame_depth_, false /* intersects_viewport */, ShouldBoostPriorityForPendingViews(), @@ -2786,6 +2787,17 @@ void RenderProcessHostImpl::OnMediaStreamRemoved() { UpdateProcessPriority(); } +void RenderProcessHostImpl::OnForegroundServiceWorkerAdded() { + foreground_service_worker_count_ += 1; + UpdateProcessPriority(); +} + +void RenderProcessHostImpl::OnForegroundServiceWorkerRemoved() { + DCHECK_GT(foreground_service_worker_count_, 0); + foreground_service_worker_count_ -= 1; + UpdateProcessPriority(); +} + // static void RenderProcessHostImpl::set_render_process_host_factory_for_testing( const RenderProcessHostFactory* rph_factory) { @@ -4445,7 +4457,8 @@ void RenderProcessHostImpl::UpdateProcessPriority() { const ChildProcessLauncherPriority priority( visible_clients_ > 0 || base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableRendererBackgrounding), - media_stream_count_ > 0, frame_depth_, intersects_viewport_, + media_stream_count_ > 0, foreground_service_worker_count_ > 0, + frame_depth_, intersects_viewport_, !!pending_views_ /* boost_for_pending_views */, #if defined(OS_ANDROID) // Same hack as in RenderProcessHostImpl::RenderProcessHostImpl. @@ -4490,6 +4503,13 @@ void RenderProcessHostImpl::UpdateProcessPriority() { if (!run_renderer_in_process()) { DCHECK(child_process_launcher_.get()); DCHECK(!child_process_launcher_->IsStarting()); + // Make sure to keep the pid in the trace so we can tell which process is + // being modified. + TRACE_EVENT2( + "renderer_host", + "RenderProcessHostImpl::UpdateProcessPriority.SetProcessPriority", + "pid", child_process_launcher_->GetProcess().Pid(), + "priority_is_background", priority.is_background()); child_process_launcher_->SetProcessPriority(priority_); } diff --git a/chromium/content/browser/renderer_host/render_process_host_impl.h b/chromium/content/browser/renderer_host/render_process_host_impl.h index 9cbb089496a..1d6fb2e6592 100644 --- a/chromium/content/browser/renderer_host/render_process_host_impl.h +++ b/chromium/content/browser/renderer_host/render_process_host_impl.h @@ -420,6 +420,9 @@ class CONTENT_EXPORT RenderProcessHostImpl void OnMediaStreamRemoved() override; int get_media_stream_count_for_testing() const { return media_stream_count_; } + void OnForegroundServiceWorkerAdded() override; + void OnForegroundServiceWorkerRemoved() override; + // Sets the global factory used to create new RenderProcessHosts in unit // tests. It may be nullptr, in which case the default RenderProcessHost will // be created (this is the behavior if you don't call this function). The @@ -895,6 +898,11 @@ class CONTENT_EXPORT RenderProcessHostImpl // determine if if a process should be backgrounded. int media_stream_count_ = 0; + // Tracks service workers that may need to respond to events from other + // processes in a timely manner. Used to determine if a process should + // not be backgrounded. + int foreground_service_worker_count_ = 0; + resource_coordinator::ProcessResourceCoordinator process_resource_coordinator_; diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc b/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc index cffe3954f03..d6a5bfc5164 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -721,7 +721,7 @@ void RenderWidgetHostViewAura::WasOccluded() { } bool RenderWidgetHostViewAura::ShouldShowStaleContentOnEviction() { - return host()->ShouldShowStaleContentOnEviction(); + return host() && host()->ShouldShowStaleContentOnEviction(); } gfx::Rect RenderWidgetHostViewAura::GetViewBounds() const { diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.mm b/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.mm index 673c7dacfa3..89939596b25 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.mm +++ b/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.mm @@ -92,9 +92,7 @@ NSString* const kWebContentTouchBarId = @"web-content"; // Whether a keyboard event has been reserved by OSX. BOOL EventIsReservedBySystem(NSEvent* event) { - content::SystemHotkeyHelperMac* helper = - content::SystemHotkeyHelperMac::GetInstance(); - return helper->map()->IsEventReserved(event); + return content::GetSystemHotkeyMap()->IsEventReserved(event); } // TODO(suzhe): Upstream this function. @@ -302,6 +300,8 @@ void ExtractUnderlines(NSAttributedString* string, replacementRange.location += textSelectionOffset_; [self insertText:selectedResult.replacementString replacementRange:replacementRange]; + + ui::LogTouchBarUMA(ui::TouchBarAction::TEXT_SUGGESTION); } - (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem*)anItem diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.cc b/chromium/content/browser/service_worker/embedded_worker_instance.cc index a66848077ec..033853b765d 100644 --- a/chromium/content/browser/service_worker/embedded_worker_instance.cc +++ b/chromium/content/browser/service_worker/embedded_worker_instance.cc @@ -32,6 +32,7 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/common/child_process_host.h" #include "content/public/common/content_client.h" +#include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/common/renderer_preference_watcher.mojom.h" #include "ipc/ipc_message.h" @@ -323,6 +324,21 @@ bool HasSentStartWorker(EmbeddedWorkerInstance::StartingPhase phase) { return false; } +void NotifyForegroundServiceWorkerOnUIThread(bool added, int process_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK( + base::FeatureList::IsEnabled(features::kServiceWorkerForegroundPriority)); + + RenderProcessHost* rph = RenderProcessHost::FromID(process_id); + if (!rph) + return; + + if (added) + rph->OnForegroundServiceWorkerAdded(); + else + rph->OnForegroundServiceWorkerRemoved(); +} + } // namespace // Created on UI thread and moved to IO thread. Proxies notifications to @@ -649,7 +665,7 @@ EmbeddedWorkerInstance::~EmbeddedWorkerInstance() { devtools_proxy_.reset(); if (registry_->GetWorker(embedded_worker_id_)) registry_->RemoveWorker(process_id(), embedded_worker_id_); - process_handle_.reset(); + ReleaseProcess(); } void EmbeddedWorkerInstance::Start(mojom::EmbeddedWorkerStartParamsPtr params, @@ -748,6 +764,7 @@ EmbeddedWorkerInstance::EmbeddedWorkerInstance( instance_host_binding_(this), devtools_attached_(false), network_accessed_for_script_(false), + foreground_notified_(false), weak_factory_(this) { DCHECK_CURRENTLY_ON(BrowserThread::IO); } @@ -759,6 +776,9 @@ void EmbeddedWorkerInstance::OnProcessAllocated( DCHECK(!process_handle_); process_handle_ = std::move(handle); + + UpdateForegroundPriority(); + start_situation_ = start_situation; for (auto& observer : listener_list_) observer.OnProcessAllocated(); @@ -955,6 +975,16 @@ void EmbeddedWorkerInstance::Detach() { observer.OnDetached(old_status); } +void EmbeddedWorkerInstance::UpdateForegroundPriority() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (process_handle_ && + owner_version_->ShouldRequireForegroundPriority(process_id())) { + NotifyForegroundServiceWorkerAdded(); + } else { + NotifyForegroundServiceWorkerRemoved(); + } +} + base::WeakPtr<EmbeddedWorkerInstance> EmbeddedWorkerInstance::AsWeakPtr() { return weak_factory_.GetWeakPtr(); } @@ -1020,6 +1050,8 @@ void EmbeddedWorkerInstance::ReleaseProcess() { // Abort an inflight start task. inflight_start_task_.reset(); + NotifyForegroundServiceWorkerRemoved(); + instance_host_binding_.Close(); devtools_proxy_.reset(); process_handle_.reset(); @@ -1101,4 +1133,37 @@ void EmbeddedWorkerInstance::SetNetworkFactoryForTesting( GetNetworkFactoryCallbackForTest() = create_network_factory_callback; } +void EmbeddedWorkerInstance::NotifyForegroundServiceWorkerAdded() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK( + base::FeatureList::IsEnabled(features::kServiceWorkerForegroundPriority)); + + if (!process_handle_ || foreground_notified_) + return; + + foreground_notified_ = true; + + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&NotifyForegroundServiceWorkerOnUIThread, true /* added */, + process_id())); +} + +void EmbeddedWorkerInstance::NotifyForegroundServiceWorkerRemoved() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK( + !foreground_notified_ || + base::FeatureList::IsEnabled(features::kServiceWorkerForegroundPriority)); + + if (!process_handle_ || !foreground_notified_) + return; + + foreground_notified_ = false; + + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&NotifyForegroundServiceWorkerOnUIThread, + false /* added */, process_id())); +} + } // namespace content diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.h b/chromium/content/browser/service_worker/embedded_worker_instance.h index 63682344b8a..c89de1450b7 100644 --- a/chromium/content/browser/service_worker/embedded_worker_instance.h +++ b/chromium/content/browser/service_worker/embedded_worker_instance.h @@ -217,6 +217,11 @@ class CONTENT_EXPORT EmbeddedWorkerInstance // worker. void Detach(); + // Examine the current state of the worker in order to determine if it should + // require foreground priority or not. This should be called whenever state + // changes such that the decision might change. + void UpdateForegroundPriority(); + base::WeakPtr<EmbeddedWorkerInstance> AsWeakPtr(); private: @@ -294,6 +299,11 @@ class CONTENT_EXPORT EmbeddedWorkerInstance void OnSetupFailed(StatusCallback callback, blink::ServiceWorkerStatusCode status); + // Called when a foreground service worker is added/removed in a process. + // Called on the IO thread and dispatches task to the UI thread. + void NotifyForegroundServiceWorkerAdded(); + void NotifyForegroundServiceWorkerRemoved(); + base::WeakPtr<ServiceWorkerContextCore> context_; scoped_refptr<EmbeddedWorkerRegistry> registry_; ServiceWorkerVersion* owner_version_; @@ -324,6 +334,10 @@ class CONTENT_EXPORT EmbeddedWorkerInstance // served from HTTPCache or ServiceWorkerDatabase this value is false. bool network_accessed_for_script_; + // True if the RenderProcessHost has been notified that this is a service + // worker requiring foreground priority. + bool foreground_notified_; + ListenerList listener_list_; std::unique_ptr<DevToolsProxy> devtools_proxy_; diff --git a/chromium/content/browser/service_worker/service_worker_database.cc b/chromium/content/browser/service_worker/service_worker_database.cc index 79422c740bd..36adfd0a45c 100644 --- a/chromium/content/browser/service_worker/service_worker_database.cc +++ b/chromium/content/browser/service_worker/service_worker_database.cc @@ -1192,8 +1192,12 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetPurgeableResourceIds( ServiceWorkerDatabase::Status ServiceWorkerDatabase::ClearPurgeableResourceIds( const std::set<int64_t>& ids) { + Status status = LazyOpen(false); + if (IsNewOrNonexistentDatabase(status)) + return STATUS_OK; + leveldb::WriteBatch batch; - Status status = DeleteResourceIdsInBatch( + status = DeleteResourceIdsInBatch( service_worker_internals::kPurgeableResIdKeyPrefix, ids, &batch); if (status != STATUS_OK) return status; @@ -1203,8 +1207,12 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ClearPurgeableResourceIds( ServiceWorkerDatabase::Status ServiceWorkerDatabase::PurgeUncommittedResourceIds( const std::set<int64_t>& ids) { + Status status = LazyOpen(false); + if (IsNewOrNonexistentDatabase(status)) + return STATUS_OK; + leveldb::WriteBatch batch; - Status status = DeleteResourceIdsInBatch( + status = DeleteResourceIdsInBatch( service_worker_internals::kUncommittedResIdKeyPrefix, ids, &batch); if (status != STATUS_OK) return status; diff --git a/chromium/content/browser/service_worker/service_worker_new_script_loader.cc b/chromium/content/browser/service_worker/service_worker_new_script_loader.cc index fb7748bc5f7..8d825657621 100644 --- a/chromium/content/browser/service_worker/service_worker_new_script_loader.cc +++ b/chromium/content/browser/service_worker/service_worker_new_script_loader.cc @@ -151,15 +151,18 @@ void ServiceWorkerNewScriptLoader::ProceedWithResponse() { void ServiceWorkerNewScriptLoader::SetPriority(net::RequestPriority priority, int32_t intra_priority_value) { - network_loader_->SetPriority(priority, intra_priority_value); + if (network_loader_) + network_loader_->SetPriority(priority, intra_priority_value); } void ServiceWorkerNewScriptLoader::PauseReadingBodyFromNet() { - network_loader_->PauseReadingBodyFromNet(); + if (network_loader_) + network_loader_->PauseReadingBodyFromNet(); } void ServiceWorkerNewScriptLoader::ResumeReadingBodyFromNet() { - network_loader_->ResumeReadingBodyFromNet(); + if (network_loader_) + network_loader_->ResumeReadingBodyFromNet(); } // URLLoaderClient for network loader ------------------------------------------ diff --git a/chromium/content/browser/service_worker/service_worker_version.cc b/chromium/content/browser/service_worker/service_worker_version.cc index 9f6f4c1d04e..e08d663c03f 100644 --- a/chromium/content/browser/service_worker/service_worker_version.cc +++ b/chromium/content/browser/service_worker/service_worker_version.cc @@ -702,7 +702,11 @@ void ServiceWorkerVersion::AddControllee( const std::string& uuid = provider_host->client_uuid(); CHECK(!provider_host->client_uuid().empty()); DCHECK(!base::ContainsKey(controllee_map_, uuid)); + controllee_map_[uuid] = provider_host; + + embedded_worker_->UpdateForegroundPriority(); + // Keep the worker alive a bit longer right after a new controllee is added. RestartTick(&idle_time_); ClearTick(&no_controllees_time_); @@ -728,6 +732,9 @@ void ServiceWorkerVersion::RemoveControllee(const std::string& client_uuid) { DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(base::ContainsKey(controllee_map_, client_uuid)); controllee_map_.erase(client_uuid); + + embedded_worker_->UpdateForegroundPriority(); + // Notify observers asynchronously since this gets called during // ServiceWorkerProviderHost's destructor, and we don't want observers to do // work during that. @@ -2111,4 +2118,39 @@ std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker::PausedState> ServiceWorkerVersion::TakePausedStateOfChangedScript(const GURL& script_url) { return std::move(compared_script_info_map_[script_url].paused_state); } + +bool ServiceWorkerVersion::ShouldRequireForegroundPriority( + int worker_process_id) const { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!base::FeatureList::IsEnabled(features::kServiceWorkerForegroundPriority)) + return false; + + // Currently FetchEvents are the only type of event we need to really process + // at foreground priority. If the service worker does not have a FetchEvent + // handler then we can always allow it to go to the background. + if (fetch_handler_existence_ != FetchHandlerExistence::EXISTS) + return false; + + // Keep the service worker at foreground priority if its controlling clients + // from a different process. In this situation we are likely to need to + // quickly service FetchEvents when the worker's process does not have any + // visible windows and would have otherwise been moved to the background. + // + // Ideally we would check the visibility of all clients as well, but that + // would also require triggering additional checks on every visibility + // change of all clients. That would add a lot of complexity and its + // unclear we need to pay that cost yet. This may get easier once the + // service worker code runs on the UI thread directly. (crbug.com/824858) + // + // For now the requirement for cross-process clients should filter out most + // service workers. The impact of foreground service workers is further + // limited by the automatic shutdown mechanism. + for (const auto& controllee : controllee_map_) { + const ServiceWorkerProviderHost* host = controllee.second; + if (host->process_id() != worker_process_id) + return true; + } + return false; +} + } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_version.h b/chromium/content/browser/service_worker/service_worker_version.h index 3b8282dbc4c..aebb003ea34 100644 --- a/chromium/content/browser/service_worker/service_worker_version.h +++ b/chromium/content/browser/service_worker/service_worker_version.h @@ -525,6 +525,10 @@ class CONTENT_EXPORT ServiceWorkerVersion std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker::PausedState> TakePausedStateOfChangedScript(const GURL& script_url); + // Called by the EmbeddedWorkerInstance to determine if its worker process + // should be kept at foreground priority. + bool ShouldRequireForegroundPriority(int worker_process_id) const; + private: friend class base::RefCounted<ServiceWorkerVersion>; friend class EmbeddedWorkerInstanceTest; diff --git a/chromium/content/browser/service_worker/service_worker_version_unittest.cc b/chromium/content/browser/service_worker/service_worker_version_unittest.cc index 03b8dd1c932..1a1138c2438 100644 --- a/chromium/content/browser/service_worker/service_worker_version_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_version_unittest.cc @@ -13,6 +13,7 @@ #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/simple_test_tick_clock.h" #include "base/time/time.h" #include "content/browser/service_worker/embedded_worker_registry.h" @@ -24,6 +25,7 @@ #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_test_utils.h" #include "content/common/service_worker/service_worker_utils.h" +#include "content/public/common/content_features.h" #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_service.mojom.h" @@ -167,8 +169,7 @@ class ServiceWorkerVersionTest : public testing::Test { version_->script_cache_map()->SetResources(records); version_->SetMainScriptHttpResponseInfo( EmbeddedWorkerTestHelper::CreateHttpResponseInfo()); - version_->set_fetch_handler_existence( - ServiceWorkerVersion::FetchHandlerExistence::EXISTS); + version_->set_fetch_handler_existence(GetFetchHandlerExistence()); // Make the registration findable via storage functions. base::Optional<blink::ServiceWorkerStatusCode> status; @@ -223,6 +224,29 @@ class ServiceWorkerVersionTest : public testing::Test { version_->SetTickClockForTesting(tick_clock); } + virtual ServiceWorkerVersion::FetchHandlerExistence GetFetchHandlerExistence() + const { + return ServiceWorkerVersion::FetchHandlerExistence::EXISTS; + } + + std::unique_ptr<ServiceWorkerProviderHost> ActivateWithControllee( + int controllee_process_id = 33) { + version_->SetStatus(ServiceWorkerVersion::ACTIVATED); + registration_->SetActiveVersion(version_); + ServiceWorkerRemoteProviderEndpoint remote_endpoint; + std::unique_ptr<ServiceWorkerProviderHost> host = + CreateProviderHostForWindow( + controllee_process_id, 1 /* dummy provider_id */, + true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(), + &remote_endpoint); + host->UpdateUrls(registration_->scope(), registration_->scope()); + host->SetControllerRegistration(registration_, + false /* notify_controllerchange */); + EXPECT_TRUE(version_->HasControllee()); + EXPECT_TRUE(host->controller()); + return host; + } + TestBrowserThreadBundle thread_bundle_; std::unique_ptr<MessageReceiver> helper_; scoped_refptr<ServiceWorkerRegistration> registration_; @@ -1346,6 +1370,135 @@ TEST_F(ServiceWorkerVersionTest, BadOrigin) { EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorDisallowed, status.value()); } +TEST_F(ServiceWorkerVersionTest, + ForegroundServiceWorkerCountUpdatedByControllee) { + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature(features::kServiceWorkerForegroundPriority); + + // Start the worker before we have a controllee. + base::Optional<blink::ServiceWorkerStatusCode> status; + version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, + CreateReceiverOnCurrentThread(&status)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status.value()); + EXPECT_EQ( + 0, + helper_->mock_render_process_host()->foreground_service_worker_count()); + + // Add a controllee in a different process from the service worker. + auto host = ActivateWithControllee(); + + // RenderProcessHost should be notified of foreground worker. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ( + 1, + helper_->mock_render_process_host()->foreground_service_worker_count()); + + // Remove the controllee. + host.reset(); + EXPECT_FALSE(version_->HasControllee()); + + // RenderProcessHost should be notified that there are no foreground workers. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ( + 0, + helper_->mock_render_process_host()->foreground_service_worker_count()); +} + +TEST_F(ServiceWorkerVersionTest, + ForegroundServiceWorkerCountNotUpdatedBySameProcessControllee) { + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature(features::kServiceWorkerForegroundPriority); + + // Start the worker before we have a controllee. + base::Optional<blink::ServiceWorkerStatusCode> status; + version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, + CreateReceiverOnCurrentThread(&status)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status.value()); + EXPECT_EQ( + 0, + helper_->mock_render_process_host()->foreground_service_worker_count()); + + // Add a controllee in the same process as the service worker. + auto host = ActivateWithControllee(version_->embedded_worker()->process_id()); + + // RenderProcessHost should be notified of foreground worker. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ( + 0, + helper_->mock_render_process_host()->foreground_service_worker_count()); +} + +TEST_F(ServiceWorkerVersionTest, + ForegroundServiceWorkerCountUpdatedByWorkerStatus) { + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature(features::kServiceWorkerForegroundPriority); + + // Add a controllee in a different process from the service worker. + auto host = ActivateWithControllee(); + + // RenderProcessHost should not be notified of foreground worker yet since + // there is no worker running. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ( + 0, + helper_->mock_render_process_host()->foreground_service_worker_count()); + + // Starting the worker should notify the RenderProcessHost of the foreground + // worker. + base::Optional<blink::ServiceWorkerStatusCode> status; + version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, + CreateReceiverOnCurrentThread(&status)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status.value()); + EXPECT_EQ( + 1, + helper_->mock_render_process_host()->foreground_service_worker_count()); + + // Stopping the worker should notify the RenderProcessHost that the foreground + // worker has been removed. + version_->StopWorker(base::DoNothing()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ( + 0, + helper_->mock_render_process_host()->foreground_service_worker_count()); +} + +class ServiceWorkerVersionNoFetchHandlerTest : public ServiceWorkerVersionTest { + protected: + ServiceWorkerVersion::FetchHandlerExistence GetFetchHandlerExistence() + const override { + return ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST; + } +}; + +TEST_F(ServiceWorkerVersionNoFetchHandlerTest, + ForegroundServiceWorkerCountNotUpdated) { + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature(features::kServiceWorkerForegroundPriority); + + // Start the worker before we have a controllee. + base::Optional<blink::ServiceWorkerStatusCode> status; + version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, + CreateReceiverOnCurrentThread(&status)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status.value()); + EXPECT_EQ( + 0, + helper_->mock_render_process_host()->foreground_service_worker_count()); + + // Add a controllee in a different process from the service worker. + auto host = ActivateWithControllee(); + + // RenderProcessHost should not be notified if the service worker does not + // have a FetchEvent handler. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ( + 0, + helper_->mock_render_process_host()->foreground_service_worker_count()); +} + TEST_F(ServiceWorkerFailToStartTest, FailingWorkerUsesNewRendererProcess) { base::Optional<blink::ServiceWorkerStatusCode> status; ServiceWorkerContextCore* context = helper_->context(); diff --git a/chromium/content/browser/site_per_process_browsertest.cc b/chromium/content/browser/site_per_process_browsertest.cc index dfd5ce5ea83..58b8cb40a44 100644 --- a/chromium/content/browser/site_per_process_browsertest.cc +++ b/chromium/content/browser/site_per_process_browsertest.cc @@ -655,6 +655,21 @@ class DetachMessageFilter : public BrowserMessageFilter { DISALLOW_COPY_AND_ASSIGN(DetachMessageFilter); }; +// Observes navigation start. +class DidStartNavigationObserver : public WebContentsObserver { + public: + explicit DidStartNavigationObserver(WebContents* web_contents) + : WebContentsObserver(web_contents) {} + void DidStartNavigation(NavigationHandle* navigation_handle) override { + observed_ = true; + } + bool observed() { return observed_; } + + private: + bool observed_ = false; + DISALLOW_COPY_AND_ASSIGN(DidStartNavigationObserver); +}; + } // namespace // @@ -15090,4 +15105,103 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, EXPECT_TRUE(delete_c.deleted()); } +// An history navigation from the renderer process is received while the +// RenderFrameHost is pending deletion. +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + HistoryNavigationWhilePendingDeletion) { + GURL url_ab(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html")); + + EXPECT_TRUE(NavigateToURL(shell(), url_ab)); + RenderFrameHostImpl* rfh_a = web_contents()->GetMainFrame(); + RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host(); + NavigateFrameToURL(rfh_b->frame_tree_node(), url_c); + RenderFrameHostImpl* rfh_c = rfh_a->child_at(0)->current_frame_host(); + + // Frame C has a unload handler. The browser process needs to wait before + // deleting it. + EXPECT_TRUE(ExecJs(rfh_c, "onunload=function(){}")); + + RenderFrameDeletedObserver deleted_observer(rfh_c); + TestNavigationManager navigation_observer(web_contents(), url_ab); + + // History navigation on C. + ExecuteScriptAsync(rfh_c, "history.back();"); + + // Simulate A deleting C. + // It starts before receiving the history navigation. The detach ACK is + // received after. + rfh_c->DetachFromProxy(); + deleted_observer.WaitUntilDeleted(); + + // The NavigationController won't be able to find the subframe to navigate + // since it was just detached, so it should fall back to navigating the main + // frame + navigation_observer.WaitForNavigationFinished(); + EXPECT_TRUE(navigation_observer.was_successful()); +} + +// A same document commit from the renderer process is received while the +// RenderFrameHost is pending deletion. +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + SameDocumentCommitWhilePendingDeletion) { + GURL url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(shell(), url)); + RenderFrameHostImpl* rfh_a = web_contents()->GetMainFrame(); + RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host(); + + // Frame B has a unload handler. The browser process needs to wait before + // deleting it. + EXPECT_TRUE(ExecJs(rfh_b, "onunload=function(){}")); + + RenderFrameDeletedObserver deleted_observer(rfh_b); + DidStartNavigationObserver did_start_navigation_observer(web_contents()); + + // Start a same-document navigation on B. + ExecuteScriptAsync(rfh_b, "location.href='#fragment'"); + + // Simulate A deleting B. + // It starts before receiving the same-document navigation. The detach ACK is + // received after. + rfh_b->DetachFromProxy(); + deleted_observer.WaitUntilDeleted(); + + // The navigation was ignored. + EXPECT_FALSE(did_start_navigation_observer.observed()); +} + +// One frame navigates using window.open while it is pending deletion. The two +// frames lives in different processes. +// See https://crbug.com/932087. +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + OpenUrlToRemoteFramePendingDeletion) { + GURL url_ab(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html")); + + EXPECT_TRUE(NavigateToURL(shell(), url_ab)); + RenderFrameHostImpl* rfh_a = web_contents()->GetMainFrame(); + RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host(); + + // Frame B has a unload handler. The browser process needs to wait before + // deleting it. + EXPECT_TRUE(ExecJs(rfh_b, "onunload=function(){}")); + RenderFrameDeletedObserver deleted_observer(rfh_b); + + // window.open from A in B to url_c. + DidStartNavigationObserver did_start_navigation_observer(web_contents()); + EXPECT_TRUE(ExecuteScript(rfh_b, "window.name = 'name';")); + ExecuteScriptAsync(rfh_a, JsReplace("window.open($1, 'name');", url_c)); + + // Simulate A deleting C. + // It starts before receiving the navigation. The detach ACK is + // received after. + rfh_b->DetachFromProxy(); + deleted_observer.WaitUntilDeleted(); + + EXPECT_FALSE(did_start_navigation_observer.observed()); +} + } // namespace content diff --git a/chromium/content/browser/web_contents/web_contents_impl.cc b/chromium/content/browser/web_contents/web_contents_impl.cc index bdc3ae99f2b..b0f41edaff5 100644 --- a/chromium/content/browser/web_contents/web_contents_impl.cc +++ b/chromium/content/browser/web_contents/web_contents_impl.cc @@ -2663,6 +2663,7 @@ void WebContentsImpl::CreateNewWindow( int32_t main_frame_route_id, int32_t main_frame_widget_route_id, const mojom::CreateNewWindowParams& params, + bool has_user_gesture, SessionStorageNamespace* session_storage_namespace) { // We should have zero valid routing ids, or three valid routing IDs. DCHECK_EQ((render_view_route_id == MSG_ROUTING_NONE), @@ -2824,7 +2825,7 @@ void WebContentsImpl::CreateNewWindow( gfx::Rect initial_rect; // Report an empty initial rect. delegate_->AddNewContents(this, std::move(owning_contents_impl), params.disposition, initial_rect, - params.mimic_user_gesture, &was_blocked); + has_user_gesture, &was_blocked); // The delegate may delete |new_contents_impl| during AddNewContents(). if (!weak_new_contents) return; @@ -2838,7 +2839,7 @@ void WebContentsImpl::CreateNewWindow( load_params->referrer = params.referrer.To<Referrer>(); load_params->transition_type = ui::PAGE_TRANSITION_LINK; load_params->is_renderer_initiated = true; - load_params->has_user_gesture = params.mimic_user_gesture; + load_params->has_user_gesture = has_user_gesture; if (delegate_ && !is_guest && !delegate_->ShouldResumeRequestsForCreatedWindow()) { diff --git a/chromium/content/browser/web_contents/web_contents_impl.h b/chromium/content/browser/web_contents/web_contents_impl.h index 5db7007f550..798e9d4d300 100644 --- a/chromium/content/browser/web_contents/web_contents_impl.h +++ b/chromium/content/browser/web_contents/web_contents_impl.h @@ -568,6 +568,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, int32_t main_frame_route_id, int32_t main_frame_widget_route_id, const mojom::CreateNewWindowParams& params, + bool has_user_gesture, SessionStorageNamespace* session_storage_namespace) override; void ShowCreatedWindow(int process_id, int main_frame_widget_route_id, diff --git a/chromium/content/browser/web_contents/web_contents_view_mac.mm b/chromium/content/browser/web_contents/web_contents_view_mac.mm index 7f4308b56a1..2ff03cf86f7 100644 --- a/chromium/content/browser/web_contents/web_contents_view_mac.mm +++ b/chromium/content/browser/web_contents/web_contents_view_mac.mm @@ -561,7 +561,12 @@ void WebContentsViewMac::ViewsHostableAttach(ViewsHostableView::Host* host) { } else if (factory_host_id != NSViewBridgeFactoryHost::kLocalDirectHostId) { LOG(ERROR) << "Failed to look up NSViewBridgeFactoryHost!"; } - ns_view_bridge_local_->SetParentNSView(views_host_->GetNSViewId(), token); + + // TODO(https://crbug.com/933679): WebContentsNSViewBridge::SetParentView + // will look up the parent NSView by its id, but this has been observed to + // fail in the field, so assume that the caller handles updating the NSView + // hierarchy. + // ns_view_bridge_local_->SetParentNSView(views_host_->GetNSViewId(), token); for (auto* rwhv_mac : GetChildViews()) { rwhv_mac->MigrateNSViewBridge(factory_host, ns_view_id_); diff --git a/chromium/content/browser/web_package/signed_exchange_request_handler_browsertest.cc b/chromium/content/browser/web_package/signed_exchange_request_handler_browsertest.cc index d996c81a4a8..55b5371aaae 100644 --- a/chromium/content/browser/web_package/signed_exchange_request_handler_browsertest.cc +++ b/chromium/content/browser/web_package/signed_exchange_request_handler_browsertest.cc @@ -510,6 +510,27 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerDownloadBrowserTest, observer->observed_content_disposition()); } +IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerDownloadBrowserTest, + DataURLDownload) { + const GURL sxg_url = GURL("data:application/signed-exchange,"); + std::unique_ptr<DownloadObserver> observer = + std::make_unique<DownloadObserver>(BrowserContext::GetDownloadManager( + shell()->web_contents()->GetBrowserContext())); + + embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data"); + ASSERT_TRUE(embedded_test_server()->Start()); + NavigateToURL(shell(), embedded_test_server()->GetURL("/empty.html")); + + const std::string load_sxg = base::StringPrintf( + "const iframe = document.createElement('iframe');" + "iframe.src = '%s';" + "document.body.appendChild(iframe);", + sxg_url.spec().c_str()); + EXPECT_TRUE(ExecuteScript(shell()->web_contents(), load_sxg)); + observer->WaitUntilDownloadCreated(); + EXPECT_EQ(sxg_url, observer->observed_url()); +} + class SignedExchangeRequestHandlerRealCertVerifierBrowserTest : public SignedExchangeRequestHandlerBrowserTestBase { public: diff --git a/chromium/content/browser/web_package/signed_exchange_utils.cc b/chromium/content/browser/web_package/signed_exchange_utils.cc index 07653504db9..7b812b301e2 100644 --- a/chromium/content/browser/web_package/signed_exchange_utils.cc +++ b/chromium/content/browser/web_package/signed_exchange_utils.cc @@ -103,6 +103,10 @@ bool ShouldHandleAsSignedHTTPExchange( return false; if (!SignedExchangeRequestHandler::IsSupportedMimeType(head.mime_type)) return false; + // Do not handle responses without HttpResponseHeaders. + // (Example: data:application/signed-exchange,) + if (!head.headers.get()) + return false; if (download_utils::MustDownload(request_url, head.headers.get(), head.mime_type)) { return false; diff --git a/chromium/content/browser/webauth/authenticator_impl.cc b/chromium/content/browser/webauth/authenticator_impl.cc index 4241adbfae9..da770a5e7c2 100644 --- a/chromium/content/browser/webauth/authenticator_impl.cc +++ b/chromium/content/browser/webauth/authenticator_impl.cc @@ -580,10 +580,21 @@ void AuthenticatorImpl::MakeCredential( blink::mojom::PublicKeyCredentialCreationOptionsPtr options, MakeCredentialCallback callback) { if (request_) { - std::move(callback).Run(blink::mojom::AuthenticatorStatus::PENDING_REQUEST, - nullptr); - return; + if (OriginIsCryptoTokenExtension( + render_frame_host_->GetLastCommittedOrigin())) { + // Requests originating from cryptotoken will generally outlive any + // navigation events on the tab of the request's sender. Evict pending + // requests if cryptotoken sends a new one such that requests from before + // a navigation event do not prevent new requests. See + // https://crbug.com/935480. + Cancel(); + } else { + std::move(callback).Run( + blink::mojom::AuthenticatorStatus::PENDING_REQUEST, nullptr); + return; + } } + DCHECK(!request_); UpdateRequestDelegate(); if (!request_delegate_) { @@ -709,10 +720,21 @@ void AuthenticatorImpl::GetAssertion( blink::mojom::PublicKeyCredentialRequestOptionsPtr options, GetAssertionCallback callback) { if (request_) { - std::move(callback).Run(blink::mojom::AuthenticatorStatus::PENDING_REQUEST, - nullptr); - return; + if (OriginIsCryptoTokenExtension( + render_frame_host_->GetLastCommittedOrigin())) { + // Requests originating from cryptotoken will generally outlive any + // navigation events on the tab of the request's sender. Evict pending + // requests if cryptotoken sends a new one such that requests from before + // a navigation event do not prevent new requests. See + // https://crbug.com/935480. + Cancel(); + } else { + std::move(callback).Run( + blink::mojom::AuthenticatorStatus::PENDING_REQUEST, nullptr); + return; + } } + DCHECK(!request_); UpdateRequestDelegate(); if (!request_delegate_) { diff --git a/chromium/content/browser/websockets/websocket_manager.cc b/chromium/content/browser/websockets/websocket_manager.cc index a825a6d71bd..eebf0d65934 100644 --- a/chromium/content/browser/websockets/websocket_manager.cc +++ b/chromium/content/browser/websockets/websocket_manager.cc @@ -82,8 +82,10 @@ class WebSocketManager::Delegate final : public network::WebSocket::Delegate { } bool CanReadRawCookies(const GURL& url) override { - return ChildProcessSecurityPolicyImpl::GetInstance()->CanReadRawCookies( - manager_->process_id_); + ChildProcessSecurityPolicyImpl* impl = + ChildProcessSecurityPolicyImpl::GetInstance(); + return impl->CanReadRawCookies(manager_->process_id_) && + impl->CanAccessDataForWebSocket(manager_->process_id_, url); } void OnCreateURLRequest(int child_id, diff --git a/chromium/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc b/chromium/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc index 11de6b9e8ee..0aa429dda77 100644 --- a/chromium/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc +++ b/chromium/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc @@ -105,11 +105,6 @@ HRESULT DWriteFontCollectionProxy::FindFamilyName(const WCHAR* family_name, if (!GetFontProxy().FindFamily(name, &family_index)) { LogFontProxyError(FIND_FAMILY_SEND_FAILED); - // TODO(https://crbug.com/922403): We're inserting an assertion here to - // gather crash reports and find more about clients in which this - // fails. Investigate crash reports resulting from this failure, then - // remove this assertion. - CHECK(false); return E_FAIL; } diff --git a/chromium/content/common/throttling_url_loader.cc b/chromium/content/common/throttling_url_loader.cc index bf88ecaf7eb..6303159af21 100644 --- a/chromium/content/common/throttling_url_loader.cc +++ b/chromium/content/common/throttling_url_loader.cc @@ -613,6 +613,31 @@ void ThrottlingURLLoader::OnComplete( DCHECK_EQ(DEFERRED_NONE, deferred_stage_); DCHECK(!loader_completed_); + // Only dispatch WillOnCompleteWithError() if status is not OK. + if (!throttles_.empty() && status.error_code != net::OK) { + pending_restart_flags_ = 0; + has_pending_restart_ = false; + bool deferred = false; + for (auto& entry : throttles_) { + auto* throttle = entry.throttle.get(); + bool throttle_deferred = false; + throttle->WillOnCompleteWithError(status, &throttle_deferred); + if (!HandleThrottleResult(throttle, throttle_deferred, &deferred)) + return; + } + + if (deferred) { + deferred_stage_ = DEFERRED_COMPLETE; + client_binding_.PauseIncomingMethodCallProcessing(); + return; + } + + if (has_pending_restart_) { + RestartWithFlagsNow(); + return; + } + } + // This is the last expected message. Pipe closure before this is an error // (see OnClientConnectionError). After this it is expected and should be // ignored. The owner of |this| is expected to destroy |this| when @@ -679,6 +704,17 @@ void ThrottlingURLLoader::Resume() { // Note: |this| may be deleted here. break; } + case DEFERRED_COMPLETE: { + // TODO(eroman): For simplicity we require throttles that defer during + // WillOnCompleteWithError() to do a restart. We could support deferring + // and choosing not to restart if needed, however the current consumers + // don't need that. + CHECK(has_pending_restart_); + + RestartWithFlagsNow(); + // Note: |this| may be deleted here. + break; + } default: NOTREACHED(); break; diff --git a/chromium/content/common/throttling_url_loader.h b/chromium/content/common/throttling_url_loader.h index 6255f8fff66..11c806f5011 100644 --- a/chromium/content/common/throttling_url_loader.h +++ b/chromium/content/common/throttling_url_loader.h @@ -151,7 +151,8 @@ class CONTENT_EXPORT ThrottlingURLLoader DEFERRED_START, DEFERRED_REDIRECT, DEFERRED_BEFORE_RESPONSE, - DEFERRED_RESPONSE + DEFERRED_RESPONSE, + DEFERRED_COMPLETE }; DeferredStage deferred_stage_ = DEFERRED_NONE; bool loader_completed_ = false; diff --git a/chromium/content/public/browser/file_url_loader.h b/chromium/content/public/browser/file_url_loader.h index 433dc0d26d1..cbf8a725f95 100644 --- a/chromium/content/public/browser/file_url_loader.h +++ b/chromium/content/public/browser/file_url_loader.h @@ -53,6 +53,7 @@ CONTENT_EXPORT void CreateFileURLLoader( network::mojom::URLLoaderRequest loader, network::mojom::URLLoaderClientPtr client, std::unique_ptr<FileURLLoaderObserver> observer, + bool allow_directory_listing, scoped_refptr<net::HttpResponseHeaders> extra_response_headers = nullptr); // Helper to create a FileURLLoaderFactory instance. This exposes the ability diff --git a/chromium/content/public/browser/render_process_host.h b/chromium/content/public/browser/render_process_host.h index 0077970df82..771fadd4135 100644 --- a/chromium/content/public/browser/render_process_host.h +++ b/chromium/content/public/browser/render_process_host.h @@ -166,6 +166,12 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender, virtual void OnMediaStreamAdded() = 0; virtual void OnMediaStreamRemoved() = 0; + // Called when a service worker is executing in the process and may need + // to respond to events from other processes in a timely manner. This is + // used to determine if the process should be backgrounded or not. + virtual void OnForegroundServiceWorkerAdded() = 0; + virtual void OnForegroundServiceWorkerRemoved() = 0; + // Indicates whether the current RenderProcessHost is exclusively hosting // guest RenderFrames. Not all guest RenderFrames are created equal. A guest, // as indicated by BrowserPluginGuest::IsGuest, may coexist with other diff --git a/chromium/content/public/common/content_features.cc b/chromium/content/public/common/content_features.cc index 2b74bf36931..163f4055afb 100644 --- a/chromium/content/public/common/content_features.cc +++ b/chromium/content/public/common/content_features.cc @@ -387,6 +387,11 @@ const base::Feature kSendBeaconThrowForBlobWithNonSimpleType{ const base::Feature kSecMetadata{"SecMetadata", base::FEATURE_DISABLED_BY_DEFAULT}; +// Keep processes with service workers controlling clients from other +// processes at foreground priority. (crbug.com/928904) +const base::Feature kServiceWorkerForegroundPriority{ + "ServiceWorkerForegroundPriority", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables long running message dispatch for service workers. // This is a temporary addition only to be used for the Android Messages // integration with ChromeOS (http://crbug.com/823256). diff --git a/chromium/content/public/common/content_features.h b/chromium/content/public/common/content_features.h index 81e3f56e0aa..f20c4771478 100644 --- a/chromium/content/public/common/content_features.h +++ b/chromium/content/public/common/content_features.h @@ -93,6 +93,7 @@ CONTENT_EXPORT extern const base::Feature kScrollAnchorSerialization; CONTENT_EXPORT extern const base::Feature kSendBeaconThrowForBlobWithNonSimpleType; CONTENT_EXPORT extern const base::Feature kSecMetadata; +CONTENT_EXPORT extern const base::Feature kServiceWorkerForegroundPriority; CONTENT_EXPORT extern const base::Feature kServiceWorkerLongRunningMessage; CONTENT_EXPORT extern const base::Feature kServiceWorkerPaymentApps; CONTENT_EXPORT extern const base::Feature kSharedArrayBuffer; diff --git a/chromium/content/public/common/url_loader_throttle.cc b/chromium/content/public/common/url_loader_throttle.cc index 39390acbdc4..1d172cb0fc7 100644 --- a/chromium/content/public/common/url_loader_throttle.cc +++ b/chromium/content/public/common/url_loader_throttle.cc @@ -54,6 +54,10 @@ void URLLoaderThrottle::BeforeWillProcessResponse( const network::ResourceResponseHead& response_head, bool* defer) {} +void URLLoaderThrottle::WillOnCompleteWithError( + const network::URLLoaderCompletionStatus& status, + bool* defer) {} + URLLoaderThrottle::URLLoaderThrottle() {} } // namespace content diff --git a/chromium/content/public/common/url_loader_throttle.h b/chromium/content/public/common/url_loader_throttle.h index e58acd2fe6d..7a0c347130d 100644 --- a/chromium/content/public/common/url_loader_throttle.h +++ b/chromium/content/public/common/url_loader_throttle.h @@ -156,6 +156,11 @@ class CONTENT_EXPORT URLLoaderThrottle { const network::ResourceResponseHead& response_head, bool* defer); + // Called if there is a non-OK net::Error in the completion status. + virtual void WillOnCompleteWithError( + const network::URLLoaderCompletionStatus& status, + bool* defer); + void set_delegate(Delegate* delegate) { delegate_ = delegate; } protected: diff --git a/chromium/content/public/renderer/render_frame.h b/chromium/content/public/renderer/render_frame.h index 95179687307..59f140736ee 100644 --- a/chromium/content/public/renderer/render_frame.h +++ b/chromium/content/public/renderer/render_frame.h @@ -8,6 +8,7 @@ #include <stddef.h> #include <memory> +#include <string> #include "base/callback_forward.h" #include "base/single_thread_task_runner.h" @@ -20,6 +21,7 @@ #include "ppapi/buildflags/buildflags.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "services/service_manager/public/cpp/binder_registry.h" +#include "third_party/blink/public/common/loader/url_loader_factory_bundle.h" #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/web/web_navigation_policy.h" @@ -294,6 +296,16 @@ class CONTENT_EXPORT RenderFrame : public IPC::Listener, virtual void SetRenderFrameMediaPlaybackOptions( const RenderFrameMediaPlaybackOptions& opts) = 0; + // Requests that fetches initiated by |initiator_origin| should go through the + // provided |url_loader_factory|. This method should be called before + // executing scripts in a isolated world - such scripts are typically + // associated with a security origin different from the main world (and + // therefore fetches from such scripts set |request_initiator| that is + // incompatible with |request_initiator_site_lock|. + virtual void MarkInitiatorAsRequiringSeparateURLLoaderFactory( + const url::Origin& initiator_origin, + network::mojom::URLLoaderFactoryPtr url_loader_factory) = 0; + protected: ~RenderFrame() override {} diff --git a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc index cef3cef6d04..218514962f4 100644 --- a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc +++ b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc @@ -16,6 +16,7 @@ #include "base/location.h" #include "base/logging.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -50,6 +51,7 @@ #include "content/renderer/render_view_impl.h" #include "crypto/openssl_util.h" #include "jingle/glue/thread_wrapper.h" +#include "media/base/bind_to_current_loop.h" #include "media/base/media_permission.h" #include "media/media_buildflags.h" #include "media/video/gpu_video_accelerator_factories.h" @@ -123,7 +125,8 @@ PeerConnectionDependencyFactory::PeerConnectionDependencyFactory( signaling_thread_(nullptr), worker_thread_(nullptr), chrome_signaling_thread_("Chrome_libJingle_Signaling"), - chrome_worker_thread_("Chrome_libJingle_WorkerThread") { + chrome_worker_thread_("Chrome_libJingle_WorkerThread"), + weak_factory_(this) { TryScheduleStunProbeTrial(); } @@ -200,18 +203,11 @@ void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() { base::WaitableEvent create_network_manager_event( base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); - std::unique_ptr<MdnsResponderAdapter> mdns_responder; -#if BUILDFLAG(ENABLE_MDNS) - if (base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns)) { - mdns_responder = std::make_unique<MdnsResponderAdapter>(); - } -#endif // BUILDFLAG(ENABLE_MDNS) chrome_worker_thread_.task_runner()->PostTask( FROM_HERE, base::BindOnce(&PeerConnectionDependencyFactory:: CreateIpcNetworkManagerOnWorkerThread, - base::Unretained(this), &create_network_manager_event, - std::move(mdns_responder))); + base::Unretained(this), &create_network_manager_event)); start_worker_event.Wait(); create_network_manager_event.Wait(); @@ -446,12 +442,15 @@ PeerConnectionDependencyFactory::CreatePortAllocator( std::unique_ptr<rtc::NetworkManager> network_manager; if (port_config.enable_multiple_routes) { - FilteringNetworkManager* filtering_network_manager = - new FilteringNetworkManager(network_manager_.get(), requesting_origin, - media_permission); - network_manager.reset(filtering_network_manager); + auto callback = media::BindToCurrentLoop(base::BindRepeating( + &PeerConnectionDependencyFactory::OnEnumeratePermissionChanged, + weak_factory_.GetWeakPtr())); + network_manager = std::make_unique<FilteringNetworkManager>( + network_manager_.get(), requesting_origin, media_permission, + std::move(callback)); } else { - network_manager.reset(new EmptyNetworkManager(network_manager_.get())); + network_manager = + std::make_unique<EmptyNetworkManager>(network_manager_.get()); } auto port_allocator = std::make_unique<P2PPortAllocator>( p2p_socket_dispatcher_, std::move(network_manager), socket_factory_.get(), @@ -553,11 +552,10 @@ void PeerConnectionDependencyFactory::StartStunProbeTrialOnWorkerThread( } void PeerConnectionDependencyFactory::CreateIpcNetworkManagerOnWorkerThread( - base::WaitableEvent* event, - std::unique_ptr<MdnsResponderAdapter> mdns_responder) { + base::WaitableEvent* event) { DCHECK(chrome_worker_thread_.task_runner()->BelongsToCurrentThread()); - network_manager_ = std::make_unique<IpcNetworkManager>( - p2p_socket_dispatcher_.get(), std::move(mdns_responder)); + network_manager_ = + std::make_unique<IpcNetworkManager>(p2p_socket_dispatcher_.get()); event->Signal(); } @@ -648,4 +646,24 @@ PeerConnectionDependencyFactory::GetReceiverCapabilities( return nullptr; } +void PeerConnectionDependencyFactory::OnEnumeratePermissionChanged( + rtc::NetworkManager::EnumerationPermission new_state) { +#if BUILDFLAG(ENABLE_MDNS) + std::unique_ptr<MdnsResponderAdapter> mdns_responder; + if (new_state == rtc::NetworkManager::ENUMERATION_BLOCKED && + base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns)) { + // Note that MdnsResponderAdapter is created on the main thread to have + // access to the connector to the service manager. + mdns_responder = std::make_unique<MdnsResponderAdapter>(); + } + // base::Unretained is safe below because |network_manager_| will be destroyed + // only after |chrome_work_thread_| stops, which flushes all tasks. See + // PeerConnectionDependencyFactory::CleanupPeerConnectionFactory. + chrome_worker_thread_.task_runner()->PostTask( + FROM_HERE, base::BindOnce(&IpcNetworkManager::SetMdnsResponder, + base::Unretained(network_manager_.get()), + base::Passed(&mdns_responder))); +#endif // BUILDFLAG(ENABLE_MDNS) +} + } // namespace content diff --git a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h index 137b36ac7b3..5182cabe9fa 100644 --- a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h +++ b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h @@ -9,6 +9,7 @@ #include "base/files/file.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop_current.h" #include "base/sequence_checker.h" #include "base/single_thread_task_runner.h" @@ -42,7 +43,6 @@ namespace content { class IpcNetworkManager; class IpcPacketSocketFactory; -class MdnsResponderAdapter; class P2PPortAllocator; class WebRtcAudioDeviceImpl; @@ -150,12 +150,13 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory void InitializeWorkerThread(rtc::Thread** thread, base::WaitableEvent* event); - void CreateIpcNetworkManagerOnWorkerThread( - base::WaitableEvent* event, - std::unique_ptr<MdnsResponderAdapter> mdns_responder); + void CreateIpcNetworkManagerOnWorkerThread(base::WaitableEvent* event); void DeleteIpcNetworkManager(); void CleanupPeerConnectionFactory(); + void OnEnumeratePermissionChanged( + rtc::NetworkManager::EnumerationPermission new_state); + // network_manager_ must be deleted on the worker thread. The network manager // uses |p2p_socket_dispatcher_|. std::unique_ptr<IpcNetworkManager> network_manager_; @@ -177,6 +178,9 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory SEQUENCE_CHECKER(sequence_checker_); + // The weak pointer MUST only be dereferenced on the main thread. + base::WeakPtrFactory<PeerConnectionDependencyFactory> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(PeerConnectionDependencyFactory); }; diff --git a/chromium/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/chromium/content/renderer/media/webrtc/rtc_peer_connection_handler.cc index 25abe6654fb..28736ac7471 100644 --- a/chromium/content/renderer/media/webrtc/rtc_peer_connection_handler.cc +++ b/chromium/content/renderer/media/webrtc/rtc_peer_connection_handler.cc @@ -844,17 +844,16 @@ class RTCPeerConnectionHandler::Observer handler_->OnRenegotiationNeeded(); } } - - void OnIceConnectionChange( - PeerConnectionInterface::IceConnectionState new_state) override {} void OnStandardizedIceConnectionChange( - + PeerConnectionInterface::IceConnectionState new_state) override {} + void OnIceConnectionChange( PeerConnectionInterface::IceConnectionState new_state) override { if (!main_thread_->BelongsToCurrentThread()) { main_thread_->PostTask( - FROM_HERE, base::BindOnce(&RTCPeerConnectionHandler::Observer:: - OnStandardizedIceConnectionChange, - this, new_state)); + FROM_HERE, + base::BindOnce( + &RTCPeerConnectionHandler::Observer::OnIceConnectionChange, this, + new_state)); } else if (handler_) { handler_->OnIceConnectionChange(new_state); } diff --git a/chromium/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc b/chromium/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc index 62251b627b7..eed9b23c50e 100644 --- a/chromium/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc +++ b/chromium/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc @@ -1047,7 +1047,7 @@ TEST_F(RTCPeerConnectionHandlerTest, OnIceConnectionChange) { EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionNew)); - pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); + pc_handler_->observer()->OnIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionChecking; EXPECT_CALL(*mock_tracker_.get(), @@ -1057,7 +1057,7 @@ TEST_F(RTCPeerConnectionHandlerTest, OnIceConnectionChange) { EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionChecking)); - pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); + pc_handler_->observer()->OnIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionConnected; EXPECT_CALL(*mock_tracker_.get(), @@ -1067,7 +1067,7 @@ TEST_F(RTCPeerConnectionHandlerTest, OnIceConnectionChange) { EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionConnected)); - pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); + pc_handler_->observer()->OnIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionCompleted; EXPECT_CALL(*mock_tracker_.get(), @@ -1077,7 +1077,7 @@ TEST_F(RTCPeerConnectionHandlerTest, OnIceConnectionChange) { EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionCompleted)); - pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); + pc_handler_->observer()->OnIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionFailed; EXPECT_CALL(*mock_tracker_.get(), @@ -1087,7 +1087,7 @@ TEST_F(RTCPeerConnectionHandlerTest, OnIceConnectionChange) { EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionFailed)); - pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); + pc_handler_->observer()->OnIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionDisconnected; EXPECT_CALL(*mock_tracker_.get(), @@ -1097,7 +1097,7 @@ TEST_F(RTCPeerConnectionHandlerTest, OnIceConnectionChange) { EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionDisconnected)); - pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); + pc_handler_->observer()->OnIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionClosed; EXPECT_CALL(*mock_tracker_.get(), @@ -1107,7 +1107,7 @@ TEST_F(RTCPeerConnectionHandlerTest, OnIceConnectionChange) { EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionClosed)); - pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); + pc_handler_->observer()->OnIceConnectionChange(new_state); } TEST_F(RTCPeerConnectionHandlerTest, OnIceGatheringChange) { diff --git a/chromium/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc b/chromium/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc index 1dc4927c824..57f11a0c8f5 100644 --- a/chromium/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc +++ b/chromium/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc @@ -226,7 +226,6 @@ int32_t RTCVideoDecoderAdapter::Decode( DVLOG(2) << __func__; DCHECK_CALLED_ON_VALID_THREAD(decoding_thread_checker_); -#if defined(OS_WIN) // Hardware VP9 decoders don't handle more than one spatial layer. Fall back // to software decoding. See https://crbug.com/webrtc/9304. if (codec_specific_info && @@ -235,7 +234,6 @@ int32_t RTCVideoDecoderAdapter::Decode( codec_specific_info->codecSpecific.VP9.num_spatial_layers > 1) { return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; } -#endif // defined(OS_WIN) if (missing_frames || !input_image._completeFrame) { DVLOG(2) << "Missing or incomplete frames"; diff --git a/chromium/content/renderer/p2p/filtering_network_manager.cc b/chromium/content/renderer/p2p/filtering_network_manager.cc index 66fb08a32c0..d09315da98b 100644 --- a/chromium/content/renderer/p2p/filtering_network_manager.cc +++ b/chromium/content/renderer/p2p/filtering_network_manager.cc @@ -17,18 +17,20 @@ namespace content { FilteringNetworkManager::FilteringNetworkManager( rtc::NetworkManager* network_manager, const GURL& requesting_origin, - media::MediaPermission* media_permission) + media::MediaPermission* media_permission, + OnEnumerationPermissionCallback callback) : network_manager_(network_manager), media_permission_(media_permission), requesting_origin_(requesting_origin), + on_enumeration_permission_cb_(std::move(callback)), weak_ptr_factory_(this) { thread_checker_.DetachFromThread(); - set_enumeration_permission(ENUMERATION_BLOCKED); + SetEnumerationPermissionAndNotify(ENUMERATION_BLOCKED); // If the feature is not enabled, just return ALLOWED as it's requested. if (!media_permission_) { started_permission_check_ = true; - set_enumeration_permission(ENUMERATION_ALLOWED); + SetEnumerationPermissionAndNotify(ENUMERATION_ALLOWED); VLOG(3) << "media_permission is not passed, granting permission"; return; } @@ -123,7 +125,7 @@ void FilteringNetworkManager::OnPermissionStatus(bool granted) { --pending_permission_checks_; if (granted) - set_enumeration_permission(ENUMERATION_ALLOWED); + SetEnumerationPermissionAndNotify(ENUMERATION_ALLOWED); // If the IP permission status changed *and* we have an up-to-date network // list, fire a network change event. @@ -131,6 +133,16 @@ void FilteringNetworkManager::OnPermissionStatus(bool granted) { FireEventIfStarted(); } +void FilteringNetworkManager::SetEnumerationPermissionAndNotify( + EnumerationPermission state) { + EnumerationPermission old_state = enumeration_permission(); + if (state != old_state) { + set_enumeration_permission(state); + if (on_enumeration_permission_cb_) + on_enumeration_permission_cb_.Run(state); + } +} + void FilteringNetworkManager::OnNetworksChanged() { DCHECK(thread_checker_.CalledOnValidThread()); pending_network_update_ = false; diff --git a/chromium/content/renderer/p2p/filtering_network_manager.h b/chromium/content/renderer/p2p/filtering_network_manager.h index 7d3b292ce16..47a9f6a9b54 100644 --- a/chromium/content/renderer/p2p/filtering_network_manager.h +++ b/chromium/content/renderer/p2p/filtering_network_manager.h @@ -5,8 +5,10 @@ #ifndef CONTENT_RENDERER_P2P_FILTERING_NETWORK_MANAGER_H_ #define CONTENT_RENDERER_P2P_FILTERING_NETWORK_MANAGER_H_ +#include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" #include "base/threading/thread_checker.h" #include "base/time/time.h" #include "content/common/content_export.h" @@ -37,12 +39,17 @@ namespace content { class FilteringNetworkManager : public rtc::NetworkManagerBase, public sigslot::has_slots<> { public: + // A callback that will be executed when |enumeration_permission_| changes. + using OnEnumerationPermissionCallback = + base::RepeatingCallback<void(EnumerationPermission)>; + // This class is created by WebRTC's signaling thread but used by WebRTC's // worker thread |task_runner|. CONTENT_EXPORT FilteringNetworkManager( rtc::NetworkManager* network_manager, const GURL& requesting_origin, - media::MediaPermission* media_permission); + media::MediaPermission* media_permission, + OnEnumerationPermissionCallback callback); CONTENT_EXPORT ~FilteringNetworkManager() override; @@ -64,6 +71,8 @@ class FilteringNetworkManager : public rtc::NetworkManagerBase, // available. void OnPermissionStatus(bool granted); + void SetEnumerationPermissionAndNotify(EnumerationPermission state); + base::WeakPtr<FilteringNetworkManager> GetWeakPtr(); // Receive callback from the wrapped NetworkManager when the underneath @@ -117,6 +126,8 @@ class FilteringNetworkManager : public rtc::NetworkManagerBase, GURL requesting_origin_; + OnEnumerationPermissionCallback on_enumeration_permission_cb_; + base::WeakPtrFactory<FilteringNetworkManager> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(FilteringNetworkManager); diff --git a/chromium/content/renderer/p2p/filtering_network_manager_unittest.cc b/chromium/content/renderer/p2p/filtering_network_manager_unittest.cc index 87295ec00de..1a4c4247664 100644 --- a/chromium/content/renderer/p2p/filtering_network_manager_unittest.cc +++ b/chromium/content/renderer/p2p/filtering_network_manager_unittest.cc @@ -9,6 +9,7 @@ #include <memory> #include <utility> +#include "base/bind_helpers.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/stl_util.h" @@ -137,7 +138,8 @@ class FilteringNetworkManagerTest : public testing::Test, if (multiple_routes_requested) { FilteringNetworkManager* filtering_network_manager = new FilteringNetworkManager(mock_network_manager_.get(), GURL(), - media_permission_.get()); + media_permission_.get(), + base::DoNothing()); filtering_network_manager->Initialize(); network_manager_.reset(filtering_network_manager); } else { diff --git a/chromium/content/renderer/p2p/ipc_network_manager.cc b/chromium/content/renderer/p2p/ipc_network_manager.cc index 4e6b5fb4297..987aa861874 100644 --- a/chromium/content/renderer/p2p/ipc_network_manager.cc +++ b/chromium/content/renderer/p2p/ipc_network_manager.cc @@ -7,16 +7,19 @@ #include <string> #include "base/bind.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/location.h" #include "base/metrics/histogram_macros.h" #include "base/single_thread_task_runner.h" #include "base/sys_byteorder.h" #include "base/threading/thread_task_runner_handle.h" +#include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "jingle/glue/utils.h" #include "net/base/ip_address.h" #include "net/base/network_change_notifier.h" #include "net/base/network_interfaces.h" +#include "net/net_buildflags.h" #include "third_party/webrtc/rtc_base/socket_address.h" namespace content { @@ -43,12 +46,8 @@ rtc::AdapterType ConvertConnectionTypeToAdapterType( } // namespace -IpcNetworkManager::IpcNetworkManager( - NetworkListManager* network_list_manager, - std::unique_ptr<MdnsResponderAdapter> mdns_responder) - : network_list_manager_(network_list_manager), - mdns_responder_(std::move(mdns_responder)), - weak_factory_(this) { +IpcNetworkManager::IpcNetworkManager(NetworkListManager* network_list_manager) + : network_list_manager_(network_list_manager), weak_factory_(this) { network_list_manager_->AddNetworkListObserver(this); } @@ -110,6 +109,7 @@ void IpcNetworkManager::OnNetworkListChanged( std::unique_ptr<rtc::Network> network(new rtc::Network( it->name, it->name, prefix, it->prefix_length, adapter_type)); network->set_default_local_address_provider(this); + network->set_mdns_responder_provider(this); rtc::InterfaceAddress iface_addr; if (it->address.IsIPv4()) { @@ -153,6 +153,7 @@ void IpcNetworkManager::OnNetworkListChanged( rtc::Network* network_v4 = new rtc::Network( name_v4, name_v4, ip_address_v4, 32, rtc::ADAPTER_TYPE_UNKNOWN); network_v4->set_default_local_address_provider(this); + network_v4->set_mdns_responder_provider(this); network_v4->AddIP(ip_address_v4); networks.push_back(network_v4); @@ -167,6 +168,7 @@ void IpcNetworkManager::OnNetworkListChanged( rtc::Network* network_v6 = new rtc::Network( name_v6, name_v6, ip_address_v6, 64, rtc::ADAPTER_TYPE_UNKNOWN); network_v6->set_default_local_address_provider(this); + network_v6->set_mdns_responder_provider(this); network_v6->AddIP(ip_address_v6); networks.push_back(network_v6); } @@ -185,6 +187,11 @@ void IpcNetworkManager::OnNetworkListChanged( stats.ipv6_network_count); } +void IpcNetworkManager::SetMdnsResponder( + std::unique_ptr<MdnsResponderAdapter> mdns_responder) { + mdns_responder_ = std::move(mdns_responder); +} + webrtc::MdnsResponderInterface* IpcNetworkManager::GetMdnsResponder() const { return mdns_responder_.get(); } diff --git a/chromium/content/renderer/p2p/ipc_network_manager.h b/chromium/content/renderer/p2p/ipc_network_manager.h index c0395753dcb..3e1657bd458 100644 --- a/chromium/content/renderer/p2p/ipc_network_manager.h +++ b/chromium/content/renderer/p2p/ipc_network_manager.h @@ -29,9 +29,7 @@ class IpcNetworkManager : public rtc::NetworkManagerBase, public NetworkListObserver { public: // Constructor doesn't take ownership of the |network_list_manager|. - CONTENT_EXPORT IpcNetworkManager( - NetworkListManager* network_list_manager, - std::unique_ptr<MdnsResponderAdapter> mdns_responder); + CONTENT_EXPORT IpcNetworkManager(NetworkListManager* network_list_manager); ~IpcNetworkManager() override; // rtc:::NetworkManager: @@ -45,6 +43,8 @@ class IpcNetworkManager : public rtc::NetworkManagerBase, const net::IPAddress& default_ipv4_local_address, const net::IPAddress& default_ipv6_local_address) override; + void SetMdnsResponder(std::unique_ptr<MdnsResponderAdapter> mdns_responder); + private: void SendNetworksChangedSignal(); diff --git a/chromium/content/renderer/p2p/ipc_network_manager_unittest.cc b/chromium/content/renderer/p2p/ipc_network_manager_unittest.cc index 26b96cf06d7..06bb29c9bfe 100644 --- a/chromium/content/renderer/p2p/ipc_network_manager_unittest.cc +++ b/chromium/content/renderer/p2p/ipc_network_manager_unittest.cc @@ -41,8 +41,7 @@ class IpcNetworkManagerTest : public testing::Test { public: IpcNetworkManagerTest() : network_list_manager_(new MockP2PSocketDispatcher()), - network_manager_( - new IpcNetworkManager(network_list_manager_.get(), nullptr)) {} + network_manager_(new IpcNetworkManager(network_list_manager_.get())) {} protected: std::unique_ptr<MockP2PSocketDispatcher> network_list_manager_; diff --git a/chromium/content/renderer/p2p/mdns_responder_adapter.cc b/chromium/content/renderer/p2p/mdns_responder_adapter.cc index 4ba765351d9..4fd88eea7b3 100644 --- a/chromium/content/renderer/p2p/mdns_responder_adapter.cc +++ b/chromium/content/renderer/p2p/mdns_responder_adapter.cc @@ -43,6 +43,8 @@ MdnsResponderAdapter::MdnsResponderAdapter() { auto request = mojo::MakeRequest(&client); thread_safe_client_ = network::mojom::ThreadSafeMdnsResponderPtr::Create(std::move(client)); + DCHECK(ChildThreadImpl::current()); + DCHECK(ChildThreadImpl::current()->GetConnector()); ChildThreadImpl::current()->GetConnector()->BindInterface( mojom::kBrowserServiceName, std::move(request)); } diff --git a/chromium/content/renderer/render_frame_impl.cc b/chromium/content/renderer/render_frame_impl.cc index 5b45214bdb3..73c2e6af3d9 100644 --- a/chromium/content/renderer/render_frame_impl.cc +++ b/chromium/content/renderer/render_frame_impl.cc @@ -3617,6 +3617,17 @@ void RenderFrameImpl::UpdateSubresourceLoaderFactories( ->UpdateThisAndAllClones(std::move(subresource_loaders)); } +void RenderFrameImpl::MarkInitiatorAsRequiringSeparateURLLoaderFactory( + const url::Origin& initiator_origin, + network::mojom::URLLoaderFactoryPtr url_loader_factory) { + DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService)); + + auto factory_bundle = std::make_unique<blink::URLLoaderFactoryBundleInfo>(); + factory_bundle->initiator_specific_factory_infos()[initiator_origin] = + url_loader_factory.PassInterface(); + UpdateSubresourceLoaderFactories(std::move(factory_bundle)); +} + void RenderFrameImpl::BindDevToolsAgent( blink::mojom::DevToolsAgentHostAssociatedPtrInfo host, blink::mojom::DevToolsAgentAssociatedRequest request) { diff --git a/chromium/content/renderer/render_frame_impl.h b/chromium/content/renderer/render_frame_impl.h index c8130291002..bfe6b75355a 100644 --- a/chromium/content/renderer/render_frame_impl.h +++ b/chromium/content/renderer/render_frame_impl.h @@ -586,6 +586,9 @@ class CONTENT_EXPORT RenderFrameImpl void UpdateSubresourceLoaderFactories( std::unique_ptr<blink::URLLoaderFactoryBundleInfo> subresource_loaders) override; + void MarkInitiatorAsRequiringSeparateURLLoaderFactory( + const url::Origin& initiator_origin, + network::mojom::URLLoaderFactoryPtr url_loader_factory) override; void BindDevToolsAgent( blink::mojom::DevToolsAgentHostAssociatedPtrInfo host, blink::mojom::DevToolsAgentAssociatedRequest request) override; diff --git a/chromium/content/renderer/render_thread_impl.cc b/chromium/content/renderer/render_thread_impl.cc index 44df5d5461c..f376c3cbbce 100644 --- a/chromium/content/renderer/render_thread_impl.cc +++ b/chromium/content/renderer/render_thread_impl.cc @@ -1308,6 +1308,11 @@ media::GpuVideoAcceleratorFactories* RenderThreadImpl::GetGpuFactories() { EstablishGpuChannelSync(); if (!gpu_channel_host) return nullptr; + // Currently, VideoResourceUpdater can't convert hardware resources to + // software resources in software compositing mode. So, fall back to software + // video decoding if gpu compositing is off. + if (is_gpu_compositing_disabled_) + return nullptr; // This context is only used to create textures and mailbox them, so // use lower limits than the default. gpu::SharedMemoryLimits limits = gpu::SharedMemoryLimits::ForMailboxContext(); diff --git a/chromium/content/renderer/render_view_impl.cc b/chromium/content/renderer/render_view_impl.cc index 676b344fe80..eb0a039e0fa 100644 --- a/chromium/content/renderer/render_view_impl.cc +++ b/chromium/content/renderer/render_view_impl.cc @@ -1319,6 +1319,10 @@ WebView* RenderViewImpl::CreateView( base::FeatureList::IsEnabled(features::kUserActivationV2) ? false : WebUserGestureIndicator::IsProcessingUserGesture(creator); + // TODO(mustaq): Investigate if mimic_user_gesture can wrongly expose presence + // of user activation w/o any user interaction, e.g. through + // |WebChromeClient#onCreateWindow|. One case to deep-dive: disabling popup + // blocker then calling window.open at onload event. crbug.com/929729 if (GetContentClient()->renderer()->AllowPopup()) params->mimic_user_gesture = true; @@ -1375,8 +1379,10 @@ WebView* RenderViewImpl::CreateView( // The browser allowed creation of a new window and consumed the user // activation (UAv2 only). - WebUserGestureIndicator::ConsumeUserGesture( + bool was_consumed = WebUserGestureIndicator::ConsumeUserGesture( creator, blink::UserActivationUpdateSource::kBrowser); + if (base::FeatureList::IsEnabled(features::kUserActivationV2)) + opened_by_user_gesture = was_consumed; // While this view may be a background extension page, it can spawn a visible // render view. So we just assume that the new one is not another background diff --git a/chromium/content/renderer/render_widget.cc b/chromium/content/renderer/render_widget.cc index a447dbf313a..5223ac9b878 100644 --- a/chromium/content/renderer/render_widget.cc +++ b/chromium/content/renderer/render_widget.cc @@ -2956,6 +2956,14 @@ cc::LayerTreeSettings RenderWidget::GenerateLayerTreeSettings( settings.wait_for_all_pipeline_stages_before_draw = true; settings.enable_latency_recovery = false; } +#if defined(OS_ANDROID) + if (features::IsSurfaceSynchronizationEnabled()) { + // TODO(crbug.com/933846): LatencyRecovery is causing jank on Android. + // Disable in viz mode for now, with plant o disable more widely once + // viz launches. + settings.enable_latency_recovery = false; + } +#endif settings.enable_image_animation_resync = !cmd.HasSwitch(switches::kDisableImageAnimationResync); diff --git a/chromium/content/renderer/service_worker/service_worker_context_client.cc b/chromium/content/renderer/service_worker/service_worker_context_client.cc index 97bea3f3820..dfde993488a 100644 --- a/chromium/content/renderer/service_worker/service_worker_context_client.cc +++ b/chromium/content/renderer/service_worker/service_worker_context_client.cc @@ -1860,8 +1860,11 @@ void ServiceWorkerContextClient::SetTimeoutTimerForTesting( } void ServiceWorkerContextClient::RecordDebugLog(const char* message) { + const size_t kMaxDebugLogSize = 512; base::AutoLock lock(debug_log_lock_); debug_log_.emplace_back(message); + if (debug_log_.size() > kMaxDebugLogSize) + debug_log_.pop_front(); } } // namespace content diff --git a/chromium/content/renderer/service_worker/service_worker_context_client.h b/chromium/content/renderer/service_worker/service_worker_context_client.h index e6816c90106..a885656b8c0 100644 --- a/chromium/content/renderer/service_worker/service_worker_context_client.h +++ b/chromium/content/renderer/service_worker/service_worker_context_client.h @@ -8,10 +8,10 @@ #include <stddef.h> #include <stdint.h> +#include <deque> #include <map> #include <memory> #include <string> -#include <vector> #include "base/callback.h" #include "base/containers/id_map.h" @@ -429,7 +429,7 @@ class CONTENT_EXPORT ServiceWorkerContextClient // TODO(crbug.com/907311): Remove after we identified the cause of crash. bool report_debug_log_ = true; base::Lock debug_log_lock_; - std::vector<std::string> debug_log_ GUARDED_BY(debug_log_lock_); + std::deque<std::string> debug_log_ GUARDED_BY(debug_log_lock_); DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextClient); }; diff --git a/chromium/content/utility/utility_service_factory.cc b/chromium/content/utility/utility_service_factory.cc index 4450cc71177..24a2644f008 100644 --- a/chromium/content/utility/utility_service_factory.cc +++ b/chromium/content/utility/utility_service_factory.cc @@ -178,7 +178,7 @@ void UtilityServiceFactory::RunNetworkServiceOnIOThread( scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner) { auto service = std::make_unique<network::NetworkService>( std::move(network_registry_), nullptr /* request */, - nullptr /* net_log */, std::move(service_request)); + nullptr /* net_log */, std::move(service_request), true); // Transfer ownership of the service to itself, and have it post to the main // thread on self-termination to kill the process. |